进度: 19/22 故事完成 (86.4%) 最近更新: 2025-12-16 (故事21-22完成:小程序首页多规格商品bug修复及集成测试) 当前状态: 故事1-15、17、20、21、22已完成,故事18-19待开始,故事16已拆分
新增父子商品多规格支持功能,在商品添加购物车或立即购买时,能同时支持单规格和多规格选择,以子商品作为多规格选项,并支持手动指定子商品。
GoodsParentChildPanel.tsx)ChildGoodsList.tsx)和批量创建(BatchSpecCreatorInline.tsx)组件GoodsSpecSelector组件但被注释,购物车支持spec字段但无规格选择逻辑publicGoodsRoutesMt(公共商品路由)adminGoodsRoutesMt(已聚合父子商品管理API)name字段作为规格名称id、name、price、stockid、name、price、stockname字段已经包含完整的规格信息,spec字段可能暂时不需要/api/v1/goods):默认只返回父商品(spuId=0)/api/v1/goods/:id):
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-aggregated.mt.ts聚合基础CRUD和父子商品管理路由,保持adminGoodsRoutesMt名称不变,前端代码无需修改spuId查询参数过滤,管理员可通过spuId=0只查看父商品故事1:管理后台父子商品配置功能 ✅ 已完成 (2025-12-07)
故事2:父子商品管理UI体验优化 ✅ 已完成 (2025-12-10)
adminGoodsRoutesMt中聚合父子商品管理API(获取子商品列表、设为父商品、解除关系、批量创建)GoodsParentChildPanel.tsx组件已创建并支持创建/编辑模式ChildGoodsList.tsx和BatchSpecCreatorInline.tsx组件已创建并集成到面板中GoodsManagement.tsx已集成新面板到创建和编辑表单admin-goods-aggregated.mt.ts聚合基础CRUD和父子商品管理路由,保持adminGoodsRoutesMt名称不变onDataChange回调实现面板与表单数据的实时同步故事3:子商品行内编辑功能 ✅ 已完成 (2025-12-11)
ChildGoodsList.tsx组件中添加行内编辑模式ChildGoodsList组件,支持editingChildId状态管理ChildGoodsList组件,添加了行内编辑功能ChildGoodsInlineEditForm组件,支持所有必需字段的编辑handleEdit函数逻辑:行内编辑现在优先于onEditChild回调enableInlineEdit配置选项,支持灵活控制行内编辑行为packages/goods-management-ui-mt/src/components/ChildGoodsInlineEditForm.tsx - 行内编辑表单组件packages/goods-management-ui-mt/tests/unit/ChildGoodsInlineEditForm.test.tsx - 行内编辑表单测试packages/goods-management-ui-mt/src/components/ChildGoodsList.tsx - 扩展行内编辑功能packages/goods-management-ui-mt/tests/unit/ChildGoodsList.test.tsx - 更新测试,添加行内编辑功能测试docs/stories/006.003.child-goods-inline-edit.story.md - 更新任务状态和开发记录故事4:商品API父子商品支持优化 ✅ 已完成 (2025-12-12)
spuId=0过滤只显示父商品@Index(['tenantId', 'spuId'])优化查询性能故事5:父子商品多规格选择组件开发 ✅ 已实现 (2025-12-12)
GoodsSpecSelector组件public-goods-aggregated.mt.ts聚合路由,确保子商品API正确暴露mini/tests/components/goods-spec-selector.test.tsx,8个测试通过故事6:商品详情页规格选择集成 ✅ 已完成
mini/src/pages/goods-detail/index.tsx - 移除过时注释,更新库存限制逻辑以支持规格库存mini/tests/unit/components/goods-spec-selector/goods-spec-selector.test.tsx - 修复测试期望和关闭按钮选择器mini/tests/unit/components/taro/Button.test.tsx - 移动Taro原生Button测试到标准位置mini/tests/unit/pages/goods-detail/goods-detail.test.tsx - 商品详情页集成测试(参照OrderButtonBar.test.tsx模式重写)mini/tests/e2e/goods-detail-spec.e2e.test.ts - E2E测试占位文件mini/tests/pages/goods-detail.test.tsx → mini/tests/unit/pages/goods-detail/goods-detail.test.tsxmini/tests/components/goods-spec-selector.test.tsx → mini/tests/unit/components/goods-spec-selector/goods-spec-selector.test.tsxmini/tests/components/Button.test.tsx → mini/tests/unit/components/taro/Button.test.tsx故事7:购物车和订单规格支持 ✅ 已完成 (2025-12-13)
addToCart逻辑,支持添加子商品(使用子商品信息填充CartItem)name字段显示完整规格信息CartContext.tsx) 已更新注释,明确支持子商品ID,购物车逻辑天然支持父子商品CreateOrderRequestDto) 已支持子商品ID,OrderGoodsMt实体正确存储子商品IDname字段(包含规格信息)实现完整规格显示CartContext.test.tsx),5个测试全部通过mini/src/contexts/CartContext.tsx - 更新接口注释和函数说明mini/tests/unit/contexts/CartContext.test.tsx - 修复测试中的useEffect依赖循环问题docs/stories/006.007.story.md - 更新任务状态和开发记录mini/tests/unit/contexts/CartContext.test.tsx - 购物车规格支持测试文件故事8:购物车页面规格切换功能 ✅ 已完成 (2025-12-13)
GoodsSpecSelector组件)CartContext或购物车组件,支持规格切换逻辑GoodsSpecSelector组件mini/src/contexts/CartContext.tsx - 扩展CartContext,添加switchSpec函数,更新CartItem接口,修复数据迁移逻辑(parentGoodsId默认值从item.id改为0)mini/src/pages/cart/index.tsx - 集成GoodsSpecSelector组件,添加规格切换功能,清理多余的调试信息mini/tests/unit/contexts/CartContext.test.tsx - 添加switchSpec函数单元测试mini/tests/unit/pages/cart/index.test.tsx - 添加购物车页面规格切换组件测试,修复测试结构使用真实CartContext,解决空购物车状态测试问题,修复库存不足提示测试,添加7个完整的规格切换集成测试mini/tests/__mocks__/taroMock.ts - 扩展Taro API mock,添加request方法支持mini/src/components/goods-spec-selector/index.tsx - 改进错误处理,解析API响应体获取具体错误消息mini/src/pages/goods-detail/index.tsx - 修复parentGoodsId计算逻辑,正确处理父子商品关系mini/tests/unit/pages/goods-detail/goods-detail.test.tsx - 更新测试期望,添加parentGoodsId字段验证docs/stories/006.008.cart-spec-switching.story.md - 更新任务状态和开发记录故事9:父子商品名称关联查询优化(为购物车显示做准备) ✅ 已完成
spuName字段冗余存储父商品名称,但存在数据一致性问题:当父商品名称更新时,不会自动同步更新子商品的spuName字段。这导致购物车等场景显示的商品名称可能不一致。故事9的目标是为故事10提供基础支持,建立可靠的父子商品名称关联查询机制。parent对象关联查询获取父商品信息,为购物车提供准确、实时的父商品名称,解决spuName字段的数据一致性问题。parent对象包含完整的父商品基本信息(至少包含id、name字段)parent字段的类型从z.any()改为具体的父商品Schema,确保类型安全goods.parent?.name获取父商品名称,用于故事10的商品名称显示优化spuName字段,前端使用parent.name获取父商品名称GoodsServiceMt.getById方法,确保parent对象包含必要字段;更新商品Schema类型定义,并从商品Schema中移除spuName字段goods.parent?.name获取父商品名称,不再依赖spuName字段,无需专门的工具函数parent对象信息parent对象包含完整的父商品基本信息(id、name等)goods.parent?.name获取父商品名称(为故事10做准备)spuName字段,前端代码直接使用parent.name获取父商品名称packages/goods-module-mt/src/schemas/parent-goods.schema.mt.ts - 父商品精简Schema定义packages/goods-module-mt/src/schemas/public-goods.schema.mt.ts - 更新parent和children字段类型,移除spuNamepackages/goods-module-mt/src/schemas/admin-goods.schema.mt.ts - 更新parent和children字段类型,移除spuNamepackages/goods-module-mt/src/schemas/user-goods.schema.mt.ts - 移除spuName字段packages/goods-module-mt/src/schemas/goods.schema.mt.ts - 更新UpdateGoodsDto,移除spuName字段packages/goods-module-mt/src/schemas/index.mt.ts - 导出ParentGoodsSchemapackages/goods-module-mt/src/services/goods.service.mt.ts - 完善getById方法,添加租户过滤和完整字段选择packages/goods-module-mt/tests/integration/admin-goods-parent-child.integration.test.ts - 更新测试验证parent对象packages/goods-module-mt/tests/integration/admin-goods-routes.integration.test.ts - 更新测试packages/goods-module-mt/tests/integration/public-goods-children.integration.test.ts - 更新测试验证spuName移除packages/goods-module-mt/tests/integration/public-goods-parent-filter.integration.test.ts - 更新测试验证parent对象完整性mini/src/pages/cart/index.tsx - 购物车页面,验证数据基础可用性packages/goods-module-mt/src/entities/goods.entity.mt.ts - 验证spuName字段保留在实体中故事10:购物车商品名称显示优化 ✅ 已完成
mini/src/pages/cart/index.tsx:253)使用goodsName = latestGoods?.name || item.name显示商品名称,对于子商品只显示规格名称,而没有显示父商品名称。购物车页面已经将商品名称和规格名称分开显示(goods-title显示商品名称,specs-text显示规格名称),但子商品的商品名称显示的是规格名称,而不是父商品名称,导致商品信息显示不完整。parent对象获取父商品名称,商品名称显示父商品名称,规格名称显示子商品规格名称,提供清晰完整的商品信息。parentGoodsId === 0),保持现有显示方式不变,直接显示商品名称mini/src/pages/order-submit/index.tsx:277)等所有显示商品名称的地方都遵循同样的显示逻辑mini/src/pages/cart/index.tsx)的商品名称显示逻辑,在goodsName计算时判断是否为子商品(通过parentGoodsId !== 0或spuId > 0)parent.name获取父商品名称(通过故事9实现的关联查询),不再使用spuName字段latestGoods?.name || '选择规格'显示子商品规格名称(子商品的name字段就是规格名称)mini/src/pages/order-submit/index.tsx)的商品名称显示逻辑,遵循同样的显示原则parent.name获取父商品名称,不再依赖spuName字段,统一处理父子商品名称获取逻辑parent对象CartItem接口中的spec字段,避免数据冗余(子商品的name字段已经包含规格信息)mini/src/pages/cart/index.tsx - 修改商品名称显示逻辑(第253行goodsName计算),移除对item.spec的依赖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函数mini/tests/unit/pages/cart/index.test.tsx - 修复购物车页面测试,移除规格选择器mock,使用真实GoodsSpecSelector组件故事11:子商品删除功能实现 ✅ 已完成
ChildGoodsList组件)提供了删除按钮,但该按钮没有实际作用。点击删除按钮时,handleDelete函数仅检查onDeleteChild回调是否存在,而父组件GoodsParentChildPanel并未传递此回调,导致删除操作无效。管理员无法在管理界面中直接删除子商品规格。GoodsParentChildPanel组件中为ChildGoodsList组件传递onDeleteChild回调函数GoodsParentChildPanel组件中添加onDeleteChild回调函数,处理子商品删除逻辑DELETE /api/v1/goods/:id)删除子商品实体,或使用解除父子关系API(DELETE /api/v1/goods/:id/parent)仅解除关系但保留商品(根据业务需求选择)refetch刷新子商品列表数据packages/goods-management-ui-mt/src/components/GoodsParentChildPanel.tsx - 添加onDeleteChild回调函数和删除确认对话框packages/goods-management-ui-mt/src/components/ChildGoodsList.tsx - 可能需优化删除按钮的视觉反馈故事12:商品详情页规格选择流程优化 ✅ 已完成
mini/src/pages/goods-detail/index.tsx中的handleAddToCart和handleBuyNow函数,添加规格选择判断逻辑showSpecModal状态与操作流程关联GoodsSpecSelector组件的onConfirm回调,支持直接执行购物车添加或购买操作mini/src/pages/goods-detail/index.tsx - 主要修改:添加pendingAction状态,重构handleAddToCart和handleBuyNow函数添加自动弹窗逻辑,移除独立"选择规格"按钮,优化规格信息显示和价格显示,修复按钮禁用逻辑mini/src/components/goods-spec-selector/index.tsx - 扩展组件:添加actionType prop,扩展onConfirm回调签名,添加getConfirmButtonText函数mini/tests/unit/pages/goods-detail/goods-detail.test.tsx - 更新集成测试:修改"打开规格选择弹窗"测试使用新流程,修复多个测试以匹配新的按钮禁用逻辑和流程docs/stories/006.012.goods-detail-spec-optimization.story.md - 更新故事状态和任务完成记录故事13:父子商品列表缓存自动刷新优化 ✅ 已完成
GoodsParentChildPanel 组件中添加 useQueryClientbatchCreateChildrenMutation 的 onSuccess 回调,使用 queryClient.invalidateQueries 使相关查询失效['goods-children', goodsId, tenantId] 和 ['goods', 'children', 'list', parentGoodsId, tenantId]batchCreateChildrenMutation、setAsParentMutation、removeParentMutation和deleteChildMutation的onSuccess回调,添加queryClient.invalidateQueries调用useQueryClient使相关查询失效,保持所有mutation缓存刷新逻辑一致packages/goods-management-ui-mt/src/components/GoodsParentChildPanel.tsx - 已添加 useQueryClient,修改四个mutation的onSuccess回调添加缓存失效逻辑packages/goods-management-ui-mt/tests/unit/GoodsParentChildPanel.test.tsx - 已添加缓存刷新测试验证invalidateQueries调用故事14:订单提交快照商品名称优化 ✅ 已完成
goodsName)直接使用商品实体的name字段。对于子商品,这会导致快照中存储的是子商品的规格名称,而不是父商品名称。然而购物车中的显示逻辑已经优化:商品名称显示父商品名称,规格名称显示子商品规格名称。订单快照与购物车显示逻辑不一致,导致订单页面显示的商品名称不正确。createOrder方法中,当写入订单商品快照时,对于子商品(spuId > 0),将父商品名称和子商品名称拼接后存储在goodsName字段中(例如:"连衣裙 红色 大码")。这样既包含了商品名称又包含了规格信息,后续所有订单页面都不需要修改,直接使用快照数据,也无需修改数据库实体。packages/orders-module-mt/src/services/order.mt.service.ts中的createOrder方法spuId字段)spuId查询父商品实体,获取父商品名称goodsName字段(例如:goodsName =${parentGoods.name} ${goods.name}``)createOrder方法,添加父商品批量查询和商品名称拼接逻辑Set<number>收集父商品ID,通过In([...parentGoodsIds])批量查询避免N+1问题packages/orders-module-mt/src/services/order.mt.service.ts - 修改createOrder方法,添加父商品批量查询和商品名称拼接逻辑packages/orders-module-mt/tests/integration/user-orders-routes.integration.test.ts - 新增两个集成测试用例,验证子商品和单规格商品的订单快照商品名称docs/stories/006.014.order-submit-goods-name-optimization.story.md - 更新任务状态和开发记录故事15:商品管理列表父子商品筛选优化 ✅ 已完成
GoodsManagement组件,扩展searchParams状态包含filter字段filters: '{"spuId": 0}'参数到API调用(filter为'parent'时传递,filter为'all'时不传递)goods.parent?.name而非已废弃的spuName字段,遵循故事9的关联查询方案parent对象关联查询获取,确保数据一致性parent对象获取父商品名称packages/goods-management-ui-mt/src/components/GoodsManagement.tsx - 添加筛选器组件,修改查询逻辑,添加父子关系标识显示(使用parent.name而非spuName)packages/goods-management-ui-mt/tests/integration/goods-management.integration.test.tsx - 添加筛选器集成测试故事16:父子商品管理界面测试用例修复与API模拟规范化 ⏳ 待开始
@d8d/shared-ui-components/utils/hc中的rpcClient函数,而不是分别模拟各个客户端管理器docs/architecture/testing-strategy.md中的API模拟规范,创建统一的mockRpcClient函数vi.mock统一模拟@d8d/shared-ui-components/utils/hc模块beforeEach或具体测试中配置模拟响应,支持跨UI包集成测试场景console.debug等调试输出,保持测试环境整洁rpcClient模拟packages/goods-management-ui-mt/tests/unit/GoodsParentChildPanel.test.tsx - 统一API模拟,修复测试用例packages/goods-management-ui-mt/tests/unit/ChildGoodsList.test.tsx - 统一API模拟,修复测试用例packages/goods-management-ui-mt/tests/unit/BatchSpecCreatorInline.test.tsx - 统一API模拟,修复测试用例packages/goods-management-ui-mt/tests/unit/BatchSpecCreator.test.tsx - 统一API模拟,修复测试用例packages/goods-management-ui-mt/tests/integration/goods-management.integration.test.tsx - 统一API模拟,修复测试用例docs/architecture/testing-strategy.md#API模拟规范执行@d8d/shared-ui-components/utils/hc中的rpcClient函数故事17:小程序商品卡片多规格支持 ✅ 已完成
addToCart函数,没有处理多规格商品的情况。这与商品详情页已经实现的完整规格选择逻辑不一致。handleAddCart函数中添加规格选择判断逻辑hasSpecOptions判断),弹出规格选择器(GoodsSpecSelector组件)parentGoodsId字段mini/src/components/goods-card/index.tsx组件,参考商品详情页的handleAddToCart逻辑showSpecModal控制规格选择器显示,selectedSpec记录选择的规格GoodsSpecSelector组件,支持add-to-cart操作类型hasSpecOptions、parentGoodsId、goodsId等字段parentGoodsId字段正确设置mini/src/components/goods-card/index.tsx - 添加规格选择逻辑,集成GoodsSpecSelector组件mini/src/components/goods-list/index.tsx - 确保传递正确的商品数据mini/src/pages/index/index.tsx - 首页商品卡片数据传递mini/src/pages/goods-list/index.tsx - 商品列表页数据传递mini/src/pages/search-result/index.tsx - 搜索结果页数据传递mini/tests/unit/components/goods-card/goods-card.test.tsx - 商品卡片多规格支持单元测试故事18:父子商品管理面板剩余测试修复 ⏳ 待开始
packages/goods-management-ui-mt/tests/unit/GoodsParentChildPanel.test.tsx - 修复剩余测试失败故事19:批量创建组件测试修复与API模拟规范化 ⏳ 待开始
packages/goods-management-ui-mt/tests/unit/BatchSpecCreatorInline.test.tsx - 修复表单验证测试packages/goods-management-ui-mt/tests/unit/BatchSpecCreator.test.tsx - 更新API模拟规范故事20:商品管理集成测试API模拟规范化 ✅ 已完成
packages/goods-management-ui-mt/tests/integration/goods-management.integration.test.tsx - 更新API模拟规范故事21:小程序首页多规格商品加入购物车失败bug修复 ⏳ 待开始
spec.id.toString())parseInt(goods.id))mini/src/components/goods-card/index.tsx - 修复handleSpecConfirm函数mini/src/pages/index/index.tsx - 修复handleAddCart函数mini/tests/unit/components/goods-card/goods-card.test.tsx - 更新测试用例故事22:小程序首页多规格商品集成测试 ⏳ 待开始
mini/tests/unit/pages/index/index.test.tsx - 创建首页集成测试文件,添加多规格商品加入购物车集成测试spuId字段:0表示父商品或单规格商品,>0表示子商品spuName字段存储父商品名称(冗余字段,故事9中移除,改用关联查询)spuId=0条件CartItem使用子商品的id、name、price、stockCartItem使用父商品的id、name、price、stockname字段已经包含完整规格信息,spec字段可暂时忽略或设置为相同值spuName字段同步问题史诗创建时间:2025-12-06 创建人:John (Product Manager) 技术栈:TypeORM + Hono + React + Taro小程序 + 多租户架构 优先级:高(支持电商核心功能)