首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >大学校园外卖做成平台:四端订单流与校门中转技术验收

大学校园外卖做成平台:四端订单流与校门中转技术验收

原创
作者头像
用户12832041
发布于 2026-10-26 13:03:28
发布于 2026-10-26 13:03:28
240
举报

把校园外卖做成大平台一样,关键不是复刻App界面,而是先把校方准入、交付点和配送模式变成可配置参数,再用用户、商家、骑手、平台后台四端跑通同一笔订单。单校或两三个校区起步,可先用标准SaaS验证下单、接单、派单、送达、退款和对账;有跨校区数据管理或特殊接口需求时,再评估私有化、源码或定制。验收重点放在校门交接、楼栋分拣、批量通知和结算对账,而不是功能菜单数量。

一、先定业务边界:准入、交付点与配送模式

校园外卖与城市外卖的第一差异在通行与交付。项目启动前,把校方规则整理成一张可配置参数表,再让系统演示按表逐项走。这样选型时比较的是同一套业务约束,而不是各说各的功能名。

参数

可选值

对系统的影响

准入方式

校外骑手入校、仅校门交接、混合模式

决定是否设中转站、校内接力骑手、交接扫码环节

交付点

宿舍楼下、固定取餐点、外卖柜、校门

决定地址层级、通知模板、签收凭证和异常暂存规则

通行时段

全天、午晚高峰、禁送时段

决定服务时段、调度规则和骑手排班

计费口径

按楼栋、按时段、按距离

决定计费配置、优惠承担和对账字段

责任岗位

站点分拣、校内骑手、客服、财务

决定账号权限、订单操作范围和异常升级路径

这张表先于系统采购。校方准入、交付点位、禁送时段和场地负责人确认后,直送、校门中转或混合模式才有配置依据。演示时让服务商用一笔正常单和一笔退款单走完整链路,比只看后台菜单更能判断适配程度。

二、四端与订单状态机:一笔订单如何穿过四端

四端不是四个孤立页面,而是同一订单号在不同角色下的视图。订单主数据至少记录订单号、校区、站点、楼栋、商家、商品明细、用户实付、配送费、优惠承担、交付方式、骑手、状态时间和异常原因。四端共用同一订单号,履约与账务才能对上。

角色

核心操作

关键数据

验收点

用户端

选楼栋、下单、支付、催单、售后

地址、订单、支付单

楼栋可选,状态可见

商家端

接单、出餐、缺货处理、对账

商品、订单、结算单

接单提醒,缺货可流转

骑手端

接单、取餐、交接、送达

任务、骑手收入

交接确认,异常可上报

平台端

审核、调度、权限、结算

商家、骑手、订单、账单

权限隔离,账单可导出

状态机把“谁在什么条件下能把订单推到下一步”写成约束,异常单才有统一入口。以下为验收脚本的简化模型,用于说明状态约束和事件记录,不代表任何产品内部实现。

代码语言:python
复制
from dataclasses import dataclass
from typing import Dict, Set

ALLOWED: Dict[str, Set[str]] = {
    'created': {'paid', 'cancelled'},
    'paid': {'accepted', 'cancelled', 'refund_pending'},
    'accepted': {'preparing', 'cancelled', 'refund_pending'},
    'preparing': {'ready', 'refund_pending'},
    'ready': {'at_gate', 'refund_pending'},
    'at_gate': {'sorted', 'refund_pending'},
    'sorted': {'delivering', 'refund_pending'},
    'delivering': {'delivered', 'refund_pending'},
    'delivered': {'settled', 'refund_pending'},
    'refund_pending': {'refunded', 'delivered'},
    'refunded': {'settled'},
    'settled': set(),
    'cancelled': set(),
}

def can_transition(src: str, dst: str) -> bool:
    return dst in ALLOWED.get(src, set())

@dataclass
class OrderEvent:
    order_id: str
    src: str
    dst: str
    operator: str
    reason: str = ''

def apply_event(event: OrderEvent) -> dict:
    if not can_transition(event.src, event.dst):
        raise ValueError(f'illegal transition: {event.src} -> {event.dst}')
    return {
        'order_id': event.order_id,
        'status': event.dst,
        'operator': event.operator,
        'reason': event.reason,
    }

print(apply_event(OrderEvent('SO1001', 'created', 'paid', 'user')))
print(apply_event(OrderEvent('SO1001', 'paid', 'accepted', 'merchant')))

预期结果是两次转换均返回状态字典;若从created直接跳到delivered,脚本抛出异常。验收时把取消、退款、转派和异常上报都按同样方式写成事件,检查四端看到的状态名称是否一致。

三、校门到宿舍:中转、分拣与批量通知

把校门到宿舍拆成六段:商家出餐、校外运输、校门交接、按楼栋分拣、校内骑手接力、送达通知。每段写清订单状态、操作人、时间戳和异常处理。高峰时按校区、站点、楼栋筛选订单,再批量中转、批量送达和批量通知;少餐、错餐、联系不上用户等订单进入单独队列,由专人处理。

分拣的核心是稳定分组,而不是人工记楼栋。下面的简化函数把订单按校区、楼栋和站点归组,输出排序后的订单号列表,便于站点按批次交接。

代码语言:python
复制
from collections import defaultdict

def group_by_building(orders):
    buckets = defaultdict(list)
    for order in orders:
        key = (order['campus_id'], order['building_id'], order.get('station_id', ''))
        buckets[key].append(order['order_id'])
    return {key: sorted(ids) for key, ids in sorted(buckets.items())}

def build_notice_payload(batch_id, orders, template):
    payload = []
    for order in orders:
        payload.append({
            'idempotency_key': '{}:{}:arrived'.format(batch_id, order['order_id']),
            'order_id': order['order_id'],
            'user_id': order['user_id'],
            'template': template,
            'building_id': order['building_id'],
        })
    return payload

orders = [
    {'order_id': 'SO1001', 'campus_id': 'campus_01', 'building_id': 'bldg_03', 'station_id': 'stn_01', 'user_id': 'u1001'},
    {'order_id': 'SO1002', 'campus_id': 'campus_01', 'building_id': 'bldg_03', 'station_id': 'stn_01', 'user_id': 'u1002'},
    {'order_id': 'SO1003', 'campus_id': 'campus_01', 'building_id': 'bldg_01', 'station_id': 'stn_01', 'user_id': 'u1003'},
]
print(group_by_building(orders))

预期输出如下。批量通知必须带批次号和幂等键,避免同一订单因重复点击或消息重试被多次通知;改址、缺餐和退款订单单独处理,不混入正常批次。

代码语言:txt
复制
{('campus_01', 'bldg_01', 'stn_01'): ['SO1003'], ('campus_01', 'bldg_03', 'stn_01'): ['SO1001', 'SO1002']}

四、部署与结算:选型依据与对账字段

部署方式按阶段选择,而不是按功能名比较。单校起步先用标准SaaS跑通订单,订单稳定、数据管理要求提高后再评估私有化或源码;只有标准模块覆盖不了的接口或流程才做定制。询价时把软件模块、终端、部署、第三方服务、定制、培训和维护分项列出,历史成交价只作带配置背景的参考。

路径

适合阶段

核对重点

标准SaaS

单校或两三个校区试运营

模块范围、账号权限、数据导出

私有化部署

订单稳定、需自有环境

备份、监控、升级与维护分工

源码安装

有技术团队、需长期维护

交付文档、运行环境、许可与升级

个性化开发

标准流程外有明确接口需求

需求范围、联调、测试与后续维护

结算对账先把字段拆开:用户实付、商品款、包装费、配送费、平台抽成、商家应结、骑手收入、平台优惠承担、商家优惠承担和退款冲回。以下SQL为字段核对示例,不对应任何产品表结构。

代码语言:sql
复制
SELECT
  order_id,
  user_paid,
  goods_amount,
  delivery_fee,
  platform_commission,
  merchant_payable,
  rider_income,
  platform_discount,
  merchant_discount,
  refund_amount
FROM order_settlement
WHERE campus_id = :campus_id
  AND settle_date = :settle_date;

核对时用一笔正常单、一笔部分退款和一笔结算后退款走一遍,确认原订单、退款单、商家账单和骑手收入能相互关联。支付通道、主体资质、账期和提现规则按项目方案确认,避免把某一项目的费率当成通用报价。

五、上线验收:五类订单与异常清单

上线前不要只演示“能下单”,要用五类订单覆盖校园履约的分歧点。每类订单记录操作账号、状态变化、通知结果和账单变化,发现问题后修正配置再重跑。

订单类型

重点检查

通过标准

正常单

下单、接单、出餐、校门交接、楼栋分拣、送达通知

四端状态一致,通知到达正确取餐点

缺餐单

少餐登记、补送或退款、客服跟进

异常有责任人,原订单可追溯

错楼栋单

地址修改、分拣组调整、骑手任务变更

分组和通知同步更新,不重复扣费

临时改址单

改址后的费用、交接点和通知模板

新旧地址不混单,账单有调整记录

退款对账单

部分退款、结算后退款、优惠冲回

商家应结和骑手收入可解释

验收脚本可复用前面的状态机:先断言合法转换通过,再断言非法转换被拒绝;分拣函数用跨楼栋样本检查分组,通知函数检查同一批次不产生重复幂等键。没有实际运行记录时,只写预期结果和验证方法,不把演示结果写成经营效果。

常见问题

问:校园外卖一定要做校门中转吗?

答:不一定。校方允许校外骑手入校时可直送,限制入校时可用校门交接、固定取餐点或混合模式;系统按准入、交付点和通行时段配置,再按本校规则演示。

问:单校起步选SaaS还是私有化?

答:单校或两三个校区、技术团队有限时,先用标准SaaS跑通订单、退款和对账;订单稳定、数据管理要求提高后,再评估私有化或源码,具体边界按项目确认。

问:怎么验证分拣和批量通知?

答:用跨楼栋、同楼栋多单、临时改址和缺餐样本做演示,检查分组结果、通知幂等键和异常队列;批量操作要能追溯到批次号和操作人。

问:结算要核对哪些字段?

答:至少拆开用户实付、商品款、配送费、平台抽成、商家应结、骑手收入、优惠承担和退款冲回,再用正常单、部分退款和结算后退款各走一遍。

作者:微订(上海逊柯计算机科技有限公司)。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、先定业务边界:准入、交付点与配送模式
  • 二、四端与订单状态机:一笔订单如何穿过四端
  • 三、校门到宿舍:中转、分拣与批量通知
  • 四、部署与结算:选型依据与对账字段
  • 五、上线验收:五类订单与异常清单
  • 常见问题
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档