tasks.md 12 KB


description: "Task list for 商品规格(SKU 规格)管理 feature implementation"

Tasks: 商品规格(SKU 规格)管理

Input: Design documents from /specs/013-food-spec/

Prerequisites: plan.md, spec.md, research.md, data-model.md, contracts/api.md, quickstart.md

本期实现状态(2026-07-15)

已完成(后端,mvn compile 通过): T001(DDL)、T002-T011(实体/Mapper/Service/XML)、T012-T013(FoodSpecController)、T018-T020(PosFoodController setposfood/add/edit 收口)、T023-T027(列表/详情注入规格)、T032(编译)。

本期暂缓(用户决定 2026-07-15):

  • 前端 foodie-store:T014-T017(规格管理页/API/路由/i18n)、T021-T022(商品编辑规格区)、T028(列表展示)——后续单独安排
  • US4 价格口径:T029-T031(订单 otherPrice / 促销 specPrice 与规格加价统一)——留作后续

待开发者执行: T033——先执行 updatesql/sql.md 建表,再按 quickstart.md 跑场景。

Tests: 不包含自动化测试任务(项目无测试框架,spec 未要求 TDD);验证通过 quickstart.md 手动场景完成。

Organization: 按用户故事分组,便于独立实现与验证。US1/US2/US3 为 P1,US4 为 P2。

Format: [ID] [P?] [Story] Description

  • [P]: 可并行(不同文件、无依赖)
  • [Story]: 所属用户故事(US1/US2/US3/US4)
  • 描述含确切文件路径

Path Conventions

  • 后端实体/mapper/service:ruoyi-system/src/main/java/com/ruoyi/system/...,XML 在 ruoyi-system/src/main/resources/mapper/system/
  • 后端 controller:ruoyi-admin/src/main/java/com/ruoyi/app/mendian/...(与 PosFoodController 同包)
  • 前端商家端:E:\QtwCode\foodie\foodie-store\src\...
  • SQL:updatesql/sql.md

Phase 1: Setup (Shared Infrastructure)

Purpose: 数据库结构准备

  • T001 在 updatesql/sql.md 追加三张规格表 DDL(food_specsfood_specs_valuefood_spec_relation,字段/类型见 data-model.md,规格加价 price 用 decimal 与 pos_food.price 同口径)并确认 pos_food.food_sku 列存在;标注日期 2026-07-15 与用途注释

Phase 2: Foundational (Blocking Prerequisites)

Purpose: 规格体系基础数据层(实体/Mapper/Service),所有用户故事共用

⚠️ CRITICAL: 本阶段完成前不得开始任何用户故事

  • T002 [P] 新建实体 FoodSpecsruoyi-system/src/main/java/com/ruoyi/system/domain/FoodSpecs.java):@TableName("food_specs"),字段 id/title/type/state/language/remark/mdId/sort/isOpen/isDelete,transient foodSpecsItems: List<FoodSpecsValue>
  • T003 [P] 新建实体 FoodSpecsValueruoyi-system/src/main/java/com/ruoyi/system/domain/FoodSpecsValue.java):@TableName("food_specs_value"),字段 id/parentId/name/price(BigDecimal)/note/state/isOpen
  • T004 [P] 新建实体 FoodSpecRelationruoyi-system/src/main/java/com/ruoyi/system/domain/FoodSpecRelation.java):@TableName("food_spec_relation"),字段 id/foodId/specsId
  • T005 [P] 扩展 PosFoodruoyi-system/src/main/java/com/ruoyi/system/domain/PosFood.java):新增 transient foodSpecs: List<FoodSpecs>@TableField(exist=false)),确认既有 transient sku: JSONArray 可用
  • T006 [P] 新建 FoodSpecsMapperruoyi-system/.../mapper/FoodSpecsMapper.javaextends BaseMapper<FoodSpecs>)+ XML(ruoyi-system/src/main/resources/mapper/system/FoodSpecsMapper.xml,含 resultMap 与标准 CRUD)
  • T007 [P] 新建 FoodSpecsValueMapper + XML(同上目录结构,extends BaseMapper<FoodSpecsValue>
  • T008 [P] 新建 FoodSpecRelationMapper + XML(同上,extends BaseMapper<FoodSpecRelation>
  • T009 [P] 新建 IFoodSpecsServiceextends IService<FoodSpecs>)+ FoodSpecsServiceImplruoyi-system/.../service/service/impl/
  • T010 [P] 新建 IFoodSpecsValueService + FoodSpecsValueServiceImpl(同上模式)
  • T011 [P] 新建 IFoodSpecRelationService + FoodSpecRelationServiceImpl(同上模式)

Checkpoint: 规格三实体/Mapper/Service 就绪,可开始用户故事


Phase 3: User Story 1 - 商家管理门店规格模板 (Priority: P1) 🎯 MVP

Goal: 商家在商家端对本门店规格组(含级联规格值)做增删改查、启停、软删

Independent Test: 商家新建"甜度"(单选/必选)+3 个规格值,保存后在列表可见、可编辑、可停用、可软删;跨门店不可见

Implementation for User Story 1

  • T012 [US1] 新建 FoodSpecControllerruoyi-admin/src/main/java/com/ruoyi/app/mendian/FoodSpecController.java,基路径 /chanting/foodSpec@Anonymous @Auth):实现 foodSpecPageList/getSpecs/deleteFoodSpec(软删 isDelete=1)/getAvailableSpecsList(isOpen=1 & isDelete=0,按 mdId 隔离)/changeOpen/changeSpecValueOpen
  • T013 [US1] 在 FoodSpecController 实现 saveFoodSpec(@RequestBody List<FoodSpecs>):规格组 id≤0 新增否则更新,级联 saveOrUpdate 其下 foodSpecsItems(规格值),事务保证一致(依赖 T009/T010)
  • T014 [P] [US1] 前端 API 封装 foodie-store/src/api/specs.js(foodSpecPageList/saveFoodSpec/getSpecs/deleteFoodSpec/getAvailableSpecsList/changeOpen/changeSpecValueOpen)
  • T015 [US1] 前端规格管理页 foodie-store/src/views/FoodSpec.vue(或遵循 store 现有命名):分页列表(按门店切换)+ 新增/编辑弹窗(嵌套规格值子表增删改 name/price/note/isOpen)+ 启停开关 + 软删
  • T016 [US1] 前端路由/菜单接入规格管理页(按 foodie-store 现有路由约定)
  • T017 [P] [US1] 前端 i18n:在 foodie-store/src/lang/ 的 zh.js/tw.js/en.js/vi.js 同一对象层级追加规格相关 key(有意义驼峰命名,四文件 key 一致)

Checkpoint: US1 独立可用——规格模板完整管理闭环


Phase 4: User Story 2 - 商品使用规格 (Priority: P1)

Goal: 商家编辑商品时可从本门店可用规格多选规格组挂到商品;保存建立/更新关联

Independent Test: 商家编辑"珍珠奶茶"勾选"甜度""加料",保存后详情返回这两个规格;重新勾选后关联正确更新

Implementation for User Story 2

  • T018 [US2] 在 PosFoodControllerruoyi-admin/src/main/java/com/ruoyi/app/mendian/PosFoodController.java)抽取私有方法 handleFoodSpec(PosFood):删除该 foodId 旧关联 → 按 foodSpecs[*].id 批量插 food_spec_relationsku.toString() 写入 food_sku(依赖 T011)
  • T019 [US2] setposfood 保存商品后调用 handleFoodSpec(依赖 T018)
  • T020 [US2] 后台 add/edit 也调用 handleFoodSpec,统一收口(FR-011,修复当前后台通道不写规格)
  • T021 [P] [US2] 前端 foodie-store/src/api/food.js 的 setposfood 提交体增加 foodSpecssku
  • T022 [US2] 前端商品编辑页规格选择区:el-select multiplegetAvailableSpecsList 结果,handleSpecChange 同时构造 form.foodSpecs(完整规格对象,写关联) 与 form.sku(精简 JSON,写 food_sku),编辑回显由详情 foodSpecs 抽 id(依赖 T014/T021)

Checkpoint: US1+US2 可用——规格可挂到商品并持久化


Phase 5: User Story 3 - 商品列表与详情返回规格 (Priority: P1)

Goal: 商品列表(分类/门店/搜索)与详情接口返回该商品规格结构(仅启用项),供前端渲染与下单

Independent Test: 挂规格的商品在 getfood/getidlist/stallFoodList/foodSearch 返回完整规格与加价;无规格商品返回空规格

Implementation for User Story 3

  • T023 [US3] 在 PosFoodController 抽取批量规格注入工具:按 foodId 集合一次查 food_spec_relation → 一次查相关 food_specs(isDelete=0,isOpen=1) → 一次查相关 food_specs_value(isOpen=1) → 内存分组,产出每商品的 foodSpecs+foodSku(命名统一为 foodSpecsItems,避免 N+1)
  • T024 [US3] getfood(详情) 调用注入工具填 foodSpecs/foodSku(依赖 T023)
  • T025 [US3] getidlist 批量注入规格(依赖 T023)
  • T026 [US3] stallFoodList 批量注入规格(依赖 T023)
  • T027 [US3] foodSearch 注入规格(依赖 T023)
  • T028 [US3] 前端商品列表/详情规格展示(遍历 foodSpecs 与 foodSpecsItems 显示名称/备注/加价),在 foodie-store/src/views/ 相关商品组件实现

Checkpoint: US1+US2+US3 构成核心闭环(管理→挂载→展示)——可交付 MVP


Phase 6: User Story 4 - 规格与订单/促销价格口径统一 (Priority: P2)

Goal: 选规格下单时订单快照记录规格及加价,促销算价计入加价,三者口径一致

Independent Test: 顾客选加价规格下单,订单 otherPrice = 所选规格值加价之和,单价 = 商品价 + 加价;促销 specPrice 一致

Implementation for User Story 4

  • T029 [US4] 确认/补全下单链路:订单商品快照写入所选规格及加价,otherPrice = 所选规格值加价之和(ruoyi-admin/.../app/order/PosOrderController.javaOrderDTO/OrderCreatItem,先勘察现有 otherPrice 写入点)
  • T030 [US4] 确认促销算价 specPrice 口径 = 所选规格值加价之和(ruoyi-system/.../service/impl/PromotionCalcServiceImpl.java,先勘察现有 specPrice 叠加点)
  • T031 [US4] 验证 otherPrice / specPrice / 规格加价三者一致(按 quickstart 场景 4)

Checkpoint: 全链路价格一致


Phase 7: Polish & Cross-Cutting Concerns

Purpose: 编译、验证、收尾

  • T032 [P] 编译验证:用 JDK21(graalvm-jdk-21.0.7)执行 mvn -pl ruoyi-system,ruoyi-admin -am compile 通过
  • T033 按 specs/013-food-spec/quickstart.md 跑 5 个场景手动验证(规格管理/商品挂规格/列表返回/计价一致/兼容性)
  • T034 [P] 文档收尾:更新 spec 状态、在本会话 memory 记录 013-food-spec 要点

Dependencies & Execution Order

Phase Dependencies

  • Setup (Phase 1): 无依赖,立即开始(DDL 供开发者手动执行,不阻塞编码,但编码前最好先建表)
  • Foundational (Phase 2): 依赖 Setup;阻塞所有用户故事
  • US1 (Phase 3): 依赖 Foundational
  • US2 (Phase 4): 依赖 Foundational;前端选规格依赖 US1 的 getAvailableSpecsList(T014)
  • US3 (Phase 5): 依赖 Foundational;后端注入逻辑依赖 US2 已能写关联(否则无数据可返回,但代码可先行)
  • US4 (Phase 6): 依赖 US2+US3(要先能挂规格、返回规格)
  • Polish (Phase 7): 依赖所有目标 story 完成

Within Each User Story

  • 实体/Mapper/Service 先于 Controller
  • 后端先于前端
  • 核心实现先于集成展示

Parallel Opportunities

  • Foundational 的实体(T002-T005)、Mapper(T006-T008)、Service(T009-T011) 各组内可并行(不同文件)
  • US1 的前端 API(T014) 与 i18n(T017) 可与页面(T015) 部分并行
  • US3 的多个列表接口注入(T025-T027) 依赖同一工具(T023),T023 完成后可并行改造

Parallel Example: Foundational

# 实体可并行创建(不同文件):
Task: "FoodSpecs in domain/FoodSpecs.java"
Task: "FoodSpecsValue in domain/FoodSpecsValue.java"
Task: "FoodSpecRelation in domain/FoodSpecRelation.java"
# Mapper 与 Service 依赖对应实体,实体就绪后各组并行

Implementation Strategy

MVP First(核心闭环 = US1+US2+US3)

  1. 完成 Phase 1 Setup(DDL)
  2. 完成 Phase 2 Foundational(阻塞关键路径
  3. 完成 US1 → 独立验证规格管理
  4. 完成 US2 → 验证商品挂规格
  5. 完成 US3 → 验证列表/详情返回规格
  6. STOP and VALIDATE:US1+US2+US3 构成可交付 MVP

Incremental Delivery

  • Foundational → US1(规格管理可用)→ +US2(商品可挂规格)→ +US3(规格可展示/下单可见)= MVP
  • +US4(价格口径增强,P2)

Notes

  • [P] = 不同文件、无依赖,可并行
  • [Story] 标签用于用户故事阶段任务追踪
  • 价格一律与 pos_food.price 同口径(decimal/BigDecimal),不照搬源项目 Long(分)
  • 前端文件 CRLF,编辑用 Python 脚本替换;i18n 四语言 key 一致
  • 后台 add/edit 收口(FR-011)与 setposfood 共用 handleFoodSpec
  • 规格名称是商家录入的动态多语言数据(按 language 字段),不做成 i18n key
  • 提交策略:按用户故事或逻辑分组提交(用户未要求建分支,直接在 test 分支)