|
|
@@ -0,0 +1,165 @@
|
|
|
+# Story 006.005: 父子商品多规格选择组件开发
|
|
|
+
|
|
|
+## Status
|
|
|
+Draft
|
|
|
+
|
|
|
+## Story
|
|
|
+**As a** 商品购买用户
|
|
|
+**I want** 在商品详情页选择子商品作为规格选项
|
|
|
+**so that** 我能够购买特定规格(如颜色、尺寸、配置等)的商品
|
|
|
+
|
|
|
+## Acceptance Criteria
|
|
|
+1. 激活并增强现有的`GoodsSpecSelector`组件,移除模拟数据
|
|
|
+2. 组件支持父子商品关系,以子商品名称作为规格选项显示
|
|
|
+3. 规格选择实际选择对应的子商品ID,而不仅仅是规格名称
|
|
|
+4. 组件适配多租户商品数据查询,包含正确的tenantId过滤
|
|
|
+5. 规格选择器能正确显示子商品名称作为规格,并能选择对应的子商品
|
|
|
+6. 选择规格后,组件应显示子商品的价格、库存等信息
|
|
|
+
|
|
|
+## Tasks / Subtasks
|
|
|
+- [ ] 分析现有GoodsSpecSelector组件实现 (AC: 1)
|
|
|
+ - [ ] 查看当前组件代码和模拟数据逻辑
|
|
|
+ - [ ] 分析组件在商品详情页中的使用方式(当前被注释)
|
|
|
+ - [ ] 确定需要修改的接口和数据结构
|
|
|
+- [ ] 修改GoodsSpecSelector组件支持父子商品关系 (AC: 2, 3)
|
|
|
+ - [ ] 更新SpecOption接口,支持子商品ID、价格、库存等字段
|
|
|
+ - [ ] 修改组件props,接收父商品ID而不是通用商品ID
|
|
|
+ - [ ] 实现子商品数据获取逻辑,替换模拟数据
|
|
|
+ - [ ] 更新规格选择逻辑,确保选择的是子商品ID
|
|
|
+- [ ] 集成子商品列表API调用 (AC: 2, 3)
|
|
|
+ - [ ] 在组件中添加API调用获取子商品列表(GET /api/v1/goods/{id}/children)
|
|
|
+ - [ ] 处理API加载状态、错误状态和空状态
|
|
|
+ - [ ] 将API响应数据转换为组件所需的SpecOption格式
|
|
|
+ - [ ] 确保API调用包含多租户参数
|
|
|
+- [ ] 适配多租户数据查询 (AC: 4)
|
|
|
+ - [ ] 确保API调用包含正确的tenantId参数
|
|
|
+ - [ ] 验证父子商品在同一租户下的数据一致性
|
|
|
+ - [ ] 添加租户数据隔离的安全检查
|
|
|
+- [ ] 在商品详情页取消注释并集成组件 (AC: 5)
|
|
|
+ - [ ] 取消商品详情页中对GoodsSpecSelector组件的注释
|
|
|
+ - [ ] 更新商品详情页的规格选择状态管理
|
|
|
+ - [ ] 集成组件与"立即购买"和"加入购物车"功能
|
|
|
+ - [ ] 确保向后兼容性(无规格商品保持现有行为)
|
|
|
+- [ ] 添加单元测试和集成测试 (AC: 1-6)
|
|
|
+ - [ ] 为GoodsSpecSelector组件添加单元测试
|
|
|
+ - [ ] 测试组件渲染、规格选择、API调用等场景
|
|
|
+ - [ ] 添加商品详情页集成测试
|
|
|
+ - [ ] 确保测试覆盖多租户场景
|
|
|
+ - [ ] 验证所有测试通过
|
|
|
+
|
|
|
+## Dev Notes
|
|
|
+
|
|
|
+### 技术栈信息 [Source: architecture/tech-stack.md]
|
|
|
+- **前端框架**: React 19.1.0 + TypeScript
|
|
|
+- **小程序框架**: Taro(微信小程序)
|
|
|
+- **构建工具**: Vite 7.0.0
|
|
|
+- **状态管理**: @tanstack/react-query (服务端状态)
|
|
|
+- **UI组件库**: shadcn/ui (基于Radix UI)
|
|
|
+- **样式**: Tailwind CSS 4.1.11
|
|
|
+- **HTTP客户端**: 基于Hono Client的封装 + axios适配器
|
|
|
+
|
|
|
+### 源码树信息 [Source: architecture/source-tree.md]
|
|
|
+- **小程序项目位置**: `mini/` - 小程序项目 (Taro + React)
|
|
|
+- **组件位置**: `mini/src/components/goods-spec-selector/index.tsx` - 现有规格选择器组件
|
|
|
+- **页面位置**: `mini/src/pages/goods-detail/index.tsx` - 商品详情页面(当前组件被注释)
|
|
|
+- **API客户端位置**: `mini/src/api.ts` - API客户端配置
|
|
|
+- **测试位置**: `mini/tests/` - 小程序测试文件
|
|
|
+
|
|
|
+### 数据模型信息 [Source: docs/stories/006.004.goods-api-parent-child-support-optimization.story.md:68-73]
|
|
|
+- **商品实体字段**:
|
|
|
+ - `id`: number - 商品ID
|
|
|
+ - `spuId`: number - 主商品ID,0表示父商品或单规格商品,>0表示子商品
|
|
|
+ - `spuName`: string | null - 主商品名称
|
|
|
+ - `tenantId`: number - 租户ID,用于多租户数据隔离
|
|
|
+ - `state`: number - 状态(1可用,2不可用)
|
|
|
+ - `name`: string - 商品名称(子商品名称作为规格名称)
|
|
|
+ - `price`: number - 商品价格
|
|
|
+ - `stock`: number - 商品库存
|
|
|
+- **父子商品关系**: 通过spuId字段建立父子关系,子商品的spuId指向父商品的id
|
|
|
+
|
|
|
+### API信息 [Source: docs/prd/epic-006-parent-child-goods-multi-spec-support.md:79]
|
|
|
+- **获取子商品列表API**: `GET /api/v1/goods/{id}/children` - 已实现,返回指定父商品的子商品列表
|
|
|
+- **API响应格式**: 返回子商品数组,每个子商品包含id、name、price、stock等字段
|
|
|
+- **API路由位置**: `packages/goods-module-mt/src/routes/public-goods-children.mt.ts`
|
|
|
+
|
|
|
+### 现有组件分析
|
|
|
+- **`GoodsSpecSelector`当前状态** [Source: mini/src/components/goods-spec-selector/index.tsx]:
|
|
|
+ - 使用模拟数据(mockSpecs),未调用真实API
|
|
|
+ - 当前SpecOption接口:id、name、price、stock、image
|
|
|
+ - 当前props:visible、onClose、onConfirm、goodsId、currentSpec、currentQuantity
|
|
|
+ - 需要修改:将goodsId改为parentGoodsId,添加API调用逻辑
|
|
|
+- **`GoodsDetailPage`当前状态** [Source: mini/src/pages/goods-detail/index.tsx:11]:
|
|
|
+ - 规格选择功能被注释(第11行:`// import { GoodsSpecSelector } from '@/components/goods-spec-selector'`)
|
|
|
+ - 规格选择状态管理被注释(第45-46行)
|
|
|
+ - 需要取消注释并更新组件集成
|
|
|
+
|
|
|
+### 多租户支持要求 [Source: docs/stories/006.004.goods-api-parent-child-support-optimization.story.md:139]
|
|
|
+- 保持多租户支持完整,所有查询必须包含tenantId过滤
|
|
|
+- 父子商品必须在同一租户下
|
|
|
+- API调用需要传递正确的租户上下文
|
|
|
+
|
|
|
+### RPC客户端架构 [Source: architecture/coding-standards.md:28-33]
|
|
|
+- 使用单例模式的客户端管理器确保全局唯一的客户端实例
|
|
|
+- 组件中应使用`clientManager.get().api.$method`调用API
|
|
|
+- 类型安全:使用Hono的InferRequestType和InferResponseType确保类型一致性
|
|
|
+- 测试Mock:在测试中正确mock客户端管理器的get()方法调用链
|
|
|
+
|
|
|
+### 文件位置
|
|
|
+- **组件文件**: `mini/src/components/goods-spec-selector/index.tsx`
|
|
|
+- **组件样式**: `mini/src/components/goods-spec-selector/index.css`(如果存在)
|
|
|
+- **页面文件**: `mini/src/pages/goods-detail/index.tsx`
|
|
|
+- **API客户端**: `mini/src/api.ts`
|
|
|
+- **测试文件**: `mini/tests/components/goods-spec-selector.test.tsx`(需要创建)
|
|
|
+- **集成测试**: `mini/tests/pages/goods-detail.test.tsx`(需要更新)
|
|
|
+
|
|
|
+### 编码标准 [Source: architecture/coding-standards.md]
|
|
|
+- **测试框架**: Vitest + Testing Library
|
|
|
+- **测试位置**: `tests`文件夹与源码并列(例如:`mini/tests/components/`)
|
|
|
+- **覆盖率目标**: 核心业务逻辑 > 80%
|
|
|
+- **测试类型**: 单元测试、集成测试
|
|
|
+
|
|
|
+### Testing
|
|
|
+- **测试框架**: Vitest + Testing Library
|
|
|
+- **测试文件位置**:
|
|
|
+ - 组件单元测试: `mini/tests/components/goods-spec-selector.test.tsx`
|
|
|
+ - 页面集成测试: `mini/tests/pages/goods-detail.test.tsx`
|
|
|
+- **测试标准**:
|
|
|
+ - 组件渲染测试:验证组件正确渲染规格选项
|
|
|
+ - API调用测试:验证组件正确调用子商品列表API
|
|
|
+ - 用户交互测试:验证规格选择、数量调整等功能
|
|
|
+ - 多租户测试:验证API调用包含正确的tenantId参数
|
|
|
+ - 错误处理测试:验证API错误、空状态等情况
|
|
|
+- **测试模式**:
|
|
|
+ - 使用`vi.mock()` mock API客户端
|
|
|
+ - 使用`render`函数渲染组件
|
|
|
+ - 使用`fireEvent`模拟用户交互
|
|
|
+ - 验证组件状态变化和回调调用
|
|
|
+- **具体测试要求**:
|
|
|
+ - 测试组件使用真实API而不是模拟数据
|
|
|
+ - 测试规格选择正确传递子商品ID
|
|
|
+ - 测试多租户参数正确传递
|
|
|
+ - 测试商品详情页集成功能
|
|
|
+ - 确保向后兼容性
|
|
|
+
|
|
|
+### 项目结构注意事项
|
|
|
+- 保持多租户支持完整,所有API调用必须包含tenantId参数
|
|
|
+- 父子商品关系数据一致性验证
|
|
|
+- 保持API向后兼容性,不影响现有功能
|
|
|
+- 组件修改保持现有接口兼容性(尽可能)
|
|
|
+
|
|
|
+## Change Log
|
|
|
+| Date | Version | Description | Author |
|
|
|
+|------|---------|-------------|--------|
|
|
|
+| 2025-12-12 | 1.0 | 初始故事创建 | Bob (Scrum Master) |
|
|
|
+
|
|
|
+## Dev Agent Record
|
|
|
+
|
|
|
+### Agent Model Used
|
|
|
+
|
|
|
+### Debug Log References
|
|
|
+
|
|
|
+### Completion Notes List
|
|
|
+
|
|
|
+### File List
|
|
|
+
|
|
|
+## QA Results
|