|
|
@@ -0,0 +1,155 @@
|
|
|
+# Story 006.008: 购物车页面规格切换功能
|
|
|
+
|
|
|
+## Status
|
|
|
+Draft
|
|
|
+
|
|
|
+## Story
|
|
|
+**As a** 用户(消费者),
|
|
|
+**I want** 在购物车页面直接切换同一父商品下的不同规格,
|
|
|
+**so that** 无需删除现有商品重新选择,提升用户体验
|
|
|
+
|
|
|
+## Acceptance Criteria
|
|
|
+1. 用户能在购物车页面成功切换商品规格
|
|
|
+2. 切换后商品名称、价格、库存信息正确更新
|
|
|
+3. 购物车总价正确重新计算
|
|
|
+4. 库存不足的规格无法选择或给出提示
|
|
|
+5. 现有单规格商品购物车体验不受影响
|
|
|
+
|
|
|
+## Tasks / Subtasks
|
|
|
+- [ ] 任务1:扩展CartContext支持规格切换逻辑 (AC: 1, 2, 3)
|
|
|
+ - [ ] 在`CartContext`中添加`switchSpec`函数,支持切换购物车项规格
|
|
|
+ - [ ] 更新`CartItem`接口,包含父商品ID和当前子商品ID信息
|
|
|
+ - [ ] 确保规格切换后本地存储正确更新
|
|
|
+- [ ] 任务2:在购物车项组件中集成规格选择器 (AC: 1, 4)
|
|
|
+ - [ ] 在`CartItem`组件(或类似组件)中添加规格切换按钮
|
|
|
+ - [ ] 集成`GoodsSpecSelector`组件,显示当前规格和切换选项
|
|
|
+ - [ ] 添加库存验证,库存不足的规格禁用或提示
|
|
|
+- [ ] 任务3:实现规格切换状态更新逻辑 (AC: 2, 3)
|
|
|
+ - [ ] 实现规格切换时更新商品ID、名称、价格、库存信息
|
|
|
+ - [ ] 保持购物车项数量不变,只切换规格
|
|
|
+ - [ ] 更新购物车小计和总计计算
|
|
|
+- [ ] 任务4:添加库存验证和错误处理 (AC: 4)
|
|
|
+ - [ ] 检查切换目标规格的库存是否足够
|
|
|
+ - [ ] 添加用户友好提示信息
|
|
|
+ - [ ] 处理切换失败的错误情况
|
|
|
+- [ ] 任务5:编写单元测试和集成测试 (AC: 1-5)
|
|
|
+ - [ ] 为`CartContext`的`switchSpec`函数添加单元测试
|
|
|
+ - [ ] 为购物车页面规格切换添加组件测试
|
|
|
+ - [ ] 验证多租户兼容性测试
|
|
|
+ - [ ] 测试向后兼容性(单规格商品不受影响)
|
|
|
+- [ ] 任务6:验证多租户兼容性和性能 (AC: 5)
|
|
|
+ - [ ] 确保父子商品在同一租户下的约束
|
|
|
+ - [ ] 验证切换操作性能不影响用户体验
|
|
|
+ - [ ] 检查本地存储更新效率
|
|
|
+
|
|
|
+## Dev Notes
|
|
|
+
|
|
|
+### 数据模型
|
|
|
+- **商品实体 (`GoodsMt`)**:
|
|
|
+ - `spuId`字段:0表示父商品或单规格商品,>0表示子商品
|
|
|
+ - `spuName`字段:父商品名称
|
|
|
+ - 父子商品在同一租户下(`tenantId`相同)
|
|
|
+ - [Source: packages/goods-module-mt/src/entities/goods.entity.mt.ts#L77-L81]
|
|
|
+
|
|
|
+- **购物车项 (`CartItem`)**:
|
|
|
+ - `id`: 商品ID(当前子商品ID,或父商品ID如果无规格)
|
|
|
+ - `name`: 商品名称(应包含规格信息)
|
|
|
+ - `price`: 商品价格
|
|
|
+ - `stock`: 库存数量
|
|
|
+ - `quantity`: 购买数量
|
|
|
+ - `spec?`: 可选规格字段
|
|
|
+ - 需要扩展:`parentGoodsId`字段(用于获取子商品列表)
|
|
|
+ - [Source: mini/src/contexts/CartContext.tsx#L4-L12]
|
|
|
+
|
|
|
+- **规格选择器数据结构**:
|
|
|
+ ```typescript
|
|
|
+ interface SpecOption {
|
|
|
+ id: number // 子商品ID
|
|
|
+ name: string // 规格名称(子商品名称)
|
|
|
+ price: number // 规格价格
|
|
|
+ stock: number // 规格库存
|
|
|
+ image?: string // 规格图片
|
|
|
+ }
|
|
|
+ ```
|
|
|
+
|
|
|
+### API 规范
|
|
|
+- **购物车API**:前端本地存储,无需后端API修改
|
|
|
+ - 使用`Taro.setStorageSync`存储购物车数据
|
|
|
+ - [Source: mini/src/contexts/CartContext.tsx#L65-L75]
|
|
|
+
|
|
|
+- **商品API**:
|
|
|
+ - 子商品列表API:`GET /api/v1/goods/:id/children` (故事2已实现)
|
|
|
+ - 商品详情API:返回父商品详情和子商品列表
|
|
|
+ - [Source: packages/goods-module-mt/src/services/goods.mt.service.ts#L120-L150]
|
|
|
+
|
|
|
+### 组件规范
|
|
|
+- **购物车上下文 (`CartContext`)**:
|
|
|
+ - 位置:`mini/src/contexts/CartContext.tsx`
|
|
|
+ - 现有函数:`addToCart`, `removeFromCart`, `updateQuantity`, `clearCart`
|
|
|
+ - 需要添加:`switchSpec(cartItemId, newChildGoodsId)`
|
|
|
+ - [Source: mini/src/contexts/CartContext.tsx#L90-L127]
|
|
|
+
|
|
|
+- **规格选择器 (`GoodsSpecSelector`)**:
|
|
|
+ - 位置:`mini/src/components/goods-spec-selector/index.tsx`
|
|
|
+ - 已支持父子商品规格选择(故事5完成)
|
|
|
+ - Props:`parentGoodsId`, `value`(当前子商品ID), `onChange`
|
|
|
+ - [Source: mini/tests/unit/components/goods-spec-selector/goods-spec-selector.test.tsx]
|
|
|
+
|
|
|
+- **购物车页面 (`cart/index.tsx`)**:
|
|
|
+ - 位置:`mini/src/pages/cart/index.tsx`
|
|
|
+ - 使用`CartContext`管理状态
|
|
|
+ - 需要集成规格选择器到购物车项组件
|
|
|
+ - [Source: mini/src/pages/cart/index.tsx]
|
|
|
+
|
|
|
+### 文件位置
|
|
|
+- 购物车上下文:`mini/src/contexts/CartContext.tsx`
|
|
|
+- 购物车页面:`mini/src/pages/cart/index.tsx`
|
|
|
+- 规格选择器组件:`mini/src/components/goods-spec-selector/index.tsx`
|
|
|
+- 商品实体:`packages/goods-module-mt/src/entities/goods.entity.mt.ts`
|
|
|
+- 商品服务:`packages/goods-module-mt/src/services/goods.mt.service.ts`
|
|
|
+- 测试文件:`mini/tests/unit/contexts/CartContext.test.tsx`
|
|
|
+
|
|
|
+### 技术约束
|
|
|
+- **多租户要求**:所有操作必须包含`tenantId`过滤,父子商品必须在同一租户下
|
|
|
+- **向后兼容性**:现有单规格商品(`spuId=0`且无子商品)必须继续正常工作
|
|
|
+- **性能考虑**:规格切换应快速响应,避免频繁API调用
|
|
|
+- **本地存储限制**:购物车数据大小需控制在合理范围内
|
|
|
+
|
|
|
+### 先前故事洞察
|
|
|
+- **故事5-6**:已实现`GoodsSpecSelector`组件和商品详情页集成
|
|
|
+- **故事4**:商品API已支持父子商品关系,详情API返回子商品列表
|
|
|
+- **故事2**:已实现子商品管理API,包括获取子商品列表
|
|
|
+- **故事7**:购物车已支持子商品添加,`CartItem`接口已包含规格信息
|
|
|
+- **关键设计决策**:规格=子商品名称,规格选择=选择子商品,购物车逻辑简化(使用子商品的`id`、`name`、`price`、`stock`)
|
|
|
+
|
|
|
+### 测试标准
|
|
|
+- **测试框架**:mini项目使用Jest,其他包使用Vitest
|
|
|
+- **测试位置**:与源码并列的`tests/`目录
|
|
|
+- **单元测试位置**:`mini/tests/unit/contexts/CartContext.test.tsx`
|
|
|
+- **组件测试位置**:`mini/tests/unit/pages/cart/`
|
|
|
+- **测试命名**:描述性测试名称,如"应该支持在购物车中切换商品规格"
|
|
|
+- **Mock策略**:Mock Taro API、商品API调用
|
|
|
+- **测试覆盖率**:核心业务逻辑 > 80%,关键函数 > 90%
|
|
|
+
|
|
|
+## Change Log
|
|
|
+| Date | Version | Description | Author |
|
|
|
+|------|---------|-------------|--------|
|
|
|
+| 2025-12-13 | 1.0 | 初始故事创建 | Bob (Scrum Master) |
|
|
|
+
|
|
|
+## Dev Agent Record
|
|
|
+*此部分由开发代理在实施过程中填写*
|
|
|
+
|
|
|
+### Agent Model Used
|
|
|
+{{agent_model_name_version}}
|
|
|
+
|
|
|
+### Debug Log References
|
|
|
+*引用开发过程中生成的调试日志或跟踪信息*
|
|
|
+
|
|
|
+### Completion Notes List
|
|
|
+*记录任务完成情况和遇到的问题*
|
|
|
+
|
|
|
+### File List
|
|
|
+*列出故事实现过程中创建、修改或影响的所有文件*
|
|
|
+
|
|
|
+## QA Results
|
|
|
+*此部分由QA代理在审查完成后填写*
|