|
|
@@ -0,0 +1,80 @@
|
|
|
+# 商城按价格排序 — 需求变更说明(2026-11-07)
|
|
|
+
|
|
|
+> **版本:** v1.0(主理人裁定,TDD 编排器入池依据)
|
|
|
+> **来源:** 用户 2026-11-07 需求(1 条)
|
|
|
+> **关联台账:** `docs/superpowers/specs/2026-11-07-shop-price-sort.md`(实现任务书,已入 cfclub `ad71c79d9`)
|
|
|
+> **状态:** 已完成现状核查 → 需求变更锁定 → 已派发(lan-204 `ses_e4bfe8feeffeqY4ckJyZpVoUE9`,dev 中)
|
|
|
+> **范围:** 仅小程序商城商品列表页交互增强;后端零改动
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 一、需求清单(原话)
|
|
|
+
|
|
|
+1. 修改小程序商城页面,**增加按价格排序的功能**。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 二、现状核查(只读,cfclub @ 0bdc78def)
|
|
|
+
|
|
|
+| 项 | 定位 | 关键事实 |
|
|
|
+|----|------|---------|
|
|
|
+| 商城页 | `cfc-frontend/pages/shop/index/index.vue`(704 行) | 布局:搜索栏(L18-27)→ Level1 分类 chips(L29-44)→ Level2 子分类 chips(L46-66)→ 商品列表 `scroll-view.product-list`(L68-148) |
|
|
|
+| 商品加载 | `loadProducts()`(L221-247) | 调 `productList({page, size})`,**未传有效 sort**;默认走后端 `sort_order asc + created_at desc` |
|
|
|
+| 推荐商品 | `loadRecommended()`(L327 附近) | 传 `sort:'sales'`(**字符串**)——后端拦截器要求数组,**该字符串实际被忽略,无效**(现状 bug,本次不触碰推荐区) |
|
|
|
+| 排序机制 | `cfc-backend/.../config/SortInterceptor.java` | `preHandle` 从**请求体**读 `sort`(数组 `[{column, order}]`),白名单过滤(仅 column/order,order 转小写)→ `SortContext.set` |
|
|
|
+| 排序注入 | `cfc-backend/.../util/SortUtil.java` | `applySort(wrapper, SortContext.get(), null)`;列名正则 `^[a-zA-Z_][a-zA-Z0-9_]*$` 防注入;`price` 列符合白名单;驼峰→下划线映射;双 ORDER BY 反射防护 |
|
|
|
+| 默认排序 | `ProductService.list`(L147 附近) | 默认 `orderByAsc(Product::getSortOrder).orderByDesc(createdAt)`,随后 `SortUtil.applySort` 注入用户排序 |
|
|
|
+| 前端透传 | `utils/api.js` L1683 `productList(params)` | `request('/api/product/list','POST',params)` **原样透传 body** → 前端把 `sort` 数组放进 params 即可,**无需改 api.js** |
|
|
|
+
|
|
|
+**结论:** 后端排序能力已完备(`SortInterceptor` + `SortUtil` 支持 body 数组),本次**纯前端**改动,仅加排序 UI 与传参,**后端零改动**。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 三、需求变更定义(目标态)
|
|
|
+
|
|
|
+### 变更 S1 · 商城商品列表增加「综合 / 价格↑ / 价格↓」排序栏
|
|
|
+
|
|
|
+- **UI**:在 Level2 子分类 chips(`</scroll-view>` L66)与商品列表 `scroll-view`(L68)**之间**插入排序栏(`sort-bar`),三项:综合(默认)/ 价格升序 / 价格降序;视觉与分类 chips 协调(复用 `$uni-space-*` 间距、`$facade-violet` 高亮 active)。
|
|
|
+- **状态**:`data` 新增 `sortType: 'default'`。
|
|
|
+- **方法**:
|
|
|
+ - `buildSort()`:`price_asc` → `[{column:'price',order:'asc'}]`;`price_desc` → `[{column:'price',order:'desc'}]`;`default` → `[]`(不传,走后端默认 `sort_order asc + created_at desc`)。
|
|
|
+ - `onSortSelect(type)`:相同 return;否则 `sortType=type; page=1; products=[]; noMore=false; loadProducts()`。
|
|
|
+- **传参**:`loadProducts`(L221-247)与 `onLoadMore`(L254-275)在构建 `params` 后追加 `const sort=this.buildSort(); if(sort.length) params.sort=sort`;`onRefresh` 不改(loadProducts 自动带当前 sortType)。
|
|
|
+- **排序保持**:切分类(`onCat1Select`/`onCat2Select`)不改逻辑——已重置 `page=1;products=[]`,`loadProducts` 自动带当前 sortType,**保留当前排序**(电商惯例);滚动加载沿用当前排序。
|
|
|
+- **推荐区隔离**:`loadRecommended` 的 `sort:'sales'` 字符串**保持原样**,推荐商品区独立于排序栏,不受影响。
|
|
|
+- **验收口径**:
|
|
|
+ 1. 商城商品列表出现「综合 / 价格↑ / 价格↓」排序栏;
|
|
|
+ 2. 点「价格↑」→ 商品按价格从低到高(第 1 页);「价格↓」→ 从高到低;「综合」→ 恢复默认(sort_order asc + created_at desc);
|
|
|
+ 3. 切分类后保留当前排序;滚动加载/下拉刷新沿用当前排序;
|
|
|
+ 4. 推荐商品区不受影响;
|
|
|
+ 5. 构建 `npm run build:mp-weixin` exit 0。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 四、TDD 入池
|
|
|
+
|
|
|
+| 能力键 | 变更 | requirement 溯源 | design 溯源 |
|
|
|
+|--------|------|-----------------|------------|
|
|
|
+| `shop.price.sort` | S1 | 本文档需求 1 + 变更 S1 | `SortInterceptor`(body 数组契约)+ `SortUtil`(price 列白名单)+ `api.js productList`(原样透传) |
|
|
|
+
|
|
|
+> 纯前端交互增强;是否入 SRS 由 TDD 编排器判定(能力键 `shop.price.sort`)。RED 契约以「已合入 origin/cfclub 的 `SortInterceptor` body 数组契约」为准。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 五、风险与注意事项(主理人核实)
|
|
|
+
|
|
|
+1. **排序参数必须是数组** `[{column, order}]`——字符串会被后端 `SortInterceptor` 忽略(这是 `loadRecommended` 现有 `sort:'sales'` 无效的根因),前端实现务必用数组,勿复现该 bug。
|
|
|
+2. **双 ORDER BY 防护**:`SortUtil` 通过反射清空 wrapper 已有 orderBy 段;若某环境反射初始化失败会回退旧行为,排序可能不生效或产生双 ORDER BY——**开发会话须实测三档排序确实生效**,若后端未生效则如实报告,禁止前端硬编码排序。
|
|
|
+3. **`price` 列名**:须与 `product` 表实际列名一致(`SortUtil` 驼峰→下划线映射 `price`→`price`,已确认)。
|
|
|
+4. **仅改 1 文件**:`cfc-frontend/pages/shop/index/index.vue`;不改后端、不改 `utils/api.js`、不改 `pages.json`。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 六、关联记录
|
|
|
+
|
|
|
+- **实现任务书**:`docs/superpowers/specs/2026-11-07-shop-price-sort.md`(已入 cfclub `ad71c79d9`)
|
|
|
+- **派发**:lan-204 会话 `ses_e4bfe8feeffeqY4ckJyZpVoUE9`(`opencode/deepseek-v4.1-flash-free`,dev 中);backlog `DOC-2026-11-07-shop-price-sort`(第 113 条,dispatched)
|
|
|
+- **当日同批未入需求变更台账的其它 3 项**(仅建了 specs 任务书,尚未回填需求变更说明,待补):
|
|
|
+ - 报告上传页关联商品卡片区(`specs/2026-11-06-report-upload-product-cards.md`,已合入 cfclub `0bdc78def`)
|
|
|
+ - 我的优惠券已领取券按钮修复(`specs/2026-11-06-coupon-claimed-actions.md`,已合入 cfclub `1392c7e0b`)
|
|
|
+ - 我的团队推广收益口径对齐 + 邀请成员分享(`specs/2026-11-06-team-invite-share.md`,已合入 cfclub `037aeca7e`)
|