# Tasks: 促销 + 优惠券系统 **Input**: Design documents from `/specs/008-promotion-coupon/` **Prerequisites**: plan.md (required), spec.md (required for user stories) ## Format: `[ID] [P?] [Story] Description` - **[P]**: Can run in parallel (different files, no dependencies) - **[Story]**: Which user story this task belongs to (US1=促销活动, US2=优惠券) - Include exact file paths in descriptions --- ## Phase 1: Setup (数据库 + 基础设施) **Purpose**: 创建数据库表,为后续所有任务提供基础 - [x] T001 追加 6 张新表 DDL 到 `foodie_server/updatesql/sql.md`(promotion_activity, promotion_activity_rule, promotion_coupon_batch, promotion_coupon_rule, promotion_user_coupon, pos_order_promotion),DDL 来自 spec.md Data Model 章节 - [x] T002 手动执行 SQL 建表(提醒开发者操作) --- ## Phase 2: Foundational (后端实体 + 数据层) **Purpose**: 后端核心数据层,所有 Controller 和前端页面依赖此阶段完成 ### 实体类 (5个文件,全部可并行) - [x] T003 [P] 创建 PromotionActivity 实体 `ruoyi-system/src/main/java/com/ruoyi/system/domain/PromotionActivity.java` — 字段: id, storeId, type, name, status, startTime, endTime, createTime, updateTime;非持久化: List rules, boolean editable。使用 @Data @TableName @TableId(type=IdType.AUTO) @JsonFormat 注解,参考 SalesPromotion.java - [x] T004 [P] 创建 PromotionActivityRule 实体 `ruoyi-system/src/main/java/com/ruoyi/system/domain/PromotionActivityRule.java` — 字段: id, activityId, productId, threshold(BigDecimal), reduceAmount(BigDecimal), discountRate(BigDecimal), minQuantity(Integer);非持久化: productName, productImage, productPrice - [x] T005 [P] 创建 PromotionCouponBatch 实体 `ruoyi-system/src/main/java/com/ruoyi/system/domain/PromotionCouponBatch.java` — 字段: id, storeId, name, couponType, totalCount, remainCount, receivedCount, status, startTime, endTime, validDays, createTime, updateTime;非持久化: PromotionCouponRule rule, boolean editable - [x] T006 [P] 创建 PromotionCouponRule 实体 `ruoyi-system/src/main/java/com/ruoyi/system/domain/PromotionCouponRule.java` — 字段: id, batchId, productId, isMutex(Integer), threshold(BigDecimal), amount(BigDecimal), discountRate(BigDecimal);非持久化: productName, productImage, productPrice - [x] T007 [P] 创建 PromotionUserCoupon 实体 `ruoyi-system/src/main/java/com/ruoyi/system/domain/PromotionUserCoupon.java` — 字段: id, userId, batchId, storeId, status, orderId, receiveTime, useTime, expireTime - [x] T007a [P] 创建 PosOrderPromotion 实体 `ruoyi-system/src/main/java/com/ruoyi/system/domain/PosOrderPromotion.java` — 字段: id, orderId, promoType, promoSubType, promoId, userCouponId, promoName, promoDetail, reduceAmount, pathSummary, createTime ### Mapper 接口 (全部可并行) - [x] T008 [P] 创建 PromotionActivityMapper `ruoyi-system/src/main/java/com/ruoyi/system/mapper/PromotionActivityMapper.java` — extends BaseMapper - [x] T009 [P] 创建 PromotionActivityRuleMapper `ruoyi-system/src/main/java/com/ruoyi/system/mapper/PromotionActivityRuleMapper.java` — extends BaseMapper,额外方法 List selectRulesByActivityId(Long activityId) - [x] T010 [P] 创建 PromotionCouponBatchMapper `ruoyi-system/src/main/java/com/ruoyi/system/mapper/PromotionCouponBatchMapper.java` — extends BaseMapper - [x] T011 [P] 创建 PromotionCouponRuleMapper `ruoyi-system/src/main/java/com/ruoyi/system/mapper/PromotionCouponRuleMapper.java` — extends BaseMapper,额外方法 PromotionCouponRule selectRuleByBatchId(Long batchId) - [x] T012 [P] 创建 PromotionUserCouponMapper `ruoyi-system/src/main/java/com/ruoyi/system/mapper/PromotionUserCouponMapper.java` — extends BaseMapper - [x] T012a [P] 创建 PosOrderPromotionMapper `ruoyi-system/src/main/java/com/ruoyi/system/mapper/PosOrderPromotionMapper.java` — extends BaseMapper ### Mapper XML (全部可并行) - [x] T013 [P] 创建 PromotionActivityMapper.xml `ruoyi-system/src/main/resources/mapper/system/PromotionActivityMapper.xml` — resultMap 映射全部字段 - [x] T014 [P] 创建 PromotionActivityRuleMapper.xml `ruoyi-system/src/main/resources/mapper/system/PromotionActivityRuleMapper.xml` — resultMap + selectRulesByActivityId (LEFT JOIN pos_food 获取 productName/productImage/productPrice) - [x] T015 [P] 创建 PromotionCouponBatchMapper.xml `ruoyi-system/src/main/resources/mapper/system/PromotionCouponBatchMapper.xml` — resultMap 映射全部字段 - [x] T016 [P] 创建 PromotionCouponRuleMapper.xml `ruoyi-system/src/main/resources/mapper/system/PromotionCouponRuleMapper.xml` — resultMap + selectRuleByBatchId (LEFT JOIN pos_food) - [x] T017 [P] 创建 PromotionUserCouponMapper.xml `ruoyi-system/src/main/resources/mapper/system/PromotionUserCouponMapper.xml` — resultMap 映射全部字段 - [x] T017a [P] 创建 PosOrderPromotionMapper.xml `ruoyi-system/src/main/resources/mapper/system/PosOrderPromotionMapper.xml` — resultMap 映射全部字段 **Checkpoint**: 数据层完成,可进入 Service 和 Controller --- ## Phase 3: User Story 1 - 商家创建促销活动 (Priority: P1) 🎯 MVP **Goal**: 商家能创建满减/折扣/第二份半价/新客立减活动,查看活动列表,结束进行中的活动 **Independent Test**: 商家创建一个满减活动(满20减5/满40减12),列表显示进行中,能查看详情,能结束活动 ### Service 层 (US1) - [x] T018 [US1] 创建 IPromotionActivityService `ruoyi-system/src/main/java/com/ruoyi/system/service/IPromotionActivityService.java` — extends IService,方法: createActivity(activity, rules), selectActivityWithRules(id), endActivity(id) - [x] T019 [US1] 创建 PromotionActivityServiceImpl `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/PromotionActivityServiceImpl.java` — 实现 createActivity (@Transactional: 插入activity+批量插入rules, 根据 startTime 设置初始 status), selectActivityWithRules (查activity+查rules), endActivity (status→2) - [x] T020 [US1] 创建 IPromotionActivityRuleService + PromotionActivityRuleServiceImpl `ruoyi-system/src/main/java/com/ruoyi/system/service/IPromotionActivityRuleService.java` 和 `impl/PromotionActivityRuleServiceImpl.java` — selectRulesByActivityId 委托给 mapper ### Controller (US1) - [x] T021 [US1] 创建 ShPromotionActivityController `ruoyi-admin/src/main/java/com/ruoyi/app/mendian/ShPromotionActivityController.java` — @RestController @RequestMapping("/system/shPromotionActivity"),参考 ShSalesPromotionController。端点: GET /list (page,size,storeId,type?,status? → LambdaQueryWrapper 分页), GET /{id} (selectActivityWithRules), POST / (RequestBody含rules→createActivity), PUT /{id}/end (endActivity) ### 前端 API (US1) - [x] T022 [US1] 创建 promotionActivity.js `foodie-store/src/api/promotionActivity.js` — 导出 listPromotionActivity(query), getPromotionActivity(id), addPromotionActivity(data), endPromotionActivity(id),参考 src/api/promotion.js 模式 ### 前端页面 (US1) - [x] T023 [US1] 创建 PromotionActivity.vue `foodie-store/src/views/PromotionActivity.vue` — 促销活动管理页面: - **列表区域**: 面包屑 + 门店选择(复用xuanzhemd模式) + 状态筛选radio(全部/未开始/进行中/已结束) + el-table(ID/名称/类型el-tag/状态el-tag/时间/操作-结束按钮) + el-pagination - **创建对话框** el-dialog width=750px + el-tabs v-model=activeTab: - Tab1 满减(type=1): 活动名称 + 时间范围 + 动态档位行(v-for, 每行两个el-input-number:满X减Y) + 添加/删除档位按钮 - Tab2 折扣(type=2): 活动名称 + 时间范围 + 折扣组列表(v-for, 每组含折扣率+已选商品table+添加商品按钮) + 添加/删除折扣区按钮。**同一商品只能分配到一个折扣区,添加时自动从其他折扣区移除** - Tab3 第二份半价(type=3): 活动名称 + 时间范围 + 已选商品table + 选择商品按钮 - Tab4 新客立减(type=4): 活动名称 + 时间范围 + 减免金额el-input-number - **商品选择弹窗**: 分类el-select + 搜索el-input + 商品el-table + el-pagination (复用Quanyi.vue商品加载API模式) - **提交逻辑** tijiaobaocun(): 根据activeTab转换数据为 {storeId,type,name,startTime,endTime,rules:[...]},折扣组展开为扁平rules,调用addPromotionActivity - **互斥提示**: 创建对话框顶部展示互斥规则提示文案(FR-006):"满减、折扣、第二份半价三选一(系统自动选最优),新客立减可叠加" - **i18n**: 所有文字用 $t('promoActivity.xxx') **Checkpoint**: 促销活动完整功能可用——创建4种类型活动、查看列表、查看详情、结束活动 --- ## Phase 4: User Story 2 - 商家创建优惠券 (Priority: P2) **Goal**: 商家能创建满减券/商品券,设置同享/互斥属性和库存,查看列表,下架券 **Independent Test**: 商家创建"满30减5"满减券100张,列表显示,能查看详情,能下架 ### Service 层 (US2) - [x] T024 [P] [US2] 创建 IPromotionCouponBatchService `ruoyi-system/src/main/java/com/ruoyi/system/service/IPromotionCouponBatchService.java` — 方法: createBatch(batch, rule), selectBatchWithRule(id), offShelfBatch(id) - [x] T025 [P] [US2] 创建 PromotionCouponBatchServiceImpl `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/PromotionCouponBatchServiceImpl.java` — 实现 createBatch (@Transactional: remainCount=totalCount, 插入batch+rule), selectBatchWithRule (查batch+查rule), offShelfBatch (status→3) - [x] T026 [P] [US2] 创建 IPromotionCouponRuleService + PromotionCouponRuleServiceImpl `ruoyi-system/src/main/java/com/ruoyi/system/service/IPromotionCouponRuleService.java` 和 `impl/PromotionCouponRuleServiceImpl.java` — selectRuleByBatchId 委托给 mapper ### Controller (US2) - [x] T027 [US2] 创建 ShPromotionCouponController `ruoyi-admin/src/main/java/com/ruoyi/app/mendian/ShPromotionCouponController.java` — @RestController @RequestMapping("/system/shPromotionCoupon")。端点: GET /list (page,size,storeId,couponType?,status?), GET /{id} (selectBatchWithRule), POST / (RequestBody含rule→createBatch), PUT /{id}/offShelf ### 前端 API (US2) - [x] T028 [P] [US2] 创建 promotionCoupon.js `foodie-store/src/api/promotionCoupon.js` — 导出 listPromotionCoupon(query), getPromotionCoupon(id), addPromotionCoupon(data), offShelfPromotionCoupon(id) ### 前端页面 (US2) - [x] T029 [US2] 创建 CouponBatch.vue `foodie-store/src/views/CouponBatch.vue` — 优惠券管理页面: - **列表区域**: 面包屑 + 门店选择 + 状态筛选(全部/未开始/进行中/已结束/已下架) + el-table(ID/名称/类型/总库存/剩余/已领取/状态/时间/有效期/操作-下架按钮) + el-pagination - **创建对话框** el-dialog width=600px: - 券类型 el-radio-group (满减券/商品券) - 通用字段: 名称el-input, 门店el-select, 总量el-input-number, 有效天数el-input-number, 时间范围el-date-picker - 满减券(v-if couponType===1): 叠加属性el-radio(同享/互斥), 使用门槛el-input-number, 减免金额el-input-number - 商品券(v-if couponType===2): 选择商品按钮(复用商品弹窗), 折扣率el-input-number - **提交逻辑** tijiaobaocun(): 构建 {storeId,name,couponType,totalCount,validDays,startTime,endTime,rule:{isMutex,threshold,amount,...}},调用addPromotionCoupon - **i18n**: 所有文字用 $t('couponBatch.xxx') **Checkpoint**: 优惠券完整功能可用——创建满减券/商品券、查看列表、查看详情、下架券 --- ## Phase 5: Menu + Router + i18n (跨 US) **Purpose**: 前端菜单、路由、多语言——连接所有页面的基础设施 > **注意**: 前端文件使用 CRLF 换行,必须用 Python 脚本编辑,不能用 Edit 工具。 - [x] T030 在 `foodie-store/src/router/index.js` 的 /manage children 中添加路由 promotion-activity → PromotionActivity.vue 和 coupon-batch → CouponBatch.vue - [x] T031 在 `foodie-store/src/components/Aside.vue` 末尾(el-submenu index="6" 之后)添加新的 el-submenu index="7"「营销管理」,含两个 menu-item: 促销活动(/manage/promotion-activity) + 优惠券管理(/manage/coupon-batch) - [x] T032 [P] 在 `foodie-store/src/lang/zh.js` 末尾追加 promoMenu(营销管理/促销活动/优惠券管理)、promoActivity(~40个key覆盖页面全部文案)、couponBatch(~30个key)三个 i18n section - [x] T033 [P] 在 `foodie-store/src/lang/tw.js` 追加同结构繁体中文翻译 - [x] T034 [P] 在 `foodie-store/src/lang/en.js` 追加同结构英文翻译 - [x] T035 [P] 在 `foodie-store/src/lang/vi.js` 追加同结构越南语翻译 **Checkpoint**: 侧边栏显示新菜单,页面可访问,多语言正常 --- ## Phase 5.5: 用户端后端接口 (FR-011~022) **Purpose**: 实现用户端的领券、查券、算价计算后端接口(前端界面由小程序实施,不做) **Goal**: 用户端小程序可调用后端 API 完成领券、查看优惠券、结算页优惠计算 **Independent Test**: 用 Postman 调用算价接口,传入购物车商品,返回两条路径对比 + 最优方案 + 可用券列表 ### Service 层 - [x] T039 [P] 创建 IPromotionUserCouponService + PromotionUserCouponServiceImpl `ruoyi-system/src/main/java/com/ruoyi/system/service/IPromotionUserCouponService.java` 和 `impl/PromotionUserCouponServiceImpl.java` — 方法: receiveCoupon(userId, batchId, storeId)(检查限领1张、**乐观锁扣库存 `UPDATE remain_count=remain_count-1 WHERE remain_count>0`**、计算expireTime=领取日期+validDays天23:59:59、@Transactional), selectStoreCouponsForUser(userId, storeId)(查询门店进行中券批次+用户是否已领标记,不分页), selectMyCoupons(userId, status?, storeId?)(返回含storeName,实时判断expire_time0) **Checkpoint**: 用户端 API 可用——领券、查券、算价计算接口通过 Postman 测试通过 --- ## Phase 5.6: 促销活动修改/删除 (FR-005a, FR-005b) **Purpose**: 商家能修改未开始的活动、删除未开始的活动,参考美团商家端交互 **Goal**: 活动列表操作列按状态显示不同按钮(未开始=编辑+删除,进行中=结束,已结束=无) ### 后端 - [x] T046 在 IPromotionActivityService 中添加 `updateActivity(activity, rules)` — 校验 status=0 才允许修改;@Transactional 先删除旧规则再重新插入 - [x] T047 在 IPromotionActivityService 中添加 `deleteActivity(id)` — 校验 status=0 才允许删除;@Transactional 删除活动+关联规则 - [x] T048 在 ShPromotionActivityController 中添加 `PUT /` (updateActivity) 和 `DELETE /{id}` (deleteActivity) 端点 ### 前端 API - [x] T049 在 `foodie-store/src/api/promotionActivity.js` 中添加 `updatePromotionActivity(data)` 和 `deletePromotionActivity(id)` ### 前端页面 - [x] T050 修改 `foodie-store/src/views/PromotionActivity.vue`: - 操作列按状态显示按钮:未开始(编辑+删除) / 进行中(结束) / 已结束(无) - 编辑:点击后调用 getPromotionActivity(id) 获取详情,回填到创建对话框,tijiaobaocun 判断有 id 则调用 updatePromotionActivity - 删除:二次确认后调用 deletePromotionActivity(id) - 新增 data: `editingId: null`,`tijiaobaocun` 判断 editingId 有值走修改、无值走新增 ### i18n - [x] T051 [P] 在 4 个语言文件(zh/tw/en/vi)的 promoActivity section 中追加:editBtn、deleteBtn、editActivity、deleteConfirm 等新 key **Checkpoint**: 未开始的活动可编辑(修改名称/时间/规则)、可删除(二次确认后删除),进行中只能结束 --- ## Phase 5.7: 优惠券修改/删除 (FR-009a, FR-009b) **Purpose**: 商家能修改未开始/进行中的优惠券、删除未开始的优惠券 **Goal**: 优惠券列表操作列按状态显示不同按钮(未开始=编辑+删除,进行中=编辑+下架,已结束/已下架=无) ### 后端 - [x] T052 在 IPromotionCouponBatchService 中添加 `updateBatch(batch, rule)` — 校验 status=0或1 才允许修改;@Transactional 先删除旧规则再重新插入 - [x] T053 在 IPromotionCouponBatchService 中添加 `deleteBatch(id)` — 校验 status=0 才允许删除;@Transactional 删除券批次+关联规则 - [x] T054 在 ShPromotionCouponController 中添加 `PUT /` (updateBatch) 和 `DELETE /{id}` (deleteBatch) 端点 ### 前端 API - [x] T055 在 `foodie-store/src/api/promotionCoupon.js` 中添加 `updatePromotionCoupon(data)` 和 `deletePromotionCoupon(id)` ### 前端页面 - [x] T056 修改 `foodie-store/src/views/CouponBatch.vue`: - 操作列按状态显示按钮:未开始(编辑+删除) / 进行中(编辑+下架) / 已结束/已下架(无) - 编辑:点击后调用 getPromotionCoupon(id) 获取详情,回填到创建对话框,tijiaobaocun 判断有 id 则调用 updatePromotionCoupon - 删除:二次确认后调用 deletePromotionCoupon(id) - 新增 data: `editingId: null`,`tijiaobaocun` 判断 editingId 有值走修改、无值走新增 ### i18n - [x] T057 [P] 在 4 个语言文件(zh/tw/en/vi)的 couponBatch section 中追加:editBtn、deleteBtn、editCoupon、deleteConfirm 等新 key --- ## Phase 5.8: 免配送费券 (FR-008a) **Purpose**: 新增 couponType=3 免配送费券,商家可创建减免配送费的优惠券 **Goal**: 创建券对话框新增"免配送费券"选项,配置使用门槛+减免金额+同享/互斥 ### 数据库 - [x] T058 在 `updatesql/sql.md` 追加 ALTER 语句更新 promotion_coupon_batch.coupon_type 的 COMMENT 为 '1=满减券 2=商品券 3=免配送费券'(无需实际 ALTER,仅记录) ### 前端页面 - [x] T059 修改 `foodie-store/src/views/CouponBatch.vue` 创建对话框:券类型 radio-group 新增第三个选项"免配送费券"(couponType=3),选中后显示:使用门槛 el-input-number + 减免金额 el-input-number + 叠加属性 radio(同享/互斥),隐藏商品选择 ### i18n - [x] T060 [P] 在 4 个语言文件(zh/tw/en/vi)的 couponBatch section 中追加:typeFreeDelivery(免配送费券)等 key **Checkpoint**: 创建券时可选"免配送费券",提交数据 couponType=3,含 threshold + amount + isMutex **Checkpoint**: 未开始的券可编辑+删除,进行中的券可编辑+下架,已结束/已下架无操作 --- ## Phase 5.9: 折扣商品改为逐商品设折扣 (需求变更) **Purpose**: 将折扣商品 UI 从「折扣区分组」改为「逐商品设折扣」(参考美团),提升商家体验 **Goal**: 商家创建折扣活动时直接选择商品并逐个设折扣率,不再需要先建折扣区 **背景**: 经美团/饿了么调研,主流外卖平台都是逐商品设折扣,不使用折扣区分组。后端数据模型已支持(`promotion_activity_rule` 每行有独立 `productId` + `discountRate`),改动集中在前端 UI。 ### 前端页面 - [x] T061 修改 `foodie-store/src/views/PromotionActivity.vue` 折扣 Tab (Tab2) 的 UI 和逻辑: - **移除**:折扣区分组 UI(建区/删区按钮、折扣组 v-for 循环) - **改为**扁平商品列表,每行 = 商品名称 + 原价 + 折扣率控件(-/+按钮+输入框,范围10%~99%,步长0.1) + 折后价(自动计算) + 移除按钮 - **添加商品按钮**:点击打开商品选择弹窗(复用已有弹窗),选中后默认折扣率90%,添加到列表 - **重复商品限制**:选择商品时如已存在于列表则提示并跳过 - **折后价实时计算**:原价 × 折扣率,显示在每行 - **提交逻辑简化**:`tijiaobaocun()` 中折扣 Tab 直接构建 `rules: [{productId, discountRate}, ...]`,无需展开分组 - **编辑回填**:编辑折扣活动时,从 `rules` 数组直接回填到商品列表,每行设置对应的 discountRate - **折扣率校验**:前端提交时校验所有折扣率在 0.10~0.99 范围内,超出范围阻止提交 ### i18n - [x] T062 [P] 更新 4 个语言文件 `foodie-store/src/lang/` 的 zh.js、tw.js、en.js、vi.js: - 移除折扣区相关 key(如 addDiscountZone、deleteZone、discountZone 等) - 新增/修改:discountRate(折扣率)、discountedPrice(折后价)、originalPrice(原价)、removeProduct(移除)、addDiscountProduct(添加折扣商品)、discountRateRange(范围10%-99%)、productAlreadyAdded(商品已添加)等 key - 更新 promoActivity section 中与折扣 Tab 相关的所有文案 ### 后端验证 - [x] T063 验证后端接口兼容性:确认 `ShPromotionActivityController` 的 POST/PUT 端点已支持接收扁平的 `rules: [{productId, discountRate}]` 格式(不需要改动),确认编辑回填接口 GET /{id} 返回的 rules 中每条包含 productId 和 discountRate(已有 LEFT JOIN pos_food) **Checkpoint**: 商家创建折扣活动时 UI 为扁平商品列表,每个商品独立设折扣率,不再有折扣区分组概念。编辑时正确回填。折后价实时计算。后端接口无需改动。 --- ## Phase 6: Polish & 验证 **Purpose**: 端到端验证 - [ ] T036 后端启动验证:用 Postman 测试 4 个促销 API + 4 个优惠券 API(商家端)+ 3 个用户端领券 API + 1 个算价 API 的完整流程 - [ ] T036a 算价接口专项验证:构造测试数据(门店有满减+折扣活动+优惠券),验证两条路径计算正确、互斥规则生效、新客立减可叠加 - [ ] T037 前端启动验证:npm run dev → 侧边栏新菜单 → 创建满减活动(3档位) → 创建折扣活动(选择5个商品逐个设不同折扣率) → 创建第二份半价 → 创建新客立减 → 创建满减券 → 创建商品券 → 列表筛选 → 结束活动 → 下架券 → 编辑折扣活动验证回填 - [ ] T038 [P] 切换4种语言验证所有文案显示正确 --- ## Dependencies & Execution Order ### Phase Dependencies - **Phase 1 (Setup)**: 无依赖,立即开始 - **Phase 2 (Foundational)**: 依赖 Phase 1 的表已创建 - **Phase 3 (US1 促销)**: 依赖 Phase 2 的实体和 Mapper - **Phase 4 (US2 优惠券)**: 依赖 Phase 2,可与 Phase 3 并行 - **Phase 5 (Menu/i18n)**: 依赖 Phase 3 + Phase 4 的页面文件存在 - **Phase 5.5 (用户端接口)**: 依赖 Phase 2 的实体/Mapper + Phase 3 的促销 Activity Service + Phase 4 的优惠券 Service - **Phase 6 (验证)**: 依赖全部完成(包括 Phase 5.9 折扣改动) ### Parallel Opportunities - T003-T007a (6个实体) 可并行 - T008-T012a (6个Mapper接口) 可并行 - T013-T017a (6个Mapper XML) 可并行 - Phase 3 和 Phase 4 可并行(不同文件,不同 Controller) - T039 和 T040 可并行(不同 Service) - T032-T035 (4个语言文件) 可并行 ### Recommended Execution Order ``` T001 → T002(手动) → T003-T017a (Phase 2, 大量并行) → T018-T023 (Phase 3, 促销活动) + T024-T029 (Phase 4, 优惠券) [可并行] → T030-T035 (Phase 5, 菜单路由i18n) → T039-T045 (Phase 5.5, 用户端接口) → T061-T063 (Phase 5.9, 折扣商品改为逐商品设折扣) ← 当前待实施 → T036-T038 (Phase 6, 验证) ``` --- ## Notes - [P] tasks = 不同文件,无依赖,可并行 - [Story] label 映射到 spec 中的 User Story (US1=促销, US2=优惠券) - 每个任务完成后 commit - 前端文件 CRLF 换行,用 Python 脚本编辑 - 旧代码(SalesPromotion, VipQuanyi)不动 - PromotionUserCoupon 实体和 Mapper 在 Phase 2 创建,Service/Controller 在 Phase 5.5 实现 - PosOrderPromotion 实体和 Mapper 在 Phase 2 创建,算价 Service 在 Phase 5.5 使用 - 用户端前端(小程序界面)不在本范围,只做后端 API