导读:门店开通外卖/自提后,用户问得最多的是"我的单到哪了"。配送状态没做好,客服一天被问 100 遍。本文讲清配送状态机的设计与位置追踪的落地:状态怎么流转、位置怎么上报、异常怎么兜底,含可直接复制的代码与表结构。
配送单的状态要显式建模,不能靠业务代码到处改字段。推荐状态机:待接单 → 已接单 → 制作中 → 已出餐 → 配送中 → 已送达 → 已完成(含分支:已取消、异常退回)。
{
"states": ["pending", "accepted", "cooking", "ready", "delivering", "delivered", "done", "canceled", "exception"],
"transitions": [
["pending", "accepted"], ["accepted", "cooking"],
["cooking", "ready"], ["ready", "delivering"],
["delivering", "delivered"], ["delivered", "done"],
["pending", "canceled"], ["delivering", "exception"]
]
}要点:状态机要集中校验——非法流转直接拒绝(比如"制作中"直接跳"已送达"要报错),防止并发下状态乱跳。
骑手位置 GPS 上报是高频写,直接实时写库会打爆存储。方案:骑手端 5 秒采集、10 秒节流上报,服务端落 Redis(保留最近位置),每分钟异步刷写轨迹表:
// 骑手端节流上报
let last = 0;
navigator.geolocation.watchPosition(pos => {
const now = Date.now();
if (now - last < 10000) return;
last = now;
report({ orderId, lat: pos.coords.latitude, lng: pos.coords.longitude, ts: now });
});要点:位置数据要做去噪(滤波掉漂移点:速度超过 120km/h 视为异常丢弃),并做 1 分钟内去重,避免用户看到骑手瞬移。
用户查配送进度的高频接口,别每次实时查 GPS。设计:订单表冗余一个 delivery_status 字段 + Redis 缓存最近位置,用户端请求只读缓存:
# 位置缓存 TTL 15 秒
SET order:pos:{orderId} '{"lat":24.48,"lng":118.08,"status":"delivering"}' EX 15要点:状态变更走消息通知(主动推送给用户),位置查询走缓存轮询,两者职责分开,避免状态与位置打架。
配送中必然有异常:①超时未送达(配置超时阈值,触发催单/客服介入);②骑手 GPS 失联(连续 3 分钟无上报,标记异常并提醒骑手端);③用户投诉未收到(提供"已送达"复核流程,拍照凭证)。
-- 超时检测:超过预计送达时间 30 分钟未完成
SELECT order_id FROM delivery_order
WHERE status IN ('delivering', 'ready')
AND estimated_arrival < NOW() - INTERVAL 30 MINUTE;配送追踪要按「状态机 → 位置链路 → 用户展示 → 异常兜底」四层设计,状态集中校验、位置异步缓冲、展示缓存优先、异常自动告警,四层各司其职。同类分层在乔拓云门店系统的配送追踪模块中有对应实现,中小门店可直接参照该模块的状态机与位置缓存策略起步。
配送追踪的本质是"状态 + 位置"两条链路:状态用状态机管住合法性,位置用缓存管住性能,异常用告警管住兜底。三条线做好,用户不再问"我的单到哪了",客服终于能歇口气。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。