|
|
@@ -0,0 +1,167 @@
|
|
|
+# Story 006.010: 购物车商品名称显示优化
|
|
|
+
|
|
|
+## Status
|
|
|
+Approved
|
|
|
+
|
|
|
+## Story
|
|
|
+**As a** 购物车用户,
|
|
|
+**I want** 父子商品在购物车中分开显示商品名称和规格名称,
|
|
|
+**so that** 我能清晰了解商品全貌,父子商品信息显示完整准确
|
|
|
+
|
|
|
+## Acceptance Criteria
|
|
|
+1. 购物车中父子商品显示时,商品名称显示父商品名称,规格名称显示子商品规格名称
|
|
|
+2. 单规格商品显示保持不变
|
|
|
+3. 订单提交页面、订单详情页等所有相关页面显示一致
|
|
|
+4. 现有功能不受影响,无回归问题
|
|
|
+5. 父子商品信息显示清晰完整,用户能直观了解商品全貌
|
|
|
+
|
|
|
+## Tasks / Subtasks
|
|
|
+- [ ] 任务1:修改购物车页面商品名称显示逻辑 (AC: 1, 2, 5)
|
|
|
+ - [ ] 检查购物车页面当前显示逻辑 (`mini/src/pages/cart/index.tsx:253`)
|
|
|
+ - [ ] 修改 `goodsName` 计算逻辑:判断是否为子商品(通过 `parentGoodsId !== 0` 或 `spuId > 0`)
|
|
|
+ - [ ] 如果是子商品,商品名称使用 `latestGoods?.parent?.name` 获取父商品名称
|
|
|
+ - [ ] 规格名称使用 `latestGoods?.name || '选择规格'` 显示子商品规格名称
|
|
|
+ - [ ] 对于单规格商品(`parentGoodsId === 0`),保持现有显示方式不变
|
|
|
+ - [ ] 移除对 `item.spec` 字段的依赖(子商品的 `name` 字段已包含规格信息)
|
|
|
+ - [ ] 验证购物车总价计算不受影响
|
|
|
+- [ ] 任务2:修改订单提交页面商品名称显示逻辑 (AC: 3)
|
|
|
+ - [ ] 检查订单提交页面当前显示逻辑 (`mini/src/pages/order-submit/index.tsx:277`)
|
|
|
+ - [ ] 应用与购物车页面相同的父子商品名称显示逻辑
|
|
|
+ - [ ] 确保商品名称和规格名称分开显示,保持一致性
|
|
|
+ - [ ] 验证订单创建和提交流程不受影响
|
|
|
+- [ ] 任务3:移除 CartContext 中的 spec 字段 (AC: 4)
|
|
|
+ - [ ] 检查 `CartItem` 接口中的 `spec` 字段 (`mini/src/contexts/CartContext.tsx`)
|
|
|
+ - [ ] 移除 `spec` 字段定义(子商品的 `name` 字段已包含规格信息)
|
|
|
+ - [ ] 更新 `switchSpec` 函数,移除对 `spec` 字段的依赖
|
|
|
+ - [ ] 检查其他可能使用 `spec` 字段的地方并更新
|
|
|
+ - [ ] 验证购物车功能正常工作,包括规格切换功能
|
|
|
+- [ ] 任务4:更新商品详情页面的 spec 字段逻辑 (AC: 4)
|
|
|
+ - [ ] 检查商品详情页面添加购物车时设置 `spec` 字段的逻辑 (`mini/src/pages/goods-detail/index.tsx`)
|
|
|
+ - [ ] 移除设置 `spec` 字段的代码(不再需要,使用子商品 `name` 字段)
|
|
|
+ - [ ] 验证添加购物车功能正常工作
|
|
|
+- [ ] 任务5:编写和更新测试 (AC: 4)
|
|
|
+ - [ ] 为购物车页面商品名称显示逻辑添加单元测试
|
|
|
+ - [ ] 为订单提交页面商品名称显示逻辑添加单元测试
|
|
|
+ - [ ] 更新现有购物车测试,验证移除 `spec` 字段后的兼容性
|
|
|
+ - [ ] 添加集成测试验证父子商品名称显示准确性
|
|
|
+ - [ ] 运行现有测试套件,确保无回归问题
|
|
|
+- [ ] 任务6:验证多租户兼容性和向后兼容性 (AC: 4)
|
|
|
+ - [ ] 验证父子商品在同一租户下的约束
|
|
|
+ - [ ] 确保商品详情API返回的 `parent` 对象包含完整信息
|
|
|
+ - [ ] 验证单规格商品和无父子关系的商品功能不受影响
|
|
|
+ - [ ] 进行端到端测试验证完整流程
|
|
|
+
|
|
|
+## Dev Notes
|
|
|
+
|
|
|
+### 先前故事洞察
|
|
|
+- **故事9(父子商品名称关联查询优化)**:已建立可靠的父子商品名称关联查询机制,商品详情API返回完整的 `parent` 对象,包含父商品基本信息(id、name、price、costPrice、stock、imageFileId、goodsType、spuId)
|
|
|
+- **故事8(购物车页面规格切换功能)**:已扩展 `CartContext`,`CartItem` 接口包含 `parentGoodsId` 字段,购物车页面已集成规格选择器
|
|
|
+- **故事4-7**:商品API已支持父子商品关系,购物车和订单系统已支持子商品规格
|
|
|
+- **关键设计决策**:规格=子商品的名称,规格选择=选择子商品,购物车逻辑简化(使用子商品的 `id`、`name`、`price`、`stock`)
|
|
|
+- **当前实现状态**:`GoodsServiceMt.getById` 方法已返回完整的 `parent` 对象,购物车页面可通过 `latestGoods?.parent?.name` 获取父商品名称
|
|
|
+- [Source: docs/stories/006.009.parent-child-goods-name-relation-query.story.md#Dev-Notes]
|
|
|
+
|
|
|
+### 数据模型
|
|
|
+- **商品实体 (`GoodsMt`)**:
|
|
|
+ - `spuId` 字段:0表示父商品或单规格商品,>0表示子商品
|
|
|
+ - `spuName` 字段:父商品名称(冗余字段,已从API响应中移除,保留在实体中保持向后兼容性)
|
|
|
+ - `tenantId` 字段:租户ID,父子商品必须在同一租户下
|
|
|
+ - `name` 字段:商品名称,对于子商品就是规格名称
|
|
|
+ - [Source: packages/goods-module-mt/src/entities/goods.entity.mt.ts#L76-L81]
|
|
|
+
|
|
|
+- **商品Schema**:
|
|
|
+ - `PublicGoodsSchema`:包含 `parent: ParentGoodsSchema.nullable().optional()` 和 `children: z.array(PublicGoodsSchema).nullable().optional()` 字段,无 `spuName` 字段
|
|
|
+ - `ParentGoodsSchema`:父商品精简Schema,包含 id、name、price、costPrice、stock、imageFileId、goodsType、spuId 字段
|
|
|
+ - [Source: packages/goods-module-mt/src/schemas/parent-goods.schema.mt.ts]
|
|
|
+ - [Source: packages/goods-module-mt/src/schemas/public-goods.schema.mt.ts#L125-L127]
|
|
|
+
|
|
|
+- **购物车数据模型**:
|
|
|
+ - `CartItem` 接口:包含 `parentGoodsId` 字段,`spec` 字段待移除
|
|
|
+ - 购物车项使用子商品的 `id`、`name`、`price`、`stock` 信息
|
|
|
+ - [Source: mini/src/contexts/CartContext.tsx#L4-L13]
|
|
|
+
|
|
|
+### API 规范
|
|
|
+- **商品详情API** (`GET /api/v1/goods/:id`):
|
|
|
+ - 父商品:返回商品详情 + `children` 数组(子商品列表)
|
|
|
+ - 子商品:返回子商品详情 + `parent` 对象(父商品基本信息)
|
|
|
+ - `parent` 对象字段:id、name、price、costPrice、stock、imageFileId、goodsType、spuId
|
|
|
+ - API不再返回 `spuName` 字段,前端使用 `parent.name` 获取父商品名称
|
|
|
+ - [Source: packages/goods-module-mt/src/services/goods.service.mt.ts#L120-L126]
|
|
|
+
|
|
|
+- **购物车数据获取**:
|
|
|
+ - 购物车页面通过 `goodsMap` 存储从商品详情API获取的最新商品信息
|
|
|
+ - 可通过 `latestGoods?.parent?.name` 获取父商品名称
|
|
|
+ - [Source: mini/src/pages/cart/index.tsx#L251-L253]
|
|
|
+
|
|
|
+### 组件规范
|
|
|
+- **购物车页面 (`cart/index.tsx`)**:
|
|
|
+ - 当前商品名称显示:`goodsName = latestGoods?.name || item.name`(第253行)
|
|
|
+ - 购物车项包含 `parentGoodsId` 字段
|
|
|
+ - 需要修改的逻辑:判断是否为子商品,商品名称使用 `parent.name`,规格名称使用子商品 `name`
|
|
|
+ - [Source: mini/src/pages/cart/index.tsx#L253]
|
|
|
+
|
|
|
+- **订单提交页面 (`order-submit/index.tsx`)**:
|
|
|
+ - 当前商品名称显示:`item.name`(第277行)
|
|
|
+ - 需要应用与购物车页面相同的显示逻辑
|
|
|
+ - [Source: mini/src/pages/order-submit/index.tsx#L277]
|
|
|
+
|
|
|
+- **购物车上下文 (`CartContext`)**:
|
|
|
+ - `CartItem` 接口包含 `parentGoodsId` 字段,`spec` 字段待移除
|
|
|
+ - `switchSpec` 函数支持规格切换,需要更新以移除 `spec` 字段依赖
|
|
|
+ - [Source: mini/src/contexts/CartContext.tsx#L4-L13]
|
|
|
+
|
|
|
+- **商品详情页面 (`goods-detail/index.tsx`)**:
|
|
|
+ - 添加购物车时可能设置 `spec` 字段,需要移除相关代码
|
|
|
+ - [Source: mini/src/pages/goods-detail/index.tsx]
|
|
|
+
|
|
|
+### 文件位置
|
|
|
+- **主要修改文件**:
|
|
|
+ - `mini/src/pages/cart/index.tsx` - 修改商品名称显示逻辑(第253行 `goodsName` 计算)
|
|
|
+ - `mini/src/pages/order-submit/index.tsx` - 修改商品名称显示逻辑(第277行 `item.name` 显示)
|
|
|
+ - `mini/src/pages/goods-detail/index.tsx` - 移除添加购物车时设置 `spec` 字段的逻辑
|
|
|
+ - `mini/src/contexts/CartContext.tsx` - 移除 `CartItem` 接口中的 `spec` 字段,更新 `switchSpec` 函数
|
|
|
+ - [Source: docs/prd/epic-006-parent-child-goods-multi-spec-support.md#故事10]
|
|
|
+
|
|
|
+- **测试文件**:
|
|
|
+ - `mini/tests/unit/pages/cart/index.test.tsx` - 更新购物车页面测试
|
|
|
+ - `mini/tests/unit/pages/order-submit/index.test.tsx` - 添加订单提交页面测试(如不存在则创建)
|
|
|
+ - `mini/tests/unit/contexts/CartContext.test.tsx` - 更新购物车上下文测试
|
|
|
+ - [Source: docs/architecture/testing-strategy.md#单元测试-unit-tests]
|
|
|
+
|
|
|
+### 技术约束
|
|
|
+- **多租户要求**:所有操作必须包含 `tenantId` 过滤,父子商品必须在同一租户下
|
|
|
+- **向后兼容性**:现有功能不受影响,数据库实体保留 `spuName` 字段,仅从API响应中移除
|
|
|
+- **性能考虑**:关联查询不应显著影响API响应时间,购物车页面显示逻辑应保持高效
|
|
|
+- **数据一致性**:通过关联查询解决 `spuName` 字段同步问题,确保父子商品名称显示准确
|
|
|
+- [Source: docs/architecture/tech-stack.md]
|
|
|
+- [Source: docs/architecture/source-tree.md]
|
|
|
+
|
|
|
+### 测试标准
|
|
|
+- **测试框架**:mini项目使用Jest,商品模块使用Vitest
|
|
|
+- **测试位置**:`tests` 文件夹与源码并列(例如:`mini/tests/unit/pages/cart/index.test.tsx`)
|
|
|
+- **单元测试位置**:`mini/tests/unit/` 目录下对应页面和组件的测试文件
|
|
|
+- **集成测试位置**:`mini/tests/integration/` 目录(如适用)
|
|
|
+- **测试覆盖率**:核心业务逻辑 > 80%,关键函数 > 90%
|
|
|
+- **测试策略**:验证父子商品名称显示准确性、单规格商品显示不变、现有功能无回归
|
|
|
+- **RPC客户端架构最佳实践**:使用单例模式的客户端管理器,在测试中正确mock客户端管理器的get()方法调用链
|
|
|
+- [Source: docs/architecture/testing-strategy.md#单元测试-unit-tests]
|
|
|
+- [Source: docs/architecture/coding-standards.md#rpc客户端架构最佳实践]
|
|
|
+
|
|
|
+## Change Log
|
|
|
+| Date | Version | Description | Author |
|
|
|
+|------|---------|-------------|--------|
|
|
|
+| 2025-12-14 | 1.0 | 初始故事创建 | Bob (Scrum Master) |
|
|
|
+
|
|
|
+## Dev Agent Record
|
|
|
+*此部分由开发代理在实施过程中填写*
|
|
|
+
|
|
|
+### Agent Model Used
|
|
|
+
|
|
|
+### Debug Log References
|
|
|
+
|
|
|
+### Completion Notes List
|
|
|
+
|
|
|
+### File List
|
|
|
+
|
|
|
+## QA Results
|
|
|
+*此部分由QA代理在审查完成后填写*
|