# Implementation Plan: 商家自配送 **Branch**: `test-202609v2`(按用户要求不单独开分支) | **Date**: 2026-09-08 | **Spec**: [spec.md](spec.md) **Input**: Feature specification from `/specs/029-merchant-self-delivery/spec.md` ## Summary 商家在门店信息开启自配送(全天/按星期自定义时段);下单时按快照判定(即时单按下单时刻、预约单按预约送达时间,区间 [开始,结束)),命中的外送单标记 `self_delivery=1`、不进骑手抢单池;商家接单/出餐后自行配送,可选"开始配送"、必点"确认送达"完成订单;运费全额(不抽成)入账 `user_id=sh_id`(普通商家=商家、夜市摊位单=夜市主),到付归因同步;夜市由夜市主在夜市主门店行统一配置、对旗下摊位生效;用户端与商家端显示"商家自配送/自配送"标识(四语言)。合并订单/同一配送人多单机制明确排除(另立需求)。 技术方案:`pos_store` 2 列 + 新表 `pos_store_self_delivery_hours`(镜像营业时段模式)+ `pos_order` 1 列快照;新增 SelfDeliveryUtil(时段判定,不复用边界语义不符的 isLegalTime)与 SelfDeliveryService(配置解析/入账);配送操作端点加在 PosOrderShOprateController;结算分支挂 OrderLifecycleService.completeSideEffects;骑手池过滤 + 三操作直调拒绝。详见 [research.md](research.md)、[data-model.md](data-model.md)、[contracts/api.md](contracts/api.md)。 ## Technical Context **Language/Version**: Java 21(Spring Boot + MyBatis-Plus);前端 Vue2 + Element UI(foodie-store) **Primary Dependencies**: MyBatis-Plus(新表 BaseMapper)、Redisson(配送操作并发锁)、PayPush/MerchantNotificationRouter(推送)、merchantStoreAccessService(022 门店权限) **Storage**: MySQL(DDL 见 data-model.md,写入 `updatesql/sql.md` 由开发者手动执行) **Testing**: JUnit5(SelfDeliveryUtil 边界单测、SelfDeliveryService 判定/入账单测、Controller 契约测试——仓库已有 PosOrderQsOprateControllerTest/PosOrderShOprateControllerTest 先例);接口级冒烟按 quickstart.md **Target Platform**: Linux 服务器部署(Windows 开发机,JDK 用 `C:\Users\qmj\.jdks\graalvm-jdk-21.0.7` 临时设置 JAVA_HOME) **Project Type**: web-service(后端)+ 商家端管理前端(外部路径 `E:\QtwCode\foodie\foodie-store`,CRLF 文件用 Python 脚本编辑) **Performance Goals**: 无特殊要求(判定为 O(时段数) 纯内存计算;配置读取随下单批量查表) **Constraints**: 模块依赖 admin→system 不可反向;Controller 参数规范(token/DTO/@RequestParam);i18n 后端 5 个 properties + 前端 4 个语言文件;不触碰废弃代码清单 **Scale/Scope**: 后端 ~8 个文件改动 + 4 个新文件;前端 1 个设置区块 + 订单标识 + i18n;1 张新表 + 3 列 ## Constitution Check *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* `.specify/memory/constitution.md` 为未填写的占位模板,无项目级 gates。以 CLAUDE.md 项目规范替代检查: | 规范 | 状态 | |------|------| | Controller 参数规范(token/DTO/显式 @RequestParam/禁 Map) | ✅ contracts/api.md 全部 DTO 化 | | 模块边界 admin→system | ✅ 实体+Mapper 在 system,业务服务在 admin(data-model.md) | | DDL 入 updatesql/sql.md 不直接执行 | ✅ data-model.md 已给出待登记 SQL | | 前端 i18n 四语言、key 有意义、按对象层级插入 | ✅ contracts §5/§6;CRLF 用 Python 编辑 | | 废弃代码不触碰 | ✅ research.md「涉及的废弃代码」节 | | Java 注释禁 `*/`、主要注释规范 | ✅ 实现阶段遵守 | | 餐桌码先例:功能覆盖普通商家 | ✅ 配置/判定/操作均含普通商家路径 | ## Project Structure ### Documentation (this feature) ```text specs/029-merchant-self-delivery/ ├── plan.md # This file ├── research.md # Phase 0 output(现状事实 F1-F16 + 决策 D1-D10) ├── data-model.md # Phase 1 output(DDL + 状态机 + 校验) ├── quickstart.md # Phase 1 output(8 个验证场景) ├── contracts/ │ └── api.md # Phase 1 output(接口契约 + i18n 清单) └── tasks.md # Phase 2 output (/speckit-tasks - NOT created yet) ``` ### Source Code (repository root) ```text foodie_server/ ├── ruoyi-system/src/main/java/com/ruoyi/system/ │ ├── domain/ │ │ ├── PosStore.java # +selfDeliveryEnabled/selfDeliveryMode │ │ ├── PosOrder.java # +selfDelivery │ │ └── PosStoreSelfDeliveryHours.java # 新实体 │ └── mapper/ │ └── PosStoreSelfDeliveryHoursMapper.java # 新 BaseMapper(无 XML) ├── ruoyi-admin/src/main/java/com/ruoyi/app/ │ ├── utils/SelfDeliveryUtil.java # 新:[start,end) 按星期判定 │ ├── order/ │ │ ├── SelfDeliveryService.java # 新:配置解析(摊位→夜市主门店)/判定/运费入账 │ │ ├── UserOrderController.java # createOrderChild 判定快照 │ │ ├── PosOrderShOprateController.java # 商家端 createOrder 判定;requireRiderAssigned 放行;+selfDeliveryStart/Complete;chuCan 骑手推送跳过 │ │ ├── PosOrderQsOprateController.java # newTask 过滤;三操作直调拒绝 │ │ ├── OrderLifecycleService.java # completeSideEffects 增自配送运费分支 │ │ └── OrderService.java # setSelfDeliveryFreightBilling(type="5") │ ├── mendian/PosStoreController.java # +get/saveMdSelfDeliveryHours │ └── order/dto/ │ ├── SelfDeliveryConfigInput.java # 新(含 SelfDeliveryHourInput) │ └── SelfDeliveryOperateInput.java # 新 ├── ruoyi-admin/src/main/resources/i18n/ # 5 个 properties 加 key ├── ruoyi-admin/src/test/java/... # SelfDeliveryUtilTest / SelfDeliveryServiceTest / 契约测试 └── updatesql/sql.md # DDL 登记 foodie-store/(商家端 PC,E:\QtwCode\foodie\foodie-store) ├── src/views/...门店信息页 # 自配送区块(复用营业时段编辑交互) ├── src/views/...订单列表/详情 # "自配送"标签 └── src/lang/{zh,tw,en,vi}.js # selfDelivery.* keys ``` **Structure Decision**: 复用现有分层(system 实体 / admin 业务),新表走 MyBatis-Plus BaseMapper 不建 XML;前端仅 foodie-store,foodie-admin-vue 与客户端 uni-app 不在本功能改动范围(research D10、assumptions)。 ## Complexity Tracking > 无 Constitution Check 违规需要辩护。 | Violation | Why Needed | Simpler Alternative Rejected Because | |-----------|------------|-------------------------------------| | — | — | — | ## 遗留决策(不阻塞实施) - **clarify Q2(配送操作界面的端覆盖)**:后端接口与 PC 配置/标识任务先行;"PC 配送操作按钮"单列为可独立裁剪任务,等用户决策后启用(research D9)。