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 @@