Explorar o código

📝 docs(stories): 创建子商品删除功能故事006.011

- 创建故事006.011文档,描述子商品实体删除功能实现
- 更新史诗006状态,添加故事12并调整进度为9/12
- 明确与解除父子关系功能的区别(删除实体 vs 解除关系)
- 包含完整的技术实施指导、API规范、测试要求

🤖 Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname hai 1 mes
pai
achega
796873bbcd

+ 52 - 5
docs/prd/epic-006-parent-child-goods-multi-spec-support.md

@@ -1,9 +1,9 @@
 # 史诗006:父子商品多规格支持 - 棕地增强
 
 ## 史诗状态
-**进度**: 9/11 故事完成 (81.8%)
-**最近更新**: 2025-12-15 (新增故事11:子商品删除功能实现)
-**当前状态**: 故事1-9已完成,故事10-11待开始
+**进度**: 9/12 故事完成 (75.0%)
+**最近更新**: 2025-12-15 (新增故事12:商品详情页规格选择流程优化)
+**当前状态**: 故事1-9已完成,故事10-12待开始
 
 ### 完成概览
 - ✅ **故事1**: 管理后台父子商品配置功能 (已完成)
@@ -17,6 +17,7 @@
 - ✅ **故事9**: 父子商品名称关联查询优化(为购物车显示做准备) (已完成)
 - ⏳ **故事10**: 购物车商品名称显示优化 (待开始)
 - ⏳ **故事11**: 子商品删除功能实现 (待开始)
+- ⏳ **故事12**: 商品详情页规格选择流程优化 (待开始)
 
 ## 史诗目标
 新增父子商品多规格支持功能,在商品添加购物车或立即购买时,能同时支持单规格和多规格选择,以子商品作为多规格选项,并支持手动指定子商品。
@@ -61,6 +62,7 @@
   8. ✅ 父子商品名称通过关联查询获取,为购物车显示提供准确父商品名称(故事9已实现)
   9. ⏳ 购物车中父子商品显示完整的组合名称(父商品名称 + 子商品规格名称)(故事10待实现)
   10. ⏳ 管理员能删除不需要的子商品规格(故事11待实现)
+  11. ⏳ 用户在商品详情页能一键完成规格选择和购物车/购买操作(故事12待实现)
 
 ## 设计决策
 
@@ -413,12 +415,57 @@
        - 可能添加删除确认对话框组件或复用现有Dialog
      - **可能新建的文件**:无(复用现有组件和API)
 
+12. **故事12:商品详情页规格选择流程优化** ⏳ **待开始**
+   - **问题背景**:当前小程序商品详情页的规格选择流程不够流畅。页面中有一个独立的"选择规格"按钮,用户需要先点击该按钮选择规格,关闭规格选择弹窗,然后再点击"加入购物车"或"立即购买"按钮。这种两步操作给用户带来不便,特别是对于多规格商品,用户需要记住已选择的规格再进行购买操作,体验不够直观。
+   - **解决方案**:优化商品详情页的规格选择流程,将规格选择与购物车/购买操作合并。当用户点击"加入购物车"或"立即购买"按钮时,如果商品有多规格选项且用户未选择规格,自动弹出规格选择器。用户选择规格和数量后,直接执行对应的购物车添加或购买操作,实现一键完成规格选择和购买。
+     - **完整流程**:
+       1. 用户点击"加入购物车"或"立即购买"按钮
+       2. 系统判断:如果商品有多规格选项且用户未选择规格 → 弹出规格选择器
+       3. 用户在规格选择器中选择规格和数量,点击确定
+       4. 直接执行对应的购物车添加或购买操作
+       5. 如果用户没有完成操作(如取消或返回),选择的规格状态保持在页面中
+       6. 用户再次点击操作按钮 → 再次弹出规格选择器,自动选中上次选择的规格
+       7. 用户可以快速确认原有选择,或修改规格/数量后继续操作
+   - **功能需求**:
+     - 移除商品详情页中独立的"选择规格"按钮,将规格选择与操作按钮深度集成
+     - 点击"加入购物车"或"立即购买"时,自动判断是否需要弹出规格选择器
+     - 规格选择器弹出后,用户选择规格和数量,点击确定直接执行对应操作
+     - 用户在页面上已选择的规格状态可以保持,下次弹出规格选择器时自动选中之前选择的规格,方便用户快速确认或修改选择
+     - 保持向后兼容性:单规格商品(无子商品)的操作流程不变
+     - 优化用户界面,在按钮上显示当前选择的规格信息(如有)
+   - **技术实现**:
+     - 修改`mini/src/pages/goods-detail/index.tsx`中的`handleAddToCart`和`handleBuyNow`函数,添加规格选择判断逻辑
+     - 重构规格选择状态管理,将`showSpecModal`状态与操作流程关联
+     - 扩展`GoodsSpecSelector`组件的`onConfirm`回调,支持直接执行购物车添加或购买操作
+     - 添加规格选择上下文,记录用户选择规格后的目标操作(加入购物车或立即购买)
+     - 优化按钮禁用状态逻辑,基于规格选择状态动态更新
+     - 添加规格信息显示组件,在操作按钮区域显示当前选择的规格和价格
+   - **验收标准**:
+     - 用户点击"加入购物车"或"立即购买"时,如果需要选择规格,自动弹出规格选择器
+     - 用户在规格选择器中选择规格和数量后,直接执行对应的购物车添加或购买操作
+     - 用户在页面上已选择的规格状态可以保持,下次弹出规格选择器时自动选中之前选择的规格,方便用户快速确认或修改选择
+     - 单规格商品的操作流程保持不变,不受影响
+     - 用户界面清晰显示当前选择的规格信息(如有)
+     - 操作流程流畅,无多余的弹窗关闭和重新点击步骤
+   - **完成状态**:
+     - ⏳ 功能待实现
+     - ⏳ 技术方案待设计
+     - ⏳ 测试待编写
+   - **文件变更**:
+     - **待修改的文件**:
+       - `mini/src/pages/goods-detail/index.tsx` - 重构规格选择流程,合并操作逻辑
+       - `mini/src/components/goods-spec-selector/index.tsx` - 扩展组件支持直接操作执行
+       - 可能修改`mini/src/contexts/CartContext.tsx`中的购物车添加逻辑
+     - **可能新建的文件**:
+       - `mini/src/components/goods-spec-action-context.tsx` - 规格选择操作上下文组件(可选)
+       - `mini/src/components/selected-spec-display.tsx` - 已选规格信息显示组件(可选)
+
 ## 兼容性要求
 - [x] 现有API保持向后兼容,新增端点不影响现有功能(故事2、4、7已确保)
 - [x] 数据库schema向后兼容,利用现有spuId字段(故事1-4已实现)
 - [x] UI变更遵循现有设计模式(故事2、3、5、6已实现)
 - [x] 性能影响最小化,特别是商品列表查询(故事4添加数据库索引优化)
-- [x] 多租户隔离机制保持完整(故事1-7已实现)
+- [x] 多租户隔离机制保持完整(故事1-9已实现)
 
 ## 风险缓解
 - **主要风险**:API变更影响现有客户端,规格选择逻辑影响购物车功能
@@ -426,7 +473,7 @@
 - **回滚计划**:移除新增API端点,恢复原有逻辑,保持多租户完整性
 
 ## 完成定义
-- [x] 所有故事完成,验收标准满足(9/11完成,故事10-11待实现)
+- [x] 所有故事完成,验收标准满足(9/12完成,故事10-12待实现)
 - [x] 现有功能通过测试验证(故事1-9测试通过)
 - [x] API变更经过兼容性测试(故事2-9 API测试通过)
 - [x] 多租户隔离机制保持完整(故事1-9已实现)

+ 155 - 0
docs/stories/006.011.child-goods-deletion.story.md

@@ -0,0 +1,155 @@
+# Story 006.011: 子商品删除功能实现
+
+## Status
+Draft
+
+## Story
+**As a** 管理员,
+**I want** 在父子商品管理面板中删除不需要的子商品规格,
+**so that** 我能管理商品规格清单,保持商品数据的整洁和准确
+
+## Acceptance Criteria
+1. 管理员能在父子商品管理面板中成功删除子商品
+2. 删除前有确认提示,防止误操作
+3. 删除后子商品列表实时更新
+4. 删除操作仅影响当前租户的数据,多租户隔离保持完整
+5. 现有功能不受影响,无回归问题
+
+## Tasks / Subtasks
+- [ ] 任务1:在GoodsParentChildPanel组件中添加onDeleteChild回调函数 (AC: 1, 2, 3)
+  - [ ] 检查GoodsParentChildPanel当前是否传递onDeleteChild回调给ChildGoodsList组件
+  - [ ] 在GoodsParentChildPanel组件中添加onDeleteChild回调函数处理子商品删除逻辑
+  - [ ] 实现删除确认对话框,使用现有Dialog组件防止误操作
+  - [ ] 添加删除状态管理(加载中、错误处理)
+- [ ] 任务2:调用商品删除API实现子商品实体删除 (AC: 1, 3, 4)
+  - [ ] 使用商品删除API:`DELETE /api/v1/goods/:id`(通用商品删除API)
+  - [ ] 添加API调用Mutation,包含完整的错误处理和加载状态
+  - [ ] 验证商品必须是子商品(spuId > 0)且在当前租户下
+  - [ ] 删除成功后调用refetch刷新子商品列表数据
+  - [ ] 更新本地状态(如需要)
+- [ ] 任务3:更新ChildGoodsList组件删除按钮的视觉反馈 (AC: 1, 2)
+  - [ ] 确保删除按钮在点击时有适当的视觉反馈
+  - [ ] 在删除操作期间禁用按钮,防止重复点击
+  - [ ] 添加加载状态指示器
+- [ ] 任务4:编写和更新测试 (AC: 5)
+  - [ ] 为GoodsParentChildPanel添加子商品删除功能的单元测试
+  - [ ] 更新ChildGoodsList单元测试,验证onDeleteChild回调传递
+  - [ ] 添加集成测试验证删除流程的完整性
+  - [ ] 运行现有测试套件,确保无回归问题
+- [ ] 任务5:验证多租户兼容性和向后兼容性 (AC: 4, 5)
+  - [ ] 验证删除操作仅影响当前租户的数据
+  - [ ] 确保父子商品在同一租户下的约束
+  - [ ] 验证单规格商品和无父子关系的商品功能不受影响
+  - [ ] 进行端到端测试验证完整删除流程
+
+## Dev Notes
+
+### 先前故事洞察
+- **故事2(父子商品管理UI体验优化)**:已实现父子商品管理API,包括解除父子关系API(`DELETE /api/v1/goods/:id/parent`),GoodsParentChildPanel组件已包含removeParentMutation用于解除当前商品的父子关系。**重要区别**:解除父子关系是使子商品成为独立商品,而本故事需要实现的是**删除子商品实体**功能
+- **故事3(子商品行内编辑功能)**:已扩展ChildGoodsList组件支持行内编辑,组件包含删除按钮但onDeleteChild回调未由父组件提供,导致删除操作无效。本故事需要实现此回调以支持子商品实体删除
+- **故事9(父子商品名称关联查询优化)**:商品详情API不再返回spuName字段,使用parent对象获取父商品信息。删除子商品实体后,需确保父子商品关系数据清理
+- **故事10(购物车商品名称显示优化)**:购物车使用parent.name获取父商品名称。删除子商品实体后,需确保购物车中相关子商品引用得到适当处理(如购物车项失效或清理)
+- [Source: docs/prd/epic-006-parent-child-goods-multi-spec-support.md#故事11]
+- [Source: docs/stories/006.002.parent-child-goods-ui-optimization.story.md]
+- [Source: docs/stories/006.003.child-goods-inline-edit.story.md]
+
+### 数据模型
+- **商品实体 (`GoodsMt`)**:
+  - `spuId` 字段:0表示父商品或单规格商品,>0表示子商品
+  - `spuName` 字段:父商品名称(冗余字段,保留在实体中保持向后兼容性,但从API响应中移除)
+  - `tenantId` 字段:租户ID,父子商品必须在同一租户下
+  - `name` 字段:商品名称,对于子商品就是规格名称
+  - [Source: packages/goods-module-mt/src/entities/goods.entity.mt.ts#L76-L81]
+
+- **父子关系约束**:
+  - 父子商品必须在同一租户下(`tenantId`相同)
+  - 子商品通过`spuId`字段关联到父商品
+  - 解除父子关系:将子商品的`spuId`设为0,`spuName`设为null(故事2已实现)
+  - **本故事操作**:删除子商品实体(永久删除,非解除关系)
+  - [Source: docs/prd/epic-006-parent-child-goods-multi-spec-support.md#多租户支持]
+
+### API 规范
+- **商品删除API** (`DELETE /api/v1/goods/:id`):
+  - 功能:完全删除商品实体,包括数据库记录和相关关联数据
+  - 验证:商品必须存在,必须在当前租户下,需验证权限
+  - 响应:返回删除成功状态(通常为204 No Content或200 OK)
+  - 错误处理:404错误(商品不存在)、403错误(权限不足)、租户权限错误
+  - 特殊考虑:删除子商品时需验证是否为子商品(`spuId > 0`),但API本身可能不限制
+  - **业务决策**:本故事使用商品删除API永久删除子商品实体,而非解除父子关系API
+  - [Source: docs/prd/epic-006-parent-child-goods-multi-spec-support.md#故事11]
+
+### 组件规范
+- **GoodsParentChildPanel组件**:
+  - 位置:`packages/goods-management-ui-mt/src/components/GoodsParentChildPanel.tsx`
+  - 当前状态:已包含removeParentMutation用于解除当前商品的父子关系,但未为ChildGoodsList组件提供onDeleteChild回调
+  - 需要添加:onDeleteChild回调函数、删除确认对话框、删除状态管理
+  - [Source: packages/goods-management-ui-mt/src/components/GoodsParentChildPanel.tsx#L143-L170]
+
+- **ChildGoodsList组件**:
+  - 位置:`packages/goods-management-ui-mt/src/components/ChildGoodsList.tsx`
+  - 当前状态:包含删除按钮,点击调用onDeleteChild回调,但父组件未提供此回调
+  - 删除按钮:使用Trash2图标,点击触发handleDelete函数
+  - 需要:父组件传递onDeleteChild回调,删除期间视觉反馈
+  - [Source: packages/goods-management-ui-mt/src/components/ChildGoodsList.tsx#L143-L147]
+  - [Source: packages/goods-management-ui-mt/src/components/ChildGoodsList.tsx#L262-L270]
+
+- **对话框组件**:
+  - 使用现有Dialog组件实现删除确认
+  - 确认提示信息:"确定要永久删除这个子商品规格吗?此操作将删除商品实体,包括所有相关数据,无法恢复。"
+  - 按钮:"取消"和"确定删除"
+  - [Source: packages/goods-management-ui-mt/src/components/GoodsParentChildPanel.tsx#L11]
+
+### 文件位置
+- **主要修改文件**:
+  - `packages/goods-management-ui-mt/src/components/GoodsParentChildPanel.tsx` - 添加onDeleteChild回调函数,实现删除确认对话框和API调用
+  - `packages/goods-management-ui-mt/src/components/ChildGoodsList.tsx` - 可能优化删除按钮的视觉反馈
+  - [Source: docs/prd/epic-006-parent-child-goods-multi-spec-support.md#故事11]
+
+- **测试文件**:
+  - `packages/goods-management-ui-mt/tests/unit/GoodsParentChildPanel.test.tsx` - 添加子商品删除功能测试
+  - `packages/goods-management-ui-mt/tests/unit/ChildGoodsList.test.tsx` - 更新测试验证onDeleteChild回调传递
+  - `packages/goods-management-ui-mt/tests/integration/goods-management.integration.test.tsx` - 可能添加集成测试
+  - [Source: docs/architecture/testing-strategy.md#单元测试-unit-tests]
+
+- **API测试文件**:
+  - 商品删除API (`DELETE /api/v1/goods/:id`) 是通用CRUD API的一部分,测试包含在通用CRUD测试中
+  - 如需验证商品删除功能,可参考现有商品API测试套件
+  - [Source: docs/architecture/testing-strategy.md#集成测试-integration-tests]
+
+### 技术约束
+- **多租户要求**:所有操作必须包含`tenantId`过滤,父子商品必须在同一租户下,删除操作仅影响当前租户数据
+- **向后兼容性**:现有功能不受影响,数据库实体保留`spuName`字段,仅从API响应中移除
+- **性能考虑**:删除操作应快速响应,列表刷新不应显著影响页面性能
+- **数据一致性**:删除子商品实体后,需确保父子商品关系清理,相关数据(如购物车中的子商品引用)应适当处理
+- [Source: docs/architecture/tech-stack.md]
+- [Source: docs/architecture/source-tree.md]
+
+### 测试标准
+- **测试框架**:商品管理界面使用Vitest + Testing Library
+- **测试位置**:`tests`文件夹与源码并列(例如:`packages/goods-management-ui-mt/tests/unit/`)
+- **单元测试位置**:`packages/goods-management-ui-mt/tests/unit/`目录下对应组件测试文件
+- **集成测试位置**:`packages/goods-management-ui-mt/tests/integration/`目录
+- **测试覆盖率**:核心业务逻辑 > 80%,关键函数 > 90%
+- **测试策略**:验证删除功能完整性、确认对话框工作正常、API调用正确、多租户兼容性、无回归问题
+- **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-15 | 1.0 | 初始故事创建 | Bob (Scrum Master) |
+
+## Dev Agent Record
+*此部分由开发代理在实施过程中填写*
+
+### Agent Model Used
+
+### Debug Log References
+
+### Completion Notes List
+
+### File List
+
+## QA Results
+*此部分由QA代理在审查完成后填写*