Files
medical-mall/pages/mall/delivery/doc/需求文档(现用)/数据库对比与修改建议.md
2026-03-17 11:06:26 +08:00

9.9 KiB
Raw Blame History

配送端(自营骑手)表 vs 第三方快递轨迹表:对比与数据库修改建议

本文目标:

  • 整理“原先配送端(自营骑手/同城配送)”使用的核心数据表。
  • 对比“现在第三方快递配送(韵达/圆通等)”的轨迹/运单数据表。
  • 给出建议的数据库改造方案:如何在不破坏订单主表的前提下,引入第三方快递轨迹能力,并(可选)逐步弃用原先配送端表的依赖。

明确决策(当前结论):

  • 仅支持第三方快递轨迹(承运方运单 + 轨迹时间线)。
  • 不做自营骑手端/同城配送任务流;ml_delivery_drivers/ml_delivery_tasks 视为历史遗留表,不再作为新能力的依赖与写入目标。

说明:本对比只讨论“第三方快递轨迹/运单”与“自营骑手任务”两套模型如何在数据库层共存/迁移;二者是不同业务域,不建议强行复用同一张表。


1. 原先配送端(自营骑手)核心表(现状)

数据来源:主库 DDLmall_sql/schemas/complete_mall_database.sql)与旧配送端文档(pages/mall/delivery/doc/old/*)。

1.1 ml_delivery_drivers(配送员信息表)

用途:记录配送员(骑手)档案与实时工作状态;用于配送端登录后的“是否可接单/是否在线”。

关键字段(节选):

  • id:配送员 ID
  • user_id:关联 ak_users.id
  • real_nameid_carddriver_license
  • vehicle_typevehicle_number
  • service_areasJSONB
  • work_status1 在线 / 2 忙碌 / 3 离线
  • current_lat / current_lng
  • rating_avg / rating_count / order_count
  • status1 正常 / 2 暂停 / 3 离职

1.2 ml_delivery_tasks(配送任务表,配送端“状态真源”)

用途:描述“一个订单被分配给某个骑手并经历接单→取货→配送→送达”的任务流。

关键字段(节选):

  • 关联:
    • order_idUUID唯一FK 到 ml_orders.id
    • driver_idFK 到 ml_delivery_drivers.id,可为空表示未接单)
  • 地址与费用:
    • pickup_addressJSONB取货地址
    • delivery_addressJSONB配送地址
    • distanceestimated_timedelivery_fee
  • 任务状态:statusint
    • 1 待接单
    • 2 已接单
    • 3 取货中
    • 4 配送中
    • 5 已送达
    • 6 配送失败
  • 时间戳:assigned_at / picked_at / delivered_at
  • 其他:delivery_code(取货码)、remarkfailure_reason

注意:旧页面/旧文档里常出现 accepted_atpickup_timedelivered_time 等命名,和主库 DDL 的 assigned_at/picked_at/delivered_at 存在差异;如果你要继续使用自营配送链路,建议在代码层做统一字段映射或做一次字段对齐迁移。

1.3 与订单表的关系(旧模型的关键耦合点)

  • ml_delivery_tasks.order_id 强依赖 ml_orders.id,并且 1 个订单只能有 1 条配送任务order_id UNIQUE)。
  • 旧实现里常尝试把 ml_delivery_tasks.status 同步到 ml_orders.order_status,容易造成口径不一致(旧文档也提到了这种冲突风险)。

2. 现在第三方快递配送(轨迹/运单)表(目标模型)

数据来源:pages/mall/delivery/doc/需求文档/express_tracking_mock_platform.sql

这套表的定位不是“骑手任务流”,而是“第三方承运的运单 + 轨迹事件时间线”。

2.1 platform_express_waybills(平台侧:运单主表)

用途:一条运单(一个 tracking_no)的聚合信息;用于订单详情页展示“承运方/运单号/当前状态/最后同步时间”。

关键字段(节选):

  • 关联:order_id(可选)、order_no(可选)
  • 运单:carriertracking_nosource
  • 聚合状态:current_status_codecurrent_status_text
  • 时间:etalast_synced_at
  • 约束:UNIQUE (carrier, tracking_no)

特点:

  • 同一个订单允许对应多条运单(拆包裹/分批发货)——因为 order_id 不唯一。

2.2 platform_express_tracking_events(平台侧:轨迹事件表)

用途:时间线的主数据来源;用于前端展示、告警统计与排障。

关键字段(节选):

  • 关联:waybill_idFK 到 platform_express_waybills.id
  • 事件:event_id(第三方可能缺失)、event_timeevent_codeevent_text
  • 平台统一状态:status_code
  • 节点:node_namelocationdescription
  • 证据:evidence_urlsjsonb
  • 原始回文:raw_payloadjsonb可用于审计/排障)
  • 幂等:dedupe_key + UNIQUE (waybill_id, dedupe_key)

2.3 platform_express_event_raw(平台侧:原始接收表)

用途:记录 webhook/轮询的原始请求、验签与解析错误,便于排障与审计。

2.4 mock_*Mock 承运方侧表)

这部分只用于联调/回归/故障注入,不建议进入生产主库的核心业务 schema可以放在独立 schema 或测试库)。


3. 两套模型的核心差异(为什么不建议“复用一张表”)

维度 自营骑手(旧配送端) 第三方快递(新模型)
业务对象 任务(骑手接单、取货、送达) 运单(承运方扫描轨迹)
与订单关系 1 订单 = 1 任务(order_id UNIQUE 1 订单 = N 运单(拆包裹常见)
状态来源 平台自己驱动状态机(按钮/操作) 第三方事件驱动webhook/轮询)
数据颗粒度 少量节点(接单/取货/送达) 高频节点(到站/发车/分拣/派送/签收…)
关键字段 driver_id、地址 JSON、配送费、距离 carriertracking_no、事件时间线、幂等去重
风险点 并发抢单、任务状态与订单状态不同步 乱序/重复事件、验签、防重放、脱敏

结论:

  • 旧表(ml_delivery_*)适合“自营骑手/同城配送”。
  • 新表(platform_express_*)适合“第三方快递轨迹”。
  • 两者可以共存,但不要强行把第三方轨迹塞进 ml_delivery_tasks

4. 推荐的数据库修改方案(兼容、可渐进)

4.1 方案 1推荐新增第三方快递表不改旧配送表

适用:你们当前要做第三方快递展示,且已明确“不做自营骑手”。

做法:

  1. 在主库新增(或通过 migration 引入)三张平台侧表:
    • platform_express_waybills
    • platform_express_tracking_events
    • platform_express_event_raw
  2. 商家发货时写入/绑定:创建 platform_express_waybills 行(填 order_idorder_nocarriertracking_no)。
  3. 第三方回调/轮询入库:写 platform_express_tracking_events,并更新 platform_express_waybills.current_status_*last_synced_at

建议的小幅增强(强烈建议做):

  • platform_express_waybills(order_id) 增加索引(便于按订单查运单)。
  • platform_express_waybills.order_id 建外键到 ml_orders(id)(如果你们能保证订单一定存在)。

4.2 方案 2逐步“弃用旧配送端表”的依赖当你们全面第三方快递时

适用:你们不再提供自营骑手配送,或者想把骑手端做成独立项目。

做法(建议按阶段,不要硬删表):

  • 阶段 A停止业务写入 ml_delivery_tasks(页面/接口不再创建任务)。
  • 阶段 B订单详情页的物流展示只依赖 platform_express_*
  • 阶段 Cml_delivery_tasks 标为 legacy只读保留一段时间最终再评估是否归档/删除。

为什么不建议立刻删:

  • 历史数据、结算对账、纠纷复盘可能仍需要旧数据。

在“不做自营骑手”的前提下,最小要求:

  • 新增第三方快递表后,业务代码只写入/读取 platform_express_*,不要再创建/更新 ml_delivery_tasks
  • 旧表保留只读(或仅用于历史查询/清理脚本),后续再评估归档策略。

4.3 如果两种配送方式要并存(同城骑手 + 快递)

建议用“履约类型”做分流,而不是混表:

  • 同城/自营:继续用 ml_delivery_tasks(任务流)
  • 快递:用 platform_express_*(运单轨迹)
  • 订单详情页按订单的履约类型选择展示模块(或同时展示多个包裹)

5. 迁移/改库执行清单(建议写成 migration

5.1 建表落库

  • express_tracking_mock_platform.sql 的 A 部分platform整理为一份 migration放到 mall_sql/migrations/),避免:
    • 重复创建 set_updated_at()(项目若已有同名函数)
    • mock_* 测试表混进生产 schema

5.2 对接 ml_orders

  • 建议:
    • platform_express_waybills.order_id REFERENCES public.ml_orders(id)
    • CREATE INDEX ... ON platform_express_waybills(order_id)
  • 不建议:
    • 把运单号/承运方直接塞进 ml_orders(会导致一单多包裹很难处理)

5.3 数据回填(可选)

如果你们历史上已经保存过“承运方/运单号”在别处(例如订单扩展表/发货日志),可做一次性回填:

  • 按订单生成 waybill 行
  • 再按运单触发一次轨迹拉取

5.4 权限与隐私

  • 买家/商家/客服看到的轨迹必须“同源”,但展示要按角色脱敏;敏感字段(如手机号、原始回文)按文档约束控制。

6. 你接下来要怎么改数据库(最短路线)

如果你现在的目标是:商家可选承运方 + 录入运单号 + 用户能看轨迹时间线。

最短路线:

  1. 在主库落 platform_express_waybills / platform_express_tracking_events / platform_express_event_raw
  2. 发货绑定时写 platform_express_waybills(order_id, order_no, carrier, tracking_no)
  3. 第三方事件入库写 platform_express_tracking_events
  4. 订单详情页按 order_id 查 waybills再查 events 渲染时间线

(如你确认要我进一步把“建议的小幅增强”直接写成 SQL migration 文件,我可以在 mall_sql/migrations/ 里新增一份只包含 platform 表的 migration并确保不引入 mock_* 表。)