前言
医院、餐厅、政务大厅、美容门店……排队等叫号是高频刚需场景。传统叫号机依赖现场取票,用户体验差、管理成本高。借助微信消息通道打通预约与叫号,能让用户远程取号、实时推送进度、自动叫号到场,真正做到"人不到场、号先到位"。本文从系统架构到核心代码,完整拆解微信预约排队叫号系统的对接方案,重点介绍如何通过 WechatApi 个人微信API 实现消息推送与交互。
一、系统架构与核心流程
微信预约叫号系统通常包含四个模块:预约入口、排队引擎、消息通道、叫号终端。
用户微信 ──→ 预约入口(公众号/小程序/个人微信) ──→ 排队引擎(后端队列)
│
┌──────────────┴─────────────┐
消息通道(WechatApi推送) 叫号终端(大屏/音响)
整个链路的关键瓶颈在于消息通道:如何把叫号进度实时推到用户微信?
常见方案对比如下:
| 通道方案 | 延迟 | 稳定性 | 对接复杂度 | 适用场景 |
|---|---|---|---|---|
| 公众号模板消息 | 秒级 | 高 | 中 | 已认证服务号 |
| 小程序订阅消息 | 秒级 | 高 | 中 | 已上线小程序 |
| 个人微信消息(WechatApi) | 秒级 | 高 | 低 | 无公众号/私域运营 |
| 短信通知 | 秒~分钟 | 中 | 低 | 兜底通道 |
对于大量中小商家、私立诊所、社区服务机构而言,申请认证服务号周期长、成本高。WechatApi 基于 iPad 协议实现个人微信的 HTTP API 化,无需公众号,直接用微信账号作为通知机器人,显著降低接入门槛。
二、预约取号:用户侧交互设计
用户预约的入口形式多样,常见的有:
- 微信好友私聊关键词触发:用户发送"预约"二字,系统自动回复取号结果。
- 微信群内指令取号:发送
/取号 牙科格式,机器人解析并入队。 - H5/小程序跳转后台:用户完成选择后,后台调用 WechatApi 向用户微信推送取号确认。
以好友私聊关键词触发为例,系统需要:
- WechatApi 接收用户消息(Webhook 回调)
- 后端解析关键词,向队列引擎申请号码
- 队列引擎返回队号和预计等待时间
- WechatApi 向用户推送取号成功消息
Webhook 接收示例(Python Flask):
pythonfrom flask import Flask, request, jsonify
import requests
app = Flask(__name__)
WECHAT_API_BASE = "https://your-wechat-api-endpoint"
VIDEOS_API_TOKEN = "YOUR_TOKEN_HERE"
APP_ID = "YOUR_APP_ID_HERE"
def send_wechat_message(to_user: str, content: str):
"""通过 WechatApi 发送个人微信消息"""
headers = {
"VideosApi-token": VIDEOS_API_TOKEN,
"Content-Type": "application/json"
}
payload = {
"appId": APP_ID,
"toUser": to_user,
"content": content
}
resp = requests.post(f"{WECHAT_API_BASE}/message/send", json=payload, headers=headers)
return resp.json()
@app.route("/wechat/callback", methods=["POST"])
def wechat_callback():
data = request.json
msg_type = data.get("msgType")
from_user = data.get("fromUser")
content = data.get("content", "").strip()
if msg_type == "text" and "预约" in content:
# 调用排队引擎取号
queue_result = apply_queue_number(from_user)
number = queue_result["number"]
wait_count = queue_result["waitCount"]
reply = (
f"您好!取号成功 🎫\n"
f"您的号码:{number}\n"
f"当前等待:{wait_count} 人\n"
f"预计等待:约 {wait_count * 5} 分钟\n"
f"轮到您时将自动通知,请保持微信在线。"
)
send_wechat_message(from_user, reply)
return jsonify({"ret": 200, "msg": "ok"})
def apply_queue_number(user_id: str) -> dict:
"""调用内部排队引擎接口(示意)"""
# 此处替换为真实队列服务调用
return {"number": "A088", "waitCount": 3}
if __name__ == "__main__":
app.run(port=8080)
三、排队引擎:队列状态管理
排队引擎是整个系统的核心,负责管理号段、维护等待队列、触发叫号事件。推荐用 Redis 实现轻量级队列,兼顾性能与持久化。
核心数据结构(Redis):
queue:{service_id}:counter:原子自增,生成队号queue:{service_id}:waiting:有序集合,score 为取号时间戳queue:{service_id}:current:当前服务号user:{user_id}:number:用户持有的号码
取号操作(Redis 原子性保证):
bash# 原子自增生成号码
INCR queue:dental:counter
# 将用户加入等待队列,score=当前时间戳
ZADD queue:dental:waiting 1718000000 "user_wxid_abc123"
# 存储用户号码映射
SET user:user_wxid_abc123:number "A088" EX 86400
叫号时,服务端从有序集合头部弹出用户,更新 current 计数器,并触发微信消息推送。
叫号触发推送(关键节点):
叫号的时机通常有两种:
- 前台手动叫号:工作人员点击叫号按钮,后台 API 触发推送。
- 自动轮转叫号:系统按固定间隔自动推进队列,适合流量平稳场景。
无论哪种方式,叫号推送消息应包含:队号、叫号时间、就诊/服务窗口、超时提醒规则。
四、消息推送:WechatApi 接口调用详解
叫号推送是整个系统中调用最频繁的接口。WechatApi 采用标准 HTTP POST + JSON 的调用范式,鉴权通过请求头 VideosApi-token 传入,业务参数中 appId 为设备 ID(即绑定的微信账号标识)。
叫号通知推送示例:
pythonimport requests
from datetime import datetime
def push_call_number_notification(to_user: str, number: str, window: str):
"""叫号通知推送"""
headers = {
"VideosApi-token": VIDEOS_API_TOKEN,
"Content-Type": "application/json"
}
call_time = datetime.now().strftime("%H:%M")
content = (
f"【叫号通知】\n"
f"请 {number} 号前往 {window} 窗口\n"
f"叫号时间:{call_time}\n"
f"⚠️ 请在 10 分钟内到达,逾期视为放弃,将重新排队。\n"
f"如需改约请回复"改约"。"
)
payload = {
"appId": APP_ID,
"toUser": to_user,
"content": content
}
resp = requests.post(
f"{WECHAT_API_BASE}/message/send",
json=payload,
headers=headers,
timeout=10
)
result = resp.json()
# 标准返回格式:{"ret": 200, "msg": "success", "data": {...}}
if result.get("ret") == 200:
print(f"叫号通知已推送至 {to_user},号码 {number}")
else:
print(f"推送失败:{result.get('msg')}")
return result
接口返回体格式:
json{
"ret": 200,
"msg": "消息发送成功",
"data": {
"msgId": "msg_20260613_001",
"toUser": "wxid_xxxxxxxx",
"sendTime": 1718000000
}
}
失败场景下 ret 会返回非 200 的错误码(如 401 鉴权失败、429 频率超限、500 服务异常),业务层需要做重试与告警处理。
五、进度查询:用户主动查号
用户在等待过程中,可能会主动查询当前进度。系统需要支持关键词回复触发查号,这同样通过 WechatApi 的消息回调实现。
查号交互逻辑:
| 用户发送 | 系统回复内容 |
|---|---|
| 查号 / 我的号 | 返回当前号码和前面等待人数 |
| 取消 / 弃号 | 从队列移除,回复取消成功 |
| 改约 | 引导用户重新选择时间段 |
| 进度 | 返回当前叫到的号码 |
查号回复模板建议简洁清晰:
【排队进度】
您的号码:A088
当前叫到:A084
前面还有:4 人
预计等待:约 20 分钟
回复"取消"可弃号重新排队
这类轻量交互完全不需要公众号,直接通过 WechatApi 的个人微信 iPad 协议 实现,接入成本极低,特别适合连锁门店、社区诊所等没有服务号的私域场景。
六、超时与异常处理机制
排队系统中,超时弃号和异常状态处理是保证体验的关键。
6.1 叫号超时自动弃号
叫号后若用户超时未到(通常设 5~15 分钟),系统应自动将该号标记为放弃,并推进队列。同时通过 WechatApi 发送弃号通知,告知用户可重新取号。
建议用定时任务(如 Celery Beat 或 APScheduler)扫描超时状态:
pythonfrom apscheduler.schedulers.background import BackgroundScheduler
scheduler = BackgroundScheduler()
@scheduler.scheduled_job('interval', seconds=60)
def check_timeout_numbers():
"""每分钟扫描超时叫号"""
import time
called_users = redis_client.zrangebyscore(
"queue:dental:called",
"-inf",
time.time() - 600 # 超过10分钟未到
)
for user_id in called_users:
# 移出队列
redis_client.zrem("queue:dental:called", user_id)
# 推送弃号通知
push_timeout_notice(user_id)
scheduler.start()
6.2 消息推送失败重试
网络抖动可能导致 WechatApi 推送失败,建议实现指数退避重试:
- 第 1 次失败:5 秒后重试
- 第 2 次失败:30 秒后重试
- 第 3 次失败:5 分钟后重试,同时触发短信兜底
6.3 设备离线检测
WechatApi 的 appId 对应一个登录中的微信设备,若设备离线(扫码退出、网络断开),需要立即告警运维人员重新登录,否则所有叫号推送将静默失败。可通过定时调用心跳检测接口感知设备状态。
七、私域增长:叫号流程中的运营埋点
叫号系统不只是工具,更是私域运营的流量入口。在不打扰用户体验的前提下,可以在以下节点做自然引导:
① 取号成功时:附带一句"等待期间可了解本月优惠活动",附 H5 链接。
② 叫号后:服务结束时发送满意度调查或复诊提醒,文字简短、一键回复。
③ 弃号时:主动推送"下次可提前预约,优先排队"的引导,提升预约率。
这类运营动作配合 WechatApi 的消息推送能力,能把原本一次性的排队行为转化为持续的用户触达机会,适合用 微信SCRM 场景做系统化沉淀。
对于需要管理多个门店、多个微信账号同时处理叫号推送的场景,WechatApi 支持多 appId 并发调用,每个门店配置独立的微信设备号,消息路由在后端按门店维度区分,互不干扰。
小结
微信预约排队叫号系统的核心链路清晰:用户取号 → 队列管理 → 到号推送 → 到场确认。其中消息推送是体验最关键的环节——消息到达及时、内容清晰、异常有兜底,才能让用户真正信任这套系统。
对于没有公众号或不想走复杂审核流程的场景,基于 WechatApi 个人微信 API 的对接方案是目前最轻量可行的路径:HTTP POST 标准接口、iPad 协议保障稳定性、多设备并发支持规模化部署,注册后即可在 控制台 获取 appId 和 token 开始调试,整体联调周期通常在 1~3 天内完成。
