From 1ffd73a1afe8f273428cb0c918d61c756f575699 Mon Sep 17 00:00:00 2001 From: yeuimu <2197651308@qq.com> Date: Wed, 2 Sep 2026 15:52:41 +0800 Subject: [PATCH] docs(plan): add price-matrix option sort fix plan --- plans/fix/price-matrix-option-sort-fix.md | 57 +++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 plans/fix/price-matrix-option-sort-fix.md diff --git a/plans/fix/price-matrix-option-sort-fix.md b/plans/fix/price-matrix-option-sort-fix.md new file mode 100644 index 0000000..39298d8 --- /dev/null +++ b/plans/fix/price-matrix-option-sort-fix.md @@ -0,0 +1,57 @@ +# Fix:价格矩阵选项组按词表序输出(印花/工艺/物流按钮顺序稳定) + +日期:2026-09-02 +类型:Bug 修复(fix) +影响面:`apps/api/src/product-families/family-recompute.service.ts` 及其测试、一次性全库重算 + +## 背景与问题 + +详情接口 `family.priceMatrix` 的 `printCounts / crafts / logistics` 是物化进 JSONB 的字符串数组,H5 按数组原序渲染印花/工艺/物流按钮组(无前端排序)。数组顺序 = 重算时 Set 去重的"首次遇到序",且成员查询 `originGoods` 无 `orderBy`,导致: + +1. 每个族的按钮顺序不一致(实测 goodId=1 为 `['双面印花','单面印花']`、`['不包邮','包邮']`,与词表相反); +2. 同一族两次重算顺序理论上可能漂移(Postgres 无顺序保证)。 + +对比:尺码/颜色按钮组有 `variants.sortOrder`,顺序稳定;本修复把印花/工艺/物流对齐到同样可预期。 + +## 目标顺序(业务确认) + +| 维度 | 展示顺序 | +| --- | --- | +| printCount | 单面印花 → 双面印花 | +| craft | 烫画 → 直喷 → 不打印 | +| logistics | 不包邮 → 包邮 | + +无论族内实际出现哪个子集,相对顺序恒定;词表外自由文本(如 CUSTOM 的"海运")沉到最后,相互间保持首次遇到序。 + +## 数据边界(2026-09-02 全库实测) + +- crafts 中出现 `双面印花`×2、logistics 中出现 `海运`×2:来自 3 条 CUSTOM 链接 craftLabel/logisticsLabel 自由文本(含维度填错,属数据清理问题,本修复只保证其沉底,不改数据)。 + +## 方案 + +1. `derivePriceMatrix`:聚合(Set 去重)+ 人工覆盖 append 之后,对三个数组做稳定排序: + - 新增 `OPTION_DISPLAY_ORDER` 常量(printCount/craft/logistics 三组词表序,logistics 与 `DIM_VALUES` 顺序相反是业务要求;`DIM_VALUES` 组合生成语义不动); + - 排序键 = 词表下标,未知值 = `canon.length`(沉底),稳定排序保持未知值间首次遇到序。 +2. `recomputeFamily` 成员查询加 `orderBy: { id: 'asc' }`,使"遇到序"确定(未知值之间顺序也确定)。 +3. 只影响 `autoManaged` 族物化;非自动族人工字段照旧不碰(现有不变量)。 +4. 一次性脚本:逐族调用 `recomputeFamily` 全库刷新存量(166 个族)。 + +## 非目标 + +- 不改 API 输出结构(仍是 `string[]`),前端零改动; +- 不清理 CUSTOM 维度填错数据(另行处理)。 + +## 测试计划(TDD) + +测试文件:`apps/api/src/product-families/family-recompute.service.spec.ts`(`derivePriceMatrix` 为纯函数,可直接单测)。 + +1. **打乱输入仍输出词表序**:成员顺序颠倒,crafts 输出仍 `烫画→直喷→不打印`(修复前为遇到序,RED)。 +2. **子集保序**:只含 `直喷+烫画` → 输出 `烫画,直喷`;只含 `双面` → 单元素。 +3. **未知值沉底**:logistics 含 `海运` → `不包邮,包邮,海运`;未知值相互保持遇到序。 +4. **覆盖 append 值参与同一排序**:override 新增取值后数组仍词表序。 +5. **重算幂等(含顺序)**:同输入跑两遍输出 deep-equal。 +6. 既有用例全绿;全量 jest + tsc 通过。 + +## 风险与回滚 + +- 纯物化顺序变化,无 schema/契约变更;回滚 = revert commit + 再跑一次全库重算(旧逻辑会把顺序"洗回"遇到序,仅顺序变化无数据损坏)。