Explorar el Código

feat(epic-006): 添加故事2并更新史诗结构

## 变更内容
1. **新增故事2文档**: `006.002.parent-child-goods-ui-optimization.story.md`
   - 父子商品管理UI体验优化故事
   - 支持创建和编辑模式的统一管理面板
   - 在现有`adminGoodsRoutesMt`中聚合父子商品管理API

2. **更新史诗006文档**: 调整故事结构
   - 原故事2、3改为故事3、4,原故事4、5改为故事5、6
   - 故事2: 父子商品管理UI体验优化(新增)
   - 故事3: 商品API父子商品支持优化(调整分工)
   - 明确API聚合方案,保持`adminGoodsRoutesMt`名称不变

## 设计决策
- 基于`public-goods-random.mt.ts`模式创建自定义路由
- 在`admin-goods-routes.mt.ts`中聚合基础CRUD和父子商品管理路由
- 前端零修改:保持`adminGoodsRoutesMt`名称和导入方式不变

🤖 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 hace 1 mes
padre
commit
a748e2703b

+ 26 - 15
docs/prd/epic-006-parent-child-goods-multi-spec-support.md

@@ -1,16 +1,17 @@
 # 史诗006:父子商品多规格支持 - 棕地增强
 
 ## 史诗状态
-**进度**: 1/5 故事完成 (20%)
-**最近更新**: 2025-12-07
-**当前状态**: 故事1已完成,故事2-5待实现
+**进度**: 1/6 故事完成 (17%)
+**最近更新**: 2025-12-09 (更新故事2设计,明确API聚合方案)
+**当前状态**: 故事1已完成,故事2-6待实现
 
 ### 完成概览
 - ✅ **故事1**: 管理后台父子商品配置功能 (已完成)
-- ⏳ **故事2**: 商品API父子商品支持优化 (待实现)
-- ⏳ **故事3**: 父子商品多规格选择组件开发 (待实现)
-- ⏳ **故事4**: 商品详情页规格选择集成 (待实现)
-- ⏳ **故事5**: 购物车和订单规格支持 (待实现)
+- ⏳ **故事2**: 父子商品管理UI体验优化 (待实现)
+- ⏳ **故事3**: 商品API父子商品支持优化 (待实现)
+- ⏳ **故事4**: 父子商品多规格选择组件开发 (待实现)
+- ⏳ **故事5**: 商品详情页规格选择集成 (待实现)
+- ⏳ **故事6**: 购物车和订单规格支持 (待实现)
 
 ## 史诗目标
 新增父子商品多规格支持功能,在商品添加购物车或立即购买时,能同时支持单规格和多规格选择,以子商品作为多规格选项,并支持手动指定子商品。
@@ -82,28 +83,38 @@
      - ✅ 集成测试通过(后端6个 + 前端5个)
      - ✅ 代码已提交并推送到远程仓库
 
-2. **故事2:商品API父子商品支持优化**
-   - 公共商品列表API:默认只返回父商品(spuId=0)
-   - 新增API端点:`GET /api/v1/goods/:id/children` 获取子商品列表
+2. **故事2:父子商品管理UI体验优化** ⏳ **待实现**
+   - 在商品创建和编辑页面都添加统一的父子商品管理面板
+   - 面板智能支持创建模式和编辑模式的不同行为
+   - 创建模式:支持设为父商品、选择父商品、批量创建子商品规格模板
+   - 编辑模式:支持父子关系树展示、子商品管理、关系解除
+   - 将批量创建子商品功能整合到面板中,支持创建时批量创建
+   - 面板与表单数据实时同步,确保提交数据一致性
+   - **API实现**:在现有`adminGoodsRoutesMt`中聚合父子商品管理API(获取子商品列表、设为父商品、解除关系、批量创建)
+   - **验收标准**:管理员能在创建和编辑时一次性完成商品和规格配置,提高工作效率;前端代码无需修改即可使用新API
+
+3. **故事3:商品API父子商品支持优化** ⏳ **待实现**
+   - 公共商品列表API:默认只返回父商品(spuId=0),支持过滤参数显示子商品
    - 商品详情API:根据商品类型返回相应数据(父商品+子商品列表或子商品+父商品信息)
-   - 管理员商品API:增强父子商品关系展示
-   - **验收标准**:API变更保持向后兼容,新增端点正常工作
+   - 管理员商品API:增强父子商品关系展示和查询优化
+   - **API分工**:管理员父子商品管理API已在故事2实现,本故事专注于公共API和查询优化
+   - **验收标准**:API变更保持向后兼容,公共商品列表正确过滤父子商品关系
 
-3. **故事3:父子商品多规格选择组件开发**
+4. **故事4:父子商品多规格选择组件开发** ⏳ **待实现**
    - 激活并增强现有的`GoodsSpecSelector`组件
    - 支持父子商品关系,以子商品名称作为规格选项显示
    - 规格选择实际选择对应的子商品ID
    - 适配多租户商品数据查询
    - **验收标准**:规格选择器能正确显示子商品名称作为规格,并能选择对应的子商品
 
-4. **故事4:商品详情页规格选择集成**
+5. **故事5:商品详情页规格选择集成** ⏳ **待实现**
    - 在商品详情页集成规格选择组件
    - "立即购买"和"加入购物车"支持规格选择
    - 规格选择后使用子商品的价格和库存信息
    - 多租户环境下的商品规格数据获取
    - **验收标准**:用户能在商品详情页成功选择规格,系统使用正确的子商品价格和库存
 
-5. **故事5:购物车和订单规格支持**
+6. **故事6:购物车和订单规格支持** ⏳ **待实现**
    - **购物车最小化修改**:适配`addToCart`逻辑,支持添加子商品(使用子商品信息填充CartItem)
    - **规格信息显示**:购物车和订单中通过`name`字段显示完整规格信息
    - **订单系统兼容**:订单创建使用商品ID(可能是子商品ID),保持现有逻辑

+ 341 - 0
docs/stories/006.002.parent-child-goods-ui-optimization.story.md

@@ -0,0 +1,341 @@
+# Story 006.002: 父子商品管理UI体验优化
+
+## Status
+Draft
+
+## Story
+**As a** 系统管理员,
+**I want** 在创建和编辑商品时都能统一管理父子商品关系,
+**so that** 能够一次性完成商品和规格的配置,提高工作效率
+
+## Acceptance Criteria
+1. 在商品创建和编辑页面都添加统一的父子商品管理面板
+2. 面板智能支持创建模式和编辑模式的不同行为
+3. 创建模式:支持设为父商品、选择父商品、批量创建子商品规格模板
+4. 编辑模式:支持父子关系树展示、子商品管理、关系解除
+5. 将批量创建子商品功能整合到面板中,支持创建时批量创建
+6. 面板与表单数据实时同步,确保提交数据一致性
+7. 保持与现有功能的兼容性,平滑迁移用户体验
+
+## Tasks / Subtasks
+- [ ] **分析现有父子商品管理实现** (AC: 1, 2, 3, 4, 5, 6, 7)
+  - [ ] 分析GoodsManagement.tsx中的父子商品相关代码
+  - [ ] 分析GoodsChildSelector.tsx组件
+  - [ ] 分析BatchSpecCreator.tsx组件
+  - [ ] 识别创建模式和编辑模式的不同需求
+  - [ ] 分析表单数据同步机制
+
+- [ ] **设计父子商品管理面板组件架构** (AC: 1, 2, 3, 4)
+  - [ ] 设计GoodsParentChildPanel.tsx组件接口,支持创建/编辑模式
+  - [ ] 设计GoodsRelationshipTree.tsx组件(改进版)
+  - [ ] 设计ChildGoodsList.tsx组件
+  - [ ] 设计BatchSpecCreatorInline.tsx组件(支持创建模式模板)
+  - [ ] 设计表单数据同步机制
+
+- [ ] **创建父子商品管理面板组件** (AC: 1, 2, 3, 4)
+  - [ ] 创建GoodsParentChildPanel.tsx组件(支持双模式)
+  - [ ] 创建GoodsRelationshipTree.tsx组件(改进版)
+  - [ ] 创建ChildGoodsList.tsx组件
+  - [ ] 创建BatchSpecCreatorInline.tsx组件(支持模板保存)
+
+- [ ] **实现父子商品管理API** (AC: 4, 5)
+  - [ ] 创建`admin-goods-parent-child.mt.ts`自定义路由文件
+  - [ ] 实现GET /api/v1/goods/:id/children - 获取子商品列表
+  - [ ] 实现POST /api/v1/goods/:id/set-as-parent - 设为父商品
+  - [ ] 实现DELETE /api/v1/goods/:id/parent - 解除父子关系
+  - [ ] 实现POST /api/v1/goods/batch-create-children - 批量创建子商品(支持事务)
+  - [ ] 更新`admin-goods-routes.mt.ts`聚合基础CRUD和父子商品管理路由
+  - [ ] 确保API支持多租户隔离,保持`adminGoodsRoutesMt`名称不变
+
+- [ ] **集成父子商品管理面板到商品创建和编辑页面** (AC: 1, 5, 6, 7)
+  - [ ] 更新GoodsManagement.tsx集成新面板(创建和编辑模式)
+  - [ ] 移除原有的spuId/spuName表单字段和GoodsChildSelector
+  - [ ] 移除原有的批量创建按钮(整合到面板中)
+  - [ ] 实现面板与表单数据实时同步
+  - [ ] 更新创建和编辑提交逻辑,包含父子商品数据
+  - [ ] 确保向后兼容性
+
+- [ ] **编写单元测试和集成测试** (AC: 1, 2, 3, 4, 5, 6, 7)
+  - [ ] 测试创建模式的面板行为
+  - [ ] 测试编辑模式的面板行为
+  - [ ] 测试表单数据同步机制
+  - [ ] 测试批量创建子商品功能
+  - [ ] 测试完整的创建+配置流程
+  - [ ] 确保测试覆盖率 ≥ 80%
+  - [ ] 为GoodsParentChildPanel组件编写单元测试
+  - [ ] 为GoodsRelationshipTree组件编写单元测试
+  - [ ] 为ChildGoodsList组件编写单元测试
+  - [ ] 为BatchSpecCreatorInline组件编写单元测试
+  - [ ] 编写父子商品管理功能集成测试
+  - [ ] 确保测试覆盖率 ≥ 80%
+
+## Dev Notes
+
+### 技术栈信息 [Source: architecture/tech-stack.md]
+- **运行时**: Node.js 20.18.3
+- **框架**: Hono 4.8.5 (Web框架和API路由,RPC类型安全)
+- **前端框架**: React 19.1.0 (用户界面构建)
+- **数据库**: PostgreSQL 17 (通过TypeORM进行数据持久化存储)
+- **ORM**: TypeORM 0.3.25 (数据库操作抽象,实体管理)
+- **样式**: Tailwind CSS 4.1.11 (原子化CSS框架)
+- **状态管理**: React Query 5.83.0 (服务端状态管理)
+- **测试框架**: Vitest 2.x (单元测试框架,更好的TypeORM支持)
+- **API测试**: hono/testing (内置,API端点测试,更好的类型安全)
+
+### 项目结构信息 [Source: architecture/source-tree.md]
+- **包管理**: 使用pnpm workspace管理多包依赖关系
+- **包架构层次**:
+  - **基础设施层**: shared-types → shared-utils → shared-crud
+  - **测试基础设施**: shared-test-util
+  - **业务模块层**: 多租户模块包(-mt后缀),支持租户数据隔离
+  - **应用层**: server (重构后)
+- **多租户架构**:
+  - **包复制策略**: 基于Epic-007方案,通过复制单租户包创建多租户版本
+  - **租户隔离**: 通过租户ID实现数据隔离,支持多租户部署
+  - **后端包**: 10个多租户模块包,支持租户数据隔离
+- **文件命名**: 保持现有kebab-case命名约定
+- **模块化架构**: 采用分层包结构,支持按需安装和独立开发
+
+### 编码标准 [Source: architecture/coding-standards.md]
+- **代码风格**: TypeScript严格模式,一致的缩进和命名
+- **测试位置**: `__tests__` 文件夹与源码并列(但实际使用`tests/`目录)
+- **覆盖率目标**: 核心业务逻辑 > 80%
+- **测试类型**: 单元测试、集成测试、E2E测试
+- **现有API兼容性**: 确保测试不破坏现有API契约
+- **数据库集成**: 使用测试数据库,避免污染生产数据
+
+### 现有代码分析
+**基于故事006.001的实现**:
+1. **GoodsManagement.tsx** (835行)
+   - 包含spuId/spuName字段表单控件
+   - 包含GoodsChildSelector组件
+   - 包含BatchSpecCreator弹窗
+   - 问题:父子商品管理功能分散
+
+2. **GoodsChildSelector.tsx** (214行)
+   - 子商品选择器组件
+   - 支持搜索、选择、租户过滤
+   - 问题:与批量创建功能分离
+
+3. **BatchSpecCreator.tsx** (424行)
+   - 批量创建子商品组件
+   - 支持多规格创建
+   - 问题:独立弹窗,与商品编辑流程分离
+
+### 组件设计
+**GoodsParentChildPanel.tsx** (支持创建和编辑模式):
+```tsx
+interface GoodsParentChildPanelProps {
+  // 基础属性
+  mode: 'create' | 'edit';           // 创建模式或编辑模式
+  goodsId?: number;                  // 当前商品ID(编辑模式)
+  goodsName?: string;                // 当前商品名称
+
+  // 父子商品数据(双向绑定)
+  spuId?: number;                    // 父商品ID
+  spuName?: string;                  // 父商品名称
+  childGoodsIds?: number[];          // 子商品ID列表
+  batchSpecs?: BatchSpecTemplate[];  // 批量创建规格模板(创建模式)
+
+  // 回调函数
+  onDataChange?: (data: ParentChildData) => void;  // 数据变化回调
+  onUpdate?: () => void;              // 更新回调(编辑模式)
+
+  // 其他
+  tenantId?: number;                  // 租户ID
+  disabled?: boolean;                 // 是否禁用
+}
+
+interface ParentChildData {
+  spuId: number;
+  spuName: string | null;
+  childGoodsIds: number[];
+  batchSpecs?: BatchSpecTemplate[];
+}
+
+interface BatchSpecTemplate {
+  name: string;
+  price: number;
+  costPrice: number;
+  stock: number;
+  sort: number;
+}
+
+enum PanelMode {
+  VIEW = 'view',           // 查看模式
+  BATCH_CREATE = 'batch',  // 批量创建模式
+  MANAGE_CHILDREN = 'manage' // 管理子商品模式
+}
+```
+
+**GoodsRelationshipTree.tsx**:
+- 树状结构展示父子关系
+- 支持展开/收起子商品
+- 点击子商品跳转到编辑页面
+
+**ChildGoodsList.tsx**:
+- 子商品列表(分页)
+- 编辑/删除子商品操作
+- 解除父子关系功能
+
+**BatchSpecCreatorInline.tsx**:
+- 内联版本的批量创建组件
+- 实时预览创建的子商品
+- 创建后自动刷新关系树
+
+### API设计
+**在现有`adminGoodsRoutesMt`中聚合父子商品管理API**:
+
+**实现方案**:
+1. **创建`admin-goods-parent-child.mt.ts`**: 基于`public-goods-random.mt.ts`模式创建自定义路由
+2. **更新`admin-goods-routes.mt.ts`**: 聚合基础CRUD路由和父子商品管理路由
+3. **保持`adminGoodsRoutesMt`名称不变**: 前端代码无需修改
+
+**API端点** (聚合到现有`adminGoodsRoutesMt`):
+1. `GET /api/v1/goods/:id/children`
+   - 获取指定父商品的子商品列表
+   - 支持分页、搜索、多租户过滤
+
+2. `POST /api/v1/goods/:id/set-as-parent`
+   - 将普通商品设为父商品
+   - 验证:商品存在、非子商品、租户一致
+   - 操作:设置`spuId = 0`, `spuName = null`
+
+3. `DELETE /api/v1/goods/:id/parent`
+   - 解除子商品与父商品的关联
+   - 验证:商品存在且是子商品
+   - 操作:设置`spuId = 0`, `spuName = null`
+
+4. `POST /api/v1/goods/batch-create-children`
+   - 批量创建子商品(支持事务)
+   - 参数:`parentGoodsId`, `specs`数组
+   - 继承:子商品继承父商品的分类、供应商、商户等信息
+
+**前端使用** (无需修改):
+```typescript
+// 现有代码继续工作
+import { adminGoodsRoutesMt } from '@d8d/goods-module-mt';
+const goodsClient = hc<typeof adminGoodsRoutesMt>('/api/v1/goods');
+
+// 原有调用
+await goodsClient.index.$get({ query: { page: 1 } });
+
+// 新增调用
+await goodsClient[':id'].children.$get({ param: { id: 123 } });
+await goodsClient[':id'].setAsParent.$post({ param: { id: 123 } });
+await goodsClient[':id'].parent.$delete({ param: { id: 456 } });
+await goodsClient.batchCreateChildren.$post({ json: { ... } });
+```
+
+**优势**:
+- **零前端修改**: 保持`adminGoodsRoutesMt`名称和导入方式不变
+- **功能完整**: 单一客户端包含所有商品管理功能
+- **符合现有模式**: 基于`credit-balance-module-mt`聚合模式
+- **职责分离**: 父子商品管理逻辑独立,便于维护和测试
+
+### 集成方案
+**在GoodsManagement.tsx中的集成** (创建和编辑模式):
+```tsx
+// 在商品表单之后添加面板(创建和编辑都显示)
+<div className="mt-6 pt-6 border-t">
+  <GoodsParentChildPanel
+    mode={isCreateForm ? 'create' : 'edit'}
+    goodsId={isCreateForm ? undefined : editingGoods?.id}
+    goodsName={isCreateForm ? createForm.watch('name') : editingGoods?.name}
+    spuId={isCreateForm ? createForm.watch('spuId') : editingGoods?.spuId}
+    spuName={isCreateForm ? createForm.watch('spuName') : editingGoods?.spuName}
+    childGoodsIds={isCreateForm ? createForm.watch('childGoodsIds') : editingGoods?.childGoods?.map(c => c.id) || []}
+    onDataChange={(data) => {
+      // 实时同步数据到表单
+      if (isCreateForm) {
+        createForm.setValue('spuId', data.spuId);
+        createForm.setValue('spuName', data.spuName);
+        createForm.setValue('childGoodsIds', data.childGoodsIds);
+        // 保存批量创建模板
+        setBatchSpecs(data.batchSpecs || []);
+      }
+    }}
+    onUpdate={refetch}
+  />
+</div>
+```
+
+**提交逻辑调整**:
+```tsx
+const handleSubmit = (data: CreateRequest | UpdateRequest) => {
+  // 合并表单数据和面板数据
+  const submitData = {
+    ...data,
+    spuId: parentChildData?.spuId || 0,
+    spuName: parentChildData?.spuName || null,
+    childGoodsIds: parentChildData?.childGoodsIds || [],
+  };
+
+  if (isCreateForm) {
+    // 创建模式:可能需要批量创建子商品
+    createMutation.mutate(submitData, {
+      onSuccess: (result) => {
+        // 如果创建成功且有批量创建模板,创建子商品
+        if (batchSpecs.length > 0 && result.id) {
+          batchCreateChildren(result.id, batchSpecs);
+        }
+      }
+    });
+  } else if (editingGoods) {
+    updateMutation.mutate({ id: editingGoods.id, data: submitData as UpdateRequest });
+  }
+};
+```
+
+**移除原有功能**:
+- 移除编辑表单中的spuId/spuName字段
+- 移除编辑表单中的GoodsChildSelector组件
+- 移除商品列表中的批量创建按钮
+- 将功能全部整合到面板中
+
+### 技术约束
+- **多租户支持**: 所有操作必须包含tenantId过滤
+- **数据一致性**: 父子商品必须在同一租户下
+- **向后兼容**: 保持现有spuId/spuName字段的兼容性
+- **性能考虑**: 子商品列表查询使用分页,避免性能问题
+
+### 测试要求
+- **单元测试**: 测试面板组件、关系树组件、子商品列表组件
+- **集成测试**: 测试完整的父子商品管理流程
+- **兼容性测试**: 确保与现有功能兼容
+- **覆盖率**: 核心业务逻辑必须达到80%以上单元测试覆盖率
+
+## Testing
+### 测试标准 [Source: architecture/testing-strategy.md]
+- **测试文件位置**: `packages/goods-management-ui-mt/tests/` 目录下
+- **单元测试位置**: `tests/unit/**/*.test.{ts,tsx}`
+- **集成测试位置**: `tests/integration/**/*.test.{ts,tsx}`
+- **测试框架**: Vitest + Testing Library + hono/testing + shared-test-util
+- **覆盖率要求**: 单元测试 ≥ 80%,集成测试 ≥ 60%
+- **测试模式**: 使用测试数据工厂模式,避免硬编码测试数据
+- **数据库测试**: 使用专用测试数据库,事务回滚机制
+
+### 测试策略要求
+- **单元测试**: 验证面板组件渲染、模式切换、关系树展示
+- **集成测试**: 验证完整的父子商品管理流程、API调用、状态同步
+- **兼容性测试**: 验证与现有spuId/spuName字段的兼容性
+- **错误处理测试**: 测试各种错误场景和异常情况
+- **UI交互测试**: 测试用户交互、状态管理、数据更新
+
+## Change Log
+| Date | Version | Description | Author |
+|------|---------|-------------|--------|
+| 2025-12-09 | 1.0 | 初始故事创建 | John (Product Manager) |
+
+## Status
+⏳ Pending
+
+### 完成状态
+- [ ] 所有功能实现完成
+- [ ] 所有单元测试通过
+- [ ] 所有集成测试通过
+- [ ] 代码已提交并推送到远程仓库
+- [ ] 故事验收标准全部满足
+
+## QA Results
+*此部分由QA代理在审查完成后填写*