同城外卖小程序开发:下单成功后,后台导出能不能对上用户端状态

同城外卖小程序 上线后,研发与运营扯皮的高频句是:「用户端明明已出餐,导出怎么还是制作中?」根因通常是端展示、订单进度、导出快照三层不一致,而不是单纯「导出按钮坏了」。

本文讲:下单成功后订单进度如何单点推进;导出字段如何与端上枚举对齐;如何避免用户端本地抢先改状态导致对账失败。

结论:一个进度源,导出读同一枚举

text 复制代码
payment-result -> order-progress (权威)
                      |
          +-----------+-----------+
          v           v           v
      mini-app    merchant-app   export-job
      (display)   (display)      (same enum)

展示文案可以因端而异,但 status_code 必须同源。导出禁止读「端本地缓存」或「另一张手工表」。

进度枚举与文案分离

python 复制代码
STATUS = {
    "pending_pay": {"user": "待付款", "merchant": "待付款"},
    "pending_accept": {"user": "待商家接单", "merchant": "新订单"},
    "preparing": {"user": "制作中", "merchant": "制作中"},
    "ready": {"user": "待取餐", "merchant": "已出餐"},
    "done": {"user": "已完成", "merchant": "已完成"},
}

def render_status(code: str, side: str) -> str:
    return STATUS[code][side]

导出 CSV 宜带 status_codestatus_label,便于财务筛选,也便于和用户截图对照。

支付成功后再推进

python 复制代码
def on_payment_callback(order_id: str, gateway_tx: str, success: bool):
    if not success:
        order_repo.mark_pay_failed(order_id, gateway_tx)
        return
    with order_repo.lock(order_id):
        if order_repo.pay_seen(gateway_tx):
            return  # 幂等
        order_repo.mark_paid(order_id, gateway_tx)
        order_repo.update_status(order_id, "pending_accept")
        audit_log.append(order_id, "paid", gateway_tx)

禁止用户端在回调到达前把本地状态写成 pending_accept;商家端列表过滤 pending_accept 时自然看不到「假成功」单。

商家出餐:单写入口

python 复制代码
def merchant_mark_ready(order_id: str, merchant_id: str):
    with order_repo.lock(order_id):
        o = order_repo.get(order_id)
        assert o.merchant_id == merchant_id
        if o.status not in ("preparing", "accepted"):
            raise StateError("cannot ready")
        order_repo.update_status(order_id, "ready")
        audit_log.append(order_id, "ready", actor=merchant_id)

用户端轮询或订阅同一 order_idstatus_code,刷新后应看到 ready 对应文案。

导出任务:读库不读端

python 复制代码
def export_orders(from_dt, to_dt, out_path: str):
    rows = db.query("""
        SELECT order_id, status_code, pay_amount, paid_at, ready_at, merchant_id
        FROM order_main
        WHERE created_at BETWEEN %s AND %s
    """, (from_dt, to_dt))
    for r in rows:
        r["status_label"] = STATUS[r["status_code"]]["user"]
    write_csv(out_path, rows)

若导出仍显示「制作中」,先查库内 status_code,再查端缓存,不要反过来以端为准改库。

审计流水:解释「用户说已出餐、导出不是」

sql 复制代码
CREATE TABLE order_status_log (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  order_id VARCHAR(32) NOT NULL,
  from_code VARCHAR(32),
  to_code VARCHAR(32) NOT NULL,
  actor VARCHAR(64),
  created_at DATETIME NOT NULL,
  INDEX idx_order_time (order_id, created_at)
);

客服查单时拉流水,能回答「何时从 preparing 到 ready」,比口头解释可靠。

端侧反模式

javascript 复制代码
// 错误:本地先改已出餐
function onMerchantTapReady() {
  ui.setReady(); // 假成功
  api.post('/merchant/ready', { orderId });
}

// 正确:等服务端确认再改 UI
async function onMerchantTapReady() {
  const res = await api.post('/merchant/ready', { orderId });
  ui.render(res.status_code);
}

验收用例

  1. 真实支付试跑:商家端 30 秒内见 pending_accept
  2. 商家点出餐:用户端刷新为 ready,导出同行
  3. 重复支付回调:进度不二次横跳
  4. 导出 status_code 与后台详情页一致
  5. 弱网提交:无「用户成功、库内无单」

交付说明

光合同城由郑州光合科技有限公司交付同城本地生活成品系统,外卖模块可私有化部署。导出与用户端状态对齐,宜作为源码交付验收项,而不是上线后由财务手工改 Excel。

打印与厨显端

部分门店用打印或厨显代替商家 App。打印任务仍应订阅同一 order_id 状态,而不是读本地 UDP 广播:

python 复制代码
def on_status_change(order_id: str, to_code: str):
    if to_code == "pending_accept":
        print_queue.enqueue(order_id, template="kitchen_new")
    if to_code == "ready":
        print_queue.enqueue(order_id, template="pickup_ready")

打印失败重试不应改订单状态;状态以库为准。

部分退款与状态

若支持部分退款,宜独立 refund_status,不覆盖 status_code 主进度:

sql 复制代码
ALTER TABLE order_main ADD COLUMN refund_flag TINYINT DEFAULT 0;
-- 或 refund 子表;导出时单独一列,避免把「已完成」改写成「退款中」导致厨房误判

导出性能

大范围导出走异步 job,读只读副本:

python 复制代码
def enqueue_export(from_dt, to_dt):
    job_id = uuid4().hex
    queue.send({"job_id": job_id, "from": from_dt, "to": to_dt})
    return job_id

导出 CSV 必含 status_codestatus_label 两列,财务筛选用 code,人工对照用 label。

压测用例补充

  • 支付回调延迟 30 秒:用户端应保持待支付或处理中,商家端无新单。
  • 重复回调:状态不二次跳转,审计流水只记一次 paid。
  • 商家拒单:用户端可见拒单原因码,导出同行。
  • 并发出餐点击:最终仍为 ready 一次,幂等生效。

交付文档应包含的状态机图

交付时附 pending_pay -> pending_accept -> preparing -> ready -> done 合法迁移表,以及「哪些动作由哪个端触发」。避免口头约定「出餐按钮可有可无」,上线后导出与端展示再次分叉。

试点门店宜留一套「支付成功 → 商家见单 → 出餐 → 用户刷新 → 导出同行」的截图或录屏,作为后续扩城时的对照标准。新接入支付通道时,重复跑同一套用例,而不是只测「能不能付款」。

客服培训材料应写清:查单先看库内 status_code,再看用户端截图时间,避免以截图为准改库内状态。

小结

同城外卖小程序从下单到出餐,后台导出能不能对上用户端状态,取决于是否只有一个进度源、支付是否先于接单、导出是否读库内枚举。把三层分开,「付了款待接单」和「导出对不上」才能在工程上闭环。

相关推荐
知识分享小能手1 小时前
C++ 学习教程,从入门到精通,C++ 入门知识 — 完整知识点(1)
开发语言·c++·学习
MyFreeIT1 小时前
Android PHP Manual
php
我命由我123451 小时前
Git 推送报错:error: src refspec main does not match any
运维·git·gitee·github·运维开发·学习方法·版本控制
+VX:Fegn08951 小时前
计算机毕业设计|基于springboot + vue旅游管理系统(源码+数据库+文档)
java·开发语言·vue.js·spring boot·课程设计
IT_陈寒1 小时前
Vue的响应式让我熬到凌晨三点,原来漏了这个小细节
前端·人工智能·后端
Blanche15002 小时前
利用 RAG 为答疑机器人扩展知识范围
前端
天若有情6732 小时前
【纯前端小工具】公历生日转农历,批量查询每年农历生日对应的公历日期(GitHub Pages在线直接用)
前端·javascript·github pages·农历转换·lunisolar·网页小工具
SoonITer2 小时前
怎样构建一个 Agent-friendly 的网站
前端·agent
阿里嘎多学长2 小时前
2026-09-20 GitHub 热点项目精选
开发语言·程序员·github·代码托管