加载中…
文档目录
物流配送系统

简介

本文件面向电商开发者,系统化梳理 DouPHP 物流配送体系,覆盖物流公司集成、快递单号管理、物流轨迹跟踪、运费计算、配送规则(地址验证、配送范围控制、自提点)、异常处理、数据缓存、批量查询优化与监控告警等。文档以代码为依据,提供可落地的架构图、流程图与开发指引,帮助快速扩展新物流公司、实现自定义运费规则并保障系统稳定运行。

项目结构

围绕“订单-物流-运费”的主线,DouPHP 将物流相关能力分布在以下层次:

  • 插件层:物流公司抽象与运费方法暴露(如 express 插件)。
  • API/控制器层:订单结算时运费重算、后台发货录入。
  • 服务层:订单状态推进、库存解锁、物流信息持久化。
  • 模型与数据层:订单主表、收货地址表、插件配置表等。
  • 前端交互:购物车/结算页运费动态更新。
graph TB
subgraph "前端"
FE["订单页面<br/>global.js"]
end
subgraph "API/控制器"
API_ORD["order.php 路由"]
API_CHK["CheckoutController::recalculateShipping"]
end
subgraph "服务层"
ORD_SVC["OrderService::tracking"]
EXP_SVC["ExpressService::methods"]
end
subgraph "数据层"
DB_ORD["订单表 order"]
DB_ADDR["收货地址表 order_address"]
DB_PLUG["插件表 plugin"]
end
FE --> API_CHK
API_CHK --> ORD_SVC
ORD_SVC --> DB_ORD
ORD_SVC --> DB_ADDR
ORD_SVC --> DB_PLUG
EXP_SVC --> DB_PLUG

核心组件

  • 物流公司插件接口:通过 ExpressService 暴露配送方式、名称与费用,供结算与展示使用。
  • 订单物流跟踪:后台录入物流公司与运单号,首次填写自动推进订单状态为已发货并解锁库存。
  • 运费重算:结算页根据选择的物流公司与订单金额重新计算运费,返回前端渲染。
  • 订货模块(B2B/批发):提供订货列表、加购、提交订货单等能力,可与物流流程衔接。
  • 收货地址与展示:订单详情从 order_address 统一读取收件人信息,保证前后端一致。

架构总览

下图展示了“选择物流公司→计算运费→下单→发货→状态同步”的端到端流程,以及关键数据流向。

sequenceDiagram
participant U as "用户"
participant FE as "前端页面"
participant API as "API 结算接口"
participant OS as "OrderService"
participant PL as "插件(Express)"
participant DB as "数据库"
U->>FE : 选择物流公司/修改收货地
FE->>API : 请求重算运费
API->>PL : 获取配送方法与费用
PL-->>API : 返回可用方式与价格
API->>DB : 写入/更新运费与订单金额
API-->>FE : 返回最新运费与总价
U->>FE : 提交订单
FE->>API : 创建订单含 shipping_id
API->>DB : 保存订单与收货地址
Note over U,DB : 后台发货
U->>OS : 录入物流公司+运单号
OS->>DB : 更新 shipping_id/tracking_no/shipped_at
OS->>DB : 若首次发货则改状态为已完成并解锁库存
OS-->>U : 返回详情页URL

详细组件分析

物流公司插件与运费方法

  • 插件职责:声明配送方式 id/name/desc/price,供结算与展示调用。
  • 费用来源:从插件配置中读取固定费用或按策略计算后的结果。
  • 扩展建议:新增物流公司时,实现对应插件并提供 methods() 输出;在结算流程中通过 plugin() 门面解析。
classDiagram
class ExpressService {
+string PLUGIN_ID
+methods() array
}
class PluginFacade {
+getWithConfig(id) array
}
ExpressService --> PluginFacade : "读取插件配置"

订单物流跟踪(物流公司集成与快递单号管理)

  • 输入校验:后台表单仅允许 order_id、shipping_id、tracking_no 三个字段,防止越权注入。
  • 业务逻辑:
    • 若订单已有运单号:仅更新物流公司、运单号与发货时间。
    • 若首次填写:将订单状态推进为“已完成”,设置 allow_aftersale=1,并解锁商品锁定库存。
  • 跳转:完成后返回订单详情页。
flowchart TD
Start(["开始"]) --> V["校验 order_id"]
V --> |非法| Err["抛出异常并返回"]
V --> |合法| Load["加载订单"]
Load --> Has{"是否已有 tracking_no?"}
Has --> |是| Update["更新 shipping_id/tracking_no/shipped_at"]
Has --> |否| Promote["推进状态为已完成<br/>设置 allow_aftersale=1<br/>解锁库存"]
Update --> Done["返回详情页URL"]
Promote --> Done

实时运费计算与结算

  • 触发点:结算页选择物流公司或优惠券变化时,调用 API 重算运费。
  • 计算过程:根据 shipping_id、订单金额与优惠券金额,调用结算服务重新计算运费与总价。
  • 返回内容:包含运费、优惠金额、订单总额格式化值,前端用于刷新显示。
sequenceDiagram
participant FE as "前端"
participant API as "CheckoutController"
participant CS as "结算服务"
FE->>API : POST 重算运费
API->>CS : recalculateShipping(shippingId, itemAmount, couponAmount)
CS-->>API : 返回运费与订单总额
API-->>FE : JSON{shipping_fee, order_amount_format,...}

订货模块与物流衔接(B2B场景)

  • 订货列表:支持按分类筛选、分页、默认排序。
  • 加购/改量/删除:维护订货购物车,支持数量变更与行删除。
  • 提交订货单:生成订货单号,写入联系人、电话、地址与订单金额,并将购物车明细关联到订货单。
  • 与物流的关系:订货单可作为后续发货/物流跟踪的业务载体。
flowchart TD
A["浏览订货列表"] --> B["加入购物车/修改数量"]
B --> C["提交订货单"]
C --> D["生成 dh_sn 并落库"]
D --> E["关联购物车明细到订货单"]
E --> F["可选:更新默认收货信息"]

收货地址与展示

  • 数据来源:订单详情中的收件人、电话、省市区、详细地址、邮编统一从 order_address 表读取,避免历史字段不一致问题。
  • 展示:后台订单详情页直接渲染上述字段,便于客服与运营核对。

依赖关系分析

  • 控制器/路由:API 路由将订单相关接口指向 Work/Cashier 控制器;后台路由将订单操作指向 OrderService。
  • 服务依赖:OrderService 依赖订单核心服务、支付服务与支付方式名称解析器;ExpressService 依赖插件门面。
  • 数据依赖:订单主表、收货地址表、插件配置表构成物流与运费的核心数据支撑。
graph LR
R["order.php 路由"] --> C1["WorkController"]
R --> C2["CashierController"]
C2 --> S1["CheckoutController"]
S1 --> S2["OrderService"]
S2 --> M1["订单模型"]
S2 --> M2["收货地址模型"]
S2 --> P1["插件(Express)"]

性能与优化

  • 批量查询优化
    • 后台订单列表采用分批查询与条件过滤,减少无效数据加载。
    • 收货地址批量拉取后映射到订单列表,避免 N+1 查询。
  • 运费计算缓存
    • 对常用物流公司配置与基础费率进行缓存(例如 Redis/Memcached),降低重复计算与外部依赖开销。
  • 异步与重试
    • 物流轨迹拉取、状态同步建议走队列异步执行,失败指数退避重试,避免阻塞主流程。
  • 前端体验
    • 运费变更采用局部刷新(AJAX),减少整页重载。

故障排查指南

  • 无法发货/状态未推进
    • 检查后台表单校验是否通过(order_id 必填且为正整数)。
    • 确认订单是否已有 tracking_no;若已有,仅更新不推进状态。
  • 运费不更新
    • 检查结算接口是否成功返回新的运费与订单总额。
    • 确认前端是否正确接收并渲染 shipping_fee 与 order_amount_format。
  • 地址显示为空
    • 核对 order_address 是否存在对应记录;后台详情组装会优先从此表取值。
  • 插件不可用
    • 检查插件 slug 与配置是否存在;ExpressService 会从插件配置读取 name/fee 等信息。

结论

DouPHP 的物流配送体系以“插件化物流公司 + 订单物流跟踪 + 结算运费重算”为核心,具备清晰的边界与可扩展性。通过后台表单校验与服务层事务化处理,确保物流状态与库存一致性;结合前端 AJAX 局部刷新提升用户体验。在此基础上,可通过插件扩展新物流公司、通过结算服务扩展复杂运费规则,并通过缓存与队列实现高并发与稳定性保障。

附录:开发示例与最佳实践

集成新物流公司(插件)

  • 步骤
    • 新建插件目录与 manifest,注册 slug 与配置项(name、fee 等)。
    • 实现 ExpressService 风格的 methods(),返回 id/name/desc/price。
    • 在结算流程中通过 plugin() 门面获取该物流公司并参与运费计算。
  • 参考路径
    • ExpressService.php:11-35

实现自定义运费计算规则

  • 思路
    • 在结算服务中依据 shipping_id、订单金额、优惠券金额计算运费。
    • 支持按区域、重量、件数、会员等级等维度差异化计费。
    • 将计算结果写回 Session/缓存,并在前端刷新显示。
  • 参考路径
    • CheckoutController.php(API):168-197
    • global.js(前端运费更新):97-113

处理物流异常情况

  • 常见异常
    • 物流公司接口超时/失败:进入队列重试,记录日志并告警。
    • 运单号格式错误:在表单层校验并提示修正。
    • 状态不同步:提供人工干预入口,支持补发状态与日志审计。
  • 参考路径
    • OrderService.php(后台订单服务):500-543

物流数据缓存与批量查询优化

  • 缓存策略
    • 物流公司配置与基础费率缓存(短 TTL)。
    • 热门区域运费模板缓存。
  • 批量优化
    • 订单列表批量拉取收货地址并映射。
    • 物流轨迹批量查询与去重。
  • 参考路径
    • OrderService.php(后台订单服务):96-200

物流监控告警

  • 指标
    • 发货成功率、轨迹查询成功率、平均耗时、失败率。
  • 告警
    • 连续失败阈值触发告警(邮件/IM)。
    • 慢查询与外部接口超时告警。
  • 落地
    • 在服务层埋点日志,结合监控系统(Prometheus/Grafana 或自建)采集与可视化。
添加日期:2026-10-05