订单状态图指南

订单状态图是什么、一条订单流程该有哪些状态,以及三张可以直接改的模板:电商、SaaS 订阅、外卖。

发布于 ·8 分钟阅读
order-statusstate-diagramecommercetemplate

一、什么是订单状态图

订单状态图 画的是一张订单一生的状态:它可能处于哪些状态,以及什么事件会把它从一个状态推到下一个。它回答两个文档写不清楚的问题 —— 一共有哪些状态,和 哪个状态之后能接哪个

关键区别在于:订单状态图画的是 状态,不是步骤。步骤是有人做的事(「打包」),状态是订单待着的那个处境,一直待到有事发生为止(「处理中」)。订单一生大部分时间都在待着 —— 等付款到账、等快递揽收、等退货期结束。画状态能把这些等待显出来,画步骤会把它们藏起来。

大部分团队其实已经有这张图了,只是没画出来。它散在一个 enum、一个 status 字段、和十几处 if 里。这几处一旦对不上 —— 接口说 SHIPPED,邮件表里写 in_transit,客服话术叫「已发出」—— 就会出一批谁也复现不了的 bug。把状态摆到一页纸上,是在客户之前先发现这种对不上的唯一办法。

顺手的画法是 Mermaid 的 stateDiagram-v2:方框是状态,箭头是流转,箭头上的字是触发它的事件。

二、订单流程里的常见状态

几乎所有行业的订单流程,都是同样 5 个状态加 1 个逃生口的变体:

  • 待支付(Pending) —— 订单已经存在,但钱还没到位。这一步还没有任何实际动作发生。超时逻辑住在这里。
  • 已确认(Confirmed) —— 付款已授权、库存已锁定。承诺从这一刻起是双向的。
  • 处理中(Processing) —— 有人在实际处理它:拣货、打包、打面单。
  • 已发货(Shipped) —— 东西已经离开你的控制,在承运商手里。你只能观察,不能干预。
  • 已送达(Delivered) —— 客户拿到了。注意这在多数生意里 不是 终态 —— 退货和退款都在它后面。
  • 已取消(Cancelled) —— 逃生口。从好几个地方都能到达,而且来路不同、原因不同(支付超时 / 客户主动取消 / 缺货)。

这就是那个骨架。它是刻意画到最小的 —— 从它开始,只有当你能说清「什么事件会到达这个状态」时才往上加。

看 Mermaid 源码
stateDiagram-v2
    [*] --> Pending
    Pending --> Confirmed: payment authorized
    Confirmed --> Processing: warehouse picks up
    Processing --> Shipped: handed to carrier
    Shipped --> Delivered: customer signs
    Delivered --> [*]
    Pending --> Cancelled: payment failed or timeout
    Confirmed --> Cancelled: customer cancels
    Cancelled --> [*]
最小的订单状态图:待支付、已确认、处理中、已发货、已送达,以及从待支付和已确认都能到达的已取消。

三、订单状态图怎么画

三步。前两步是想,第三步才是动手。

第 1 步 · 把状态列全

别靠头脑风暴。去读 enum、读 status 字段、读你们发出去的那些交易邮件。这三处才是系统 真实 拥有的状态,而且它们通常互相对不上 —— 这个对不上就是这件事第一份价值。

然后对每个候选状态套一个判断:订单能在这里一直待着吗? 能待就是状态;如果总是毫秒级穿过去,那是步骤,该写在箭头上而不是画成方框。「扣款中」不是状态,「待支付」才是。

留意几个团队反复忘掉的状态:退款中(钱在路上,订单既没完成也没取消)、部分发货(多商品订单)、包裹丢失(承运商不再扫码了)、风控挂起。每一个漏画的,后面都会变成一批工单。

第 2 步 · 定义流转

每条箭头上写触发它的 事件,而不是结果状态。Pending --> Confirmed: 支付已授权 是有用的,Pending --> Confirmed: 确认 是句废话。

画完之后跑三遍检查:

可达性。 每个状态至少有一条进来的箭头,而且从 [*] 出发都能走到。走不到的状态就是 status 枚举里的死代码。

终止性。 每个状态要么能往下走,要么明确是终态(--> [*])。一个出不去的状态意味着订单永远卡在那里 —— 这是这张图能抓到的、最常见的一个真 bug。

没有隐藏的回边。 如果客服能把订单从 已发货 退回 处理中,就把那条箭头画出来。没画出来的后台操作,正是状态机烂掉的方式。

第 3 步 · 画出来

把状态和流转当普通句子写出来,让 text2diagram 去排版 —— 你写「订单初始是待支付,支付授权后变成已确认,然后是处理中、已发货、已送达;待支付和已确认状态下都可以取消」,它会还给你一段可以直接改的 stateDiagram-v2

或者干脆不用打字:本页任何一张图都能一键在编辑器里打开,然后把状态名换成你自己的。这通常比从空白画布开始快 —— 费脑子的是图的形状,不是里面的词。

四、三张真实场景的订单状态图

三个真实形状。同一个六状态骨架,一旦业务具体起来,弯法完全不同。

例 1 · 电商订单

这里的复杂性全在 送达之后已送达 是个中途站,不是终点:退货、退款、丢件理赔要么从它分出去,要么从 已发货 分出去。把 已送达 当终态的团队,最后都在状态机外面用表格处理退款。

看 Mermaid 源码
stateDiagram-v2
    [*] --> Pending
    Pending --> Confirmed: payment captured
    Pending --> Cancelled: 30 min timeout
    Confirmed --> Processing: stock reserved
    Confirmed --> Refunding: customer cancels
    Processing --> Shipped: tracking number issued
    Shipped --> Delivered: proof of delivery
    Shipped --> Lost: no scan for 14 days
    Delivered --> ReturnRequested: within 7 days
    ReturnRequested --> Refunding: return received
    Refunding --> Refunded: money back
    Lost --> Refunding: claim approved
    Delivered --> [*]
    Refunded --> [*]
    Cancelled --> [*]
电商订单状态图,覆盖支付超时、库存锁定、发货、丢件、退货和退款。

例 2 · SaaS 订阅生命周期

订阅是一张永不结束的订单,所以电商图里是直线的地方,它是 逾期未付 --> 生效中(催收重试成功)和 已取消 --> 生效中(挽回)是最常被漏掉的两条箭头,而它们恰好是增长团队最关心的两条。

还要注意 取消中已取消 是两个状态:用户已经提了退订,但付费周期结束前访问权还在。把这两个并成一个,就是「客户明明付到月底却被提前掐掉」的成因。

看 Mermaid 源码
stateDiagram-v2
    [*] --> Trialing
    Trialing --> Active: card charged
    Trialing --> Expired: trial ends, no card
    Active --> PastDue: renewal payment fails
    PastDue --> Active: retry succeeds
    PastDue --> Cancelled: 3 retries fail
    Active --> Cancelling: user cancels
    Cancelling --> Active: user resubscribes
    Cancelling --> Cancelled: period ends
    Cancelled --> Active: user comes back
    Expired --> [*]
    Cancelled --> [*]
SaaS 订阅生命周期图,包含试用、生效、逾期催收重试、取消宽限期和挽回。

例 3 · 外卖订单

这张图有两点不一样。一是有 三方 —— 顾客、商家、骑手 —— 好几次流转的触发者既不是买家也不是你的系统。二是整件事 40 分钟内跑完,顾客是盯着状态实时变化的,任何一个没写清楚的状态都是一通客服电话。

商家拒单 值得单开一个方框,而不是并进 已取消:钱已经付了、说不的是商家,退款路径和话术都不一样。

看 Mermaid 源码
stateDiagram-v2
    [*] --> Placed
    Placed --> Accepted: restaurant confirms
    Placed --> Rejected: restaurant is closed or busy
    Accepted --> Preparing: kitchen starts
    Preparing --> ReadyForPickup: food is bagged
    ReadyForPickup --> PickedUp: courier collects
    PickedUp --> Delivered: handed to customer
    PickedUp --> Undeliverable: nobody answers
    Rejected --> [*]
    Delivered --> [*]
    Undeliverable --> [*]
外卖订单状态图,包含商家接单、后厨制作、骑手取餐,以及无法送达的分支。

图和 enum 要在同一个 PR 里改

订单状态图只有在保持为真的时候才值得画。这里的源码就是一段 Mermaid 纯文本,所以实际做法是把它和拥有 status 枚举的那份代码放在一起,改状态时同一个改动里一起改。落后一个版本的图比没有图更糟,因为大家会信它。

常见问题

接着读

去试试 text2diagram

打开工具
← 回到全部教程