From b788f890f848980504dab6073a09af60bc298373 Mon Sep 17 00:00:00 2001 From: CieanYau Date: Sat, 7 Nov 2026 08:23:59 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=B4=AD=E7=89=A9=E8=BD=A6?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE=E6=93=8D=E4=BD=9C=E7=9A=84=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E7=BB=91=E5=AE=9A=E4=B8=8E=E5=86=B2=E7=AA=81=E7=A1=AE=E8=AE=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/cart-edit.js | 28 ++- app/pages/cart/index.vue | 27 +-- app/pages/products/[id].vue | 14 +- tests/review-purchase.e2e.test.mjs | 254 +++++++++++++++++++++++-- tests/review-style-layout.e2e.test.mjs | 24 ++- 5 files changed, 288 insertions(+), 59 deletions(-) diff --git a/app/lib/cart-edit.js b/app/lib/cart-edit.js index fc3eba0..bf338a2 100644 --- a/app/lib/cart-edit.js +++ b/app/lib/cart-edit.js @@ -17,8 +17,14 @@ function e(e, t = {}) { function t(e) { return JSON.parse(JSON.stringify(e)); } -function n(n) { - return n.map((n) => t(e(n))); +// 版本只接受服务端对规范购物车生成的 SHA-256,缺失时停止位置写入。 +function requireCartRevision(cart) { + if ( + typeof cart?.revision !== `string` || + !/^[a-f0-9]{64}$/.test(cart.revision) + ) + throw Error(`购物车版本缺失,请返回购物车刷新后重试`); + return cart.revision; } // 递归排序对象键并省略 undefined,使相同内容不受属性插入顺序影响。 function r(e) { @@ -76,11 +82,12 @@ async function l(e) { }); } /** - * n 为 API 客户端,r 包含 position/item;返回函数的第二参 u 检查报价是否仍有效。 - * 保存前重取购物车并比较原始项,提交 expected_item 供后端进一步检测并发变更。 + * n 为 API 客户端,r 包含首次读取时绑定的 position/item/revision;第二参 u 检查报价是否仍有效。 + * 保存始终提交原始版本;冲突必须返回购物车重新确认,不能用新版本授权旧位置。 */ function u(n, r) { let a = r ? t(r.item) : null, + revision = r ? requireCartRevision(r) : null, c = !1; return async (l, u) => { if (!r || !a) throw Error(`购物车编辑上下文缺失`); @@ -88,13 +95,10 @@ function u(n, r) { c = !0; let d = t(e(a, l)); try { - let c = (await n.get(`/cart`)).list?.[r.position]; - if (!c || i(c) !== i(a)) - throw Error(`购物车商品已变化,请返回购物车刷新后重新编辑`); if (!u()) throw Error(`配置已改变,请重新确认报价后保存`); let l = await n.put(`/cart/${r.position}`, { ...d, - expected_item: e(a), + expected_revision: revision, }), f = a; a = t({ @@ -109,9 +113,15 @@ function u(n, r) { (p.fingerprints[r.position] = await s(a)), l ); + } catch (error) { + if ([409, 428].includes(Number(error?.status))) + throw Error(`购物车状态已变化,请返回购物车刷新并重新确认配置`, { + cause: error, + }); + throw error; } finally { c = !1; } }; } -export { l as a, c as i, t as n, a as o, u as r, n as t }; +export { l as a, c as i, t as n, a as o, u as r, requireCartRevision }; diff --git a/app/pages/cart/index.vue b/app/pages/cart/index.vue index 2851c34..2da0254 100644 --- a/app/pages/cart/index.vue +++ b/app/pages/cart/index.vue @@ -1,6 +1,6 @@