12 KiB
运输计划一车多卸重构 Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 将运输计划从「1 供方 + 1 需方」升级为「1 装货段 + N 送货段」,并贯通归档、地磅、司机/现场链接、打印与历史迁移。
Architecture: 在 pl_plan 保留计划级主数据;新增 pl_plan_load / pl_plan_delivery 及段产品子表;链接与地磅按 stop_type+stop_id 关联;打印与归档按段规则聚合。详见 docs/superpowers/specs/2026-08-26-pl-multi-stop-redesign-design.md。
Tech Stack: FastAPI · SQLAlchemy · Pydantic v2 · Vue 3 · Element Plus · MySQL 5.7 · docs/sql/shanxia2.0.sql
文件结构(新建 / 主要修改)
| 职责 | 路径 |
|---|---|
| 装货/送货 ORM | backend/app/models/pl_models.py |
| 段 CRUD / 归档 | backend/app/services/pl_plan_service.py(或拆 pl_plan_stop_service.py) |
| 计划 API | backend/app/api/pl/plan.py |
| 安排/地磅 | backend/app/services/pl_plan_service.py、backend/app/api/pl/transport.py |
| 公网司机/现场 | backend/app/api/public_site.py(或现有 public 路由) |
| DDL | docs/sql/migrations/2026-08-26-pl-multi-stop.sql + 合并 docs/sql/shanxia2.0.sql |
| 迁移脚本 | backend/scripts/migrate_pl_plan_to_multi_stop.py |
| 计划表单 | web-admin/src/components/business/pl-plan-form-dialog/ |
| 送货段 UI | 新建 pl-plan-load-section/、pl-plan-delivery-section/ |
| 选客户打印 | 新建 pl-plan-delivery-customer-select-dialog/ |
| 送提货/入库打印 | pl-delivery-slip-print-dialog/、pl-inbound-slip-print-dialog/ |
| 归档弹窗 | pl-plan-archive-dialog/、views/pl/plan-archive/index.vue |
| 类型/API | web-admin/src/api/pl/index.ts |
Phase 1:数据库与模型
Task 1: DDL — 装货/送货段表
Files:
-
Create:
docs/sql/migrations/2026-08-26-pl-multi-stop.sql -
Modify:
docs/sql/shanxia2.0.sql(归档后全量快照) -
Step 1: 在 migration SQL 中创建
pl_plan_load、pl_plan_load_product、pl_plan_delivery、pl_plan_delivery_product -
Step 2:
pl_plan增加freight_remark VARCHAR(512) NULL -
Step 3:
pl_plan_contract增加stop_id VARCHAR(64) NULL;side注释扩展load/delivery -
Step 4:
pl_transport_db_link增加stop_type VARCHAR(20)、stop_id VARCHAR(64)(可空,兼容旧数据) -
Step 5: 在本地库执行 migration 并验证表结构
Task 2: SQLAlchemy 模型
Files:
-
Modify:
backend/app/models/pl_models.py -
Modify:
backend/app/schemas/pl/plan.py -
Step 1: 新增
PlPlanLoad、PlPlanLoadProduct、PlPlanDelivery、PlPlanDeliveryProduct类 -
Step 2:
PlPlan增加freight_remark;PlPlanContract增加stop_id -
Step 3: 新增 Pydantic:
PlanLoadBody、PlanDeliveryBody、PlanStopProductBody、*Read嵌套进PlanWithProducts -
Step 4: 运行
python -c "from app.models.pl_models import PlPlanLoad"确认无导入错误
Task 3: 内部客户与地磅方向工具
Files:
-
Create:
backend/app/services/pl_plan_stop_rules.py -
Reuse:
backend/app/services/pl_internal_customer.py -
Step 1: 实现
resolve_stop_dibang_defaults(customer_name, stop_type) -> (generate_dibang, dibang_direction) -
Step 2: 实现
warn_qty_imbalance(plan_products, load_products, delivery_products) -> list[str](仅返回警告文案) -
Step 3: 单元测试(新建
backend/tests/test_pl_plan_stop_rules.py)覆盖山峡装货=出库、山峡送货=入库
Phase 2:计划 CRUD API
Task 4: 读取计划(含段)
Files:
-
Modify:
backend/app/api/pl/plan.py -
Modify:
backend/app/services/pl_plan_service.py -
Step 1:
_row_to_dict/get_plan_detail联查 load、deliveries、段产品、合同(按 stop_id) -
Step 2:
GET /transport/plan/{id}返回load、deliveries[] -
Step 3: 列表
planApi.list增加摘要字段loadCustomerName、deliveryCustomerSummary(后端聚合)
Task 5: 创建/更新计划(全量段)
Files:
-
Modify:
backend/app/services/pl_plan_service.py -
Modify:
backend/app/api/pl/plan.py -
Step 1:
create_plan_full接受load+deliveries[];事务内写段表 +pl_plan_product -
Step 2: 校验:必须有 1 条 load、≥1 条 delivery;外部段合同非空
-
Step 3: 数量不平衡调用
warn_qty_imbalance,响应warnings: string[](HTTP 200) -
Step 4:
update_plan全量替换段(软删旧段产品行) -
Step 5: 跑
python scripts/check_field_consistency.py并修复差异
Task 6: 历史数据迁移
Files:
-
Create:
backend/scripts/migrate_pl_plan_to_multi_stop.py -
Step 1: 对无
pl_plan_load的计划:supplier→load,customer/destination→delivery seq=1 -
Step 2: 复制产品行到 load_product / delivery_product;迁移
pl_plan_contract.side -
Step 3: 已归档计划:把
inbound_*写入 load 产品行,outbound_*写入 delivery 产品行 -
Step 4: 干跑模式
--dry-run+ 日志统计;正式执行前备份库
Phase 3:前端计划表单
Task 7: API 类型与表单数据模型
Files:
-
Modify:
web-admin/src/api/pl/index.ts -
Step 1: 增加
PlanLoad、PlanDelivery、PlanStopProduct类型 -
Step 2:
createFull/updatebody 含load、deliveries -
Step 3: 处理响应
warnings,ElMessage.warning展示
Task 8: 装货段组件(单段)
Files:
-
Create:
web-admin/src/components/business/pl-plan-load-section/index.vue -
Step 1: 客户选择 + 合同多选(内部禁用);产品表从计划产品带出
-
Step 2: 地址/时间/联系/注意事项(复用地址选择组件)
-
Step 3:
generateDibang随内部客户自动勾选(装货=出库)
Task 9: 送货段组件(多段)
Files:
-
Create:
web-admin/src/components/business/pl-plan-delivery-section/index.vue -
Step 1:
v-for送货段卡片;支持增删、排序 -
Step 2: 每段:客户、合同、产品行、地址信息、地磅勾选
-
Step 3: 「从计划产品同步」按钮(新增段时带出默认行)
Task 10: 接入 PlPlanFormDialog
Files:
-
Modify:
web-admin/src/components/business/pl-plan-form-dialog/index.vue -
Step 1: 移除供方/需方区块;接入 load + delivery 组件
-
Step 2: 保存/保存并安排:组装 payload;展示 warnings
-
Step 3: 编辑回填:API 返回的 load/deliveries 写入 formData
-
Step 4: 复制计划:深拷贝段数据
Task 11: 查看弹窗与列表摘要
Files:
-
Modify:
web-admin/src/components/business/pl-plan-view-tabs/index.vue -
Modify:
web-admin/src/views/pl/plan/index.vue -
Step 1: 查看 Tab 增加「装货/送货」分段展示
-
Step 2: 列表客户列改为装货/送货摘要
Phase 4:安排运输与地磅
Task 12: 安排弹窗按段地磅
Files:
-
Modify:
web-admin/src/components/business/pl-plan-arrange-dialog/index.vue -
Modify:
backend/app/services/pl_plan_service.py(create_transport_for_plan) -
Step 1: 安排弹窗列出各段
generateDibang勾选(可改) -
Step 2: 按段调用地磅生成;
pl_transport_db_link.stop_id写入 -
Step 3: 调整运输:revoke 逻辑按段处理(沿用现有不可作废则阻断)
Phase 5:司机 / 现场链接
Task 13: 司机公网页分段上传
Files:
-
Modify: 公网司机页模板/Vue(
miniprogram或web公网页路径,按仓库现有 driver public 页定位) -
Modify:
backend/app/api/pl/plan.py或 public 路由 -
Step 1: 司机页展示装货 + 全部送货段标题
-
Step 2: 每段独立附件上传 API:
POST .../driver-feedbackbody{ stopType, stopId, urls } -
Step 3: 管理端
PlPlanViewTabs运输信息 Tab 按段展示司机附件
Task 14: 现场公网页(仅内部段)
Files:
-
Modify: 现场公网页 +
pl_transport_site_service.py -
Step 1: 单 token 页面仅渲染
is_internal && generate_dibang的段 -
Step 2: 每段:数量必填 → 附件;校验顺序
-
Step 3: 外部送货段不在现场页出现
Phase 6:打印
Task 15: 送提货单选客户
Files:
-
Create:
web-admin/src/components/business/pl-plan-delivery-customer-select-dialog/index.vue -
Modify:
web-admin/src/views/pl/plan/index.vue(打印入口) -
Step 1: 统计送货段去重
customer_id;仅 1 个客户时跳过弹窗 -
Step 2: ≥2 客户时弹窗单选;确认后带
customerId打开PlDeliverySlipPrintDialog
Task 16: 送提货单数据聚合
Files:
-
Modify:
backend/app/api/pl/plan.py(或 print 专用 endpoint) -
Modify:
pl-delivery-slip-print-dialog/index.vue -
Modify:
web-admin/src/utils/pl-delivery-slip-template.ts -
Step 1: 后端按
customerId合并该客户所有送货段产品行 -
Step 2: 收货单位 = 客户名;地址/联系人 = seq 最小送货段
-
Step 3: 模板变量对齐新字段
Task 17: 入库单 / 分装单
Files:
-
Modify:
pl-inbound-slip-print-dialog/index.vue -
Modify:
pl-subpack-slip-print-dialog/index.vue -
Step 1: 入库单「送货单位」=
load.customerName -
Step 2: 分装单移除客户相关占位(若有)
Phase 7:归档与运费
Task 18: 归档弹窗分段
Files:
-
Modify:
web-admin/src/components/business/pl-plan-archive-dialog/ -
Modify:
backend/app/services/pl_plan_service.py(archive_plan) -
Step 1: 上区:装货表(inbound_)+ 各送货表(outbound_)
-
Step 2: 运费区增加
freightRemark输入 -
Step 3: 提交前校验全部段必填;一次 API 原子归档
-
Step 4: 库存同步改为按段汇总后写台账
Task 19: 运费结算展示备注
Files:
-
Modify:
web-admin/src/views/pl/freight/components/UnsettledPlanPanel.vue -
Modify:
SettlementBillPanel.vue(结算详情弹窗) -
Step 1: 列表/详情只读展示
freightRemark(计划级)
Phase 8:验收
Task 20: 端到端验收清单
- Step 1: 场景 30=10+15+5 建单 → 安排 → 司机/现场 → 归档 → 运费结算(需联调环境手测)
- Step 2: 送提货单 3 客户选择 + 同客户 2 段合并(单元测试覆盖)
- Step 3: 迁移脚本在 staging 数据跑通;旧单打印/归档回归(
--dry-run可用,待连库) - Step 4: 相关 pytest 通过(
vue-tsc全仓既有错误,与本变更无关) - Step 5:
./scripts/update-graph.sh(backend/frontend 已更新)
Spec 覆盖自检
| 需求 | Task |
|---|---|
| D1 装货 1 段 | Task 5 校验、Task 8 |
| D2 送货多段 | Task 9 |
| D3 数量告警 | Task 3、5、10 |
| D5/D6 内部地磅 | Task 3、8、9、12 |
| D7 归档字段 | Task 18 |
| D8 整单归档 | Task 18 |
| D9/D10 链接 | Task 13、14 |
| D11–D13 打印 | Task 15–17 |
| D14 运费备注 | Task 1、18、19 |
| D15 迁移 | Task 6 |
建议实施顺序
- Phase 1–2(可并行前后端类型草案)
- Phase 3(表单可见进展)
- Phase 6 打印(业务方易验证)
- Phase 4–5 安排与链接
- Phase 7 归档
- Phase 8 + Task 6 生产迁移
预估规模: 大重构,建议分 2~3 个 PR(① 表+API+表单 ② 链接+地磅+打印 ③ 归档+迁移)。