ZhctTrayBindingMachine 接口文档
文档日期:2026-08-20
源码项目:/Users/liang/AndroidStudioProjects/ZhctTrayBindingMachine
源码快照:分支add_swipe_card_rule,提交78e2694fdc32de0c89a27c1268b27eab87e851cc
依据:当前客户端源码静态扫描;未连接后端、第三方平台或真实设备进行联调
敏感信息:本文不记录源码中的密钥、Token、Webhook 完整地址或人员数据
1. 文档范围与结论
本项目的网络接入分为四类:
- 绑盘机业务 REST 接口:Retrofit 定义了 21 个方法声明、18 个唯一请求路径,全部为
POST。 - 第三方及运维 HTTP 接口:百度 OAuth、人脸特征提取、企业微信群机器人、阿里云 RUM、阿里云 SLS。
- 非 HTTP 通道:阿里云 MQTT,用于接收人员/人脸增量数据。
- 动态资源访问:人员头像图片和 APK 下载地址。
按当前源码调用点统计,18 个业务 REST 路径中:
- 9 个已接入当前业务流程:人员列表、人盘绑定、设备配对、心跳、硬件日志、人脸数据同步、MQTT 反馈、设备启动初始化、版本检查。
- 9 个仅有 Retrofit 定义,未发现业务调用点:排菜列表、菜品详情、取餐上传、餐盘反查人员、当餐营养、菜品库列表、添加菜谱、餐厅餐段、删除菜谱。
“仅定义”不等于后台接口已下线,只表示本源码快照中没有发现对相应方法的调用。
2. 通用约定
2.1 服务地址
| 项目 | 当前客户端行为 |
|---|---|
| 默认 Base URL | https://zhctdev.yyangpt.cn |
| 可配置地址 | 基础设置页可写入 SETTING_API_ADDRESS,运行时重建 Retrofit |
| 地址校验 | 接受 http:// 或 https:// 开头的地址 |
| 业务路径前缀 | /p/api/ |
| 连接/读/写超时 | 均为 20 秒 |
最终请求地址为:{Base URL}{接口路径}。生产、测试或客户环境的真实 Base URL 以设备基础设置为准。
2.2 请求格式
- 标注
@FormUrlEncoded的接口使用application/x-www-form-urlencoded。 - 标注
@Body的接口由 Gson 序列化为 JSON。 - 当前 OkHttp 拦截器未增加
Authorization、签名或其他业务认证请求头,只检查本机网络是否可用并记录请求/响应日志。
2.3 通用响应
除 getStaffListNew 的原始字符串变体外,业务接口统一按以下结构解析:
{
"code": 0,
"message": "",
"data": {}
}
| 字段 | 类型 | 说明 |
|---|---|---|
code |
int | 业务状态码;客户端调用点普遍以 0 判断成功 |
message |
string | 业务提示或失败原因 |
data |
object / array / null | 具体响应数据 |
客户端本地网络错误码:
| 错误码 | 含义 |
|---|---|
1000 |
网络错误 |
10001 |
当前网络不可用 |
20000 |
网络读写异常 |
20002 |
连接超时 |
注意:ApiResultUtils 在服务端 data == null 时会重新构造 code = 0 的空结果,可能覆盖服务端原始非零业务码;接口联调和故障定位时应同时检查原始 HTTP 响应。
3. 业务 REST 接口总表
| # | 方法 | 路径 | 格式 | 当前状态 | 主要调用位置 |
|---|---|---|---|---|---|
| 1 | POST | /p/api/getStaffLists |
Form | 已调用 | StaffListManager |
| 2 | POST | /p/api/bindPlate |
JSON | 已调用 | 两个绑定结果 Fragment |
| 3 | POST | /p/api/matecode |
Form | 已调用 | SetBasicFragment |
| 4 | POST | /p/api/heartbeat |
Form | 已调用 | HeartBeatWorker |
| 5 | POST | /p/api/hardware_log |
JSON | 已调用 | HomeActivity |
| 6 | POST | /p/api/facedata |
Form | 已调用 | FaceDataUpdaters |
| 7 | POST | /p/api/feedback |
Form | 已调用 | MqttSimple |
| 8 | POST | /p/api/equipmentStart |
Form | 已调用 | HomeActivity |
| 9 | POST | /p/api/getNewVersion |
Form | 已调用 | SetBasicFragment |
| 10 | POST | /p/api/getMeal |
JSON / Form | 仅定义 | 未发现调用点 |
| 11 | POST | /p/api/find |
JSON | 仅定义 | 未发现调用点 |
| 12 | POST | /p/api/ZpPushMeal |
Form | 仅定义 | 未发现调用点 |
| 13 | POST | /p/api/selectPlate |
Form | 仅定义 | 未发现调用点 |
| 14 | POST | /p/api/currentMealNutrition |
Form | 仅定义 | 未发现调用点 |
| 15 | POST | /p/api/CaterList |
Form | 仅定义 | 未发现调用点 |
| 16 | POST | /p/api/addRecipe |
Form | 仅定义 | 未发现调用点 |
| 17 | POST | /p/api/getRestaurantsInfo |
Form | 仅定义 | 未发现调用点 |
| 18 | POST | /p/api/delRecipe |
Form | 仅定义 | 未发现调用点 |
4. 当前业务流程已调用接口
4.1 获取人员列表
POST /p/api/getStaffLists
用途:分页拉取人员与人脸数据,保存到本地人脸库。
请求格式:application/x-www-form-urlencoded
| 参数 | 类型 | 必填性(按客户端) | 说明 |
|---|---|---|---|
page |
string | 是 | 当前页,从 1 开始 |
page_size |
string | 是 | 每页数量;当前调用固定为 10 |
update_time |
string | 否 | 增量更新时间;当前全量流程传空字符串 |
响应 data:
| 字段 | 类型 | 说明 |
|---|---|---|
total |
int | 总人数 |
page_size |
string | 每页数量 |
current_page |
string | 当前页 |
last_page |
int | 最后一页 |
data |
StaffInfo[] |
人员列表 |
StaffInfo 主要字段:id、uuid、name、sex、is_show、department_uuid、department_name、head_img、head_uuid、feature、face_token、create_time、update_time、hard_ware_img。
补充:同一路径还定义了返回原始 String 的 getStaffListNew,但未发现业务调用点。
4.2 人盘绑定
POST /p/api/bindPlate
用途:通过人脸、二维码或刷卡身份,将人员与餐盘绑定。
请求格式:application/json
{
"staff_uuid": "人员 UUID,刷脸模式使用",
"plate_code": "餐盘码",
"equipment_code": "设备编号",
"qr_code": "二维码/消费码,扫码模式使用",
"card_id": "卡号,刷卡模式使用"
}
| 参数 | 类型 | 必填性(按源码注释/调用) | 说明 |
|---|---|---|---|
plate_code |
string | 是 | 餐盘编号 |
equipment_code |
string | 是 | 设备编号 |
staff_uuid |
string | 条件必填 | 刷脸模式身份字段 |
qr_code |
string | 条件必填 | 扫码模式身份字段 |
card_id |
string | 条件必填 | 刷卡模式身份字段 |
客户端没有在请求模型层强制“身份字段三选一”,实际空值处理依赖调用流程和后台校验。
响应 data:
| 字段 | 类型 | 说明 |
|---|---|---|
balance |
string / null | 汇总余额;客户端遇到 -- 时隐藏余额区域 |
cash_balance |
string / null | 现金余额 |
subsidy_alance |
string / null | 补贴余额;字段名在协议中缺少字母 b,客户端按该拼写解析 |
bind_time |
string | 绑定时间 |
staff_name |
string | 人员姓名 |
staff_uuid |
string | 人员 UUID |
hard_ware_img |
string | 人员图片候选字段 1 |
head_img_url |
string | 人员图片候选字段 2 |
head_img |
string | 人员图片候选字段 3 |
staff_img |
string | 人员图片候选字段 4 |
客户端头像取值优先级:hard_ware_img → head_img_url → head_img → staff_img。
4.3 使用配对码获取设备配置
POST /p/api/matecode
用途:校验配对码,并下发设备编号、商户/餐厅信息、MQTT 参数和企业微信机器人地址。
请求格式:application/x-www-form-urlencoded
| 参数 | 类型 | 必填性 | 说明 |
|---|---|---|---|
matecode |
string | 是 | 配对码;客户端要求长度至少 6 位 |
响应 data:
| 字段 | 类型 | 说明 |
|---|---|---|
matecode |
string | 服务端返回的配对码,客户端忽略大小写比对 |
code |
string | 终端设备编号 |
communicationkey |
string | 通信密钥;当前配对成功流程未发现持久化使用 |
business_name |
string | 商户名称 |
restaurant_id |
string | 餐厅 ID |
restaurant_name |
string | 餐厅名称 |
ali_mqtt |
object | MQTT 配置 |
robot |
object / null | 企业微信机器人配置 |
ali_mqtt 字段:accessKey、secretKey、endPoint、instanceId、topic、groupId、deviceId。其中密钥属于敏感数据,本文不记录实际值。客户端实际组装 clientId = groupId + "@@@" + terminalCode,未使用响应中的 deviceId。
robot 字段:
| 字段 | 客户端用途 |
|---|---|
webhook |
报警机器人地址 |
msg |
通知机器人地址 |
main |
主流程分级告警机器人地址 |
4.4 设备心跳
POST /p/api/heartbeat
用途:周期上报设备在线状态,并接收人脸更新标记和当前餐段。
请求格式:application/x-www-form-urlencoded
| 参数 | 类型 | 必填性 | 说明 |
|---|---|---|---|
code |
string | 是 | 设备编号 |
响应 data:
| 字段 | 类型 | 说明 |
|---|---|---|
face_update |
int | 人脸数据更新标记 |
meal_times |
int | 当前餐段 |
4.5 上传硬件流程日志
POST /p/api/hardware_log
用途:上传扫码、人脸识别、绑定、排菜、取餐等硬件流程日志。
请求格式:application/json
| 参数 | 类型 | 说明 |
|---|---|---|
event |
int | 事件类型:10000 扫码、20000 人脸、30000 绑定、40000 请求排菜、50000 排菜、60000 取餐;项目中还存在其他扩展事件码 |
event_time |
string | 事件时间 |
event_code |
int | 0 成功,1 失败 |
event_msg |
string | 事件说明 |
user_uuid |
string | 人员 UUID |
user_name |
string | 人员姓名 |
machine_mac |
string | 机器 MAC |
machine_type |
int | 机器类型;自研绑盘机使用 10000 |
machine_code |
string | 终端编码 |
plate_code |
string | 餐盘码 |
user_face_img |
string | 人脸帧 Base64 |
similarity |
float | 人脸相似度 |
ori_user_face_url |
string | 原始人脸照片 URL |
dishes_uuid |
string | 菜品 UUID |
dishes_name |
string | 菜品名称 |
dishes_weight |
int | 菜品重量 |
响应 data 类型为数组,客户端不解析数组元素。
补充:项目中的大部分运行日志当前还会通过阿里云 SLS SDK 单独上报;hardware_log 与 SLS 是两条不同链路。
4.6 同步人脸数据
POST /p/api/facedata
用途:按设备编号同步人员人脸增量或全量数据。
请求格式:application/x-www-form-urlencoded
| 参数 | 类型 | 必填性 | 说明 |
|---|---|---|---|
code |
string | 是 | 终端设备编号 |
type |
string | 是 | 0 增量,1 全量 |
响应 data.face_data 为 SingleStaffDataBean[]:
| 字段 | 类型 | 说明 |
|---|---|---|
id |
int | 数据 ID |
staff_uuid |
string | 人员 UUID |
head_img_url |
string | 头像 URL 或相对路径 |
feature |
string | 人脸特征值 |
face_token |
string | 人脸 Token |
name |
string | 人员姓名 |
status |
string | 1 新增、2 更新、3 删除 |
4.7 MQTT 消息处理反馈
POST /p/api/feedback
用途:MQTT 人员数据成功保存到本地并刷新人脸内存后,向后台确认消息已处理。
请求格式:application/x-www-form-urlencoded
| 参数 | 类型 | 必填性 | 说明 |
|---|---|---|---|
device_id |
string | 是 | 设备编号 |
msg_uuid |
string | 是 | MQTT 消息 UUID |
响应 data 类型为数组,客户端只判断通用 code == 0。
4.8 设备启动初始化
POST /p/api/equipmentStart
用途:主页启动时获取 MQTT 开关和首页展示模式。
请求格式:application/x-www-form-urlencoded
| 参数 | 类型 | 必填性 | 说明 |
|---|---|---|---|
code |
string | 是 | 实际调用传终端设备编号;接口方法形参名 pairCode 与实际用途不一致 |
响应 data:
| 字段 | 类型 | 说明 |
|---|---|---|
ali_mqtt_disjunctor |
string | 值为 1 时启动 MQTT,否则走定时同步 |
model |
int / null | 1 营养+价格(汇总余额),2 营养,3 营养+价格(细分余额) |
4.9 获取最新版本
POST /p/api/getNewVersion
用途:设置页检查新版本,返回下载地址后交给系统浏览器打开。
请求格式:application/x-www-form-urlencoded
| 参数 | 类型 | 必填性 | 说明 |
|---|---|---|---|
version_number |
string | 是 | 当前 App versionName |
type |
string | 是 | 终端类型;当前调用硬编码为 1 |
code |
string | 是 | 设备编号 |
响应 data:
| 字段 | 类型 | 说明 |
|---|---|---|
code |
int | 版本编码 |
version_number |
string | 版本名称 |
url |
string | APK/版本下载地址;由系统浏览器打开 |
content |
string | 更新说明 |
is_renew |
int | 1 强制更新,2 非强制;当前调用流程未使用该字段控制弹窗 |
type |
int | 终端类型 |
源码注释称“消费机系统类型是 9”,实际传值为 1,应以后端当前约定为准并在联调时确认。
5. 仅定义、当前未发现调用的业务接口
5.1 获取排菜列表
POST /p/api/getMeal
定义了两种请求形式:
- JSON:
category、searchKey、code。 - Form:
category、keyword、code。
JSON 请求模型中的搜索字段会按 Java 字段名发送为 searchKey,Form 变体发送为 keyword,两种协议字段不一致。
响应 data 为按字符串键 1~6 分组的菜品数组。菜品字段:uuid、name、file_path、category。
5.2 获取菜品详情
POST /p/api/find
- JSON 请求:
uuid。 - 响应
data:price、name、weight、category_name、file_path、tag[]、energy、carbohydrate、fat、protein、dietary_fiber。
5.3 上传取餐信息
POST /p/api/ZpPushMeal
定义了两个 Form 变体:
| 变体 | 参数 |
|---|---|
| 人员 UUID 变体 | staff_uuid、dish_info |
| 条码变体 | staff_uuid、code、dish_info |
dish_info 结构:create_date(示例格式 yyyy-MM-dd HH:mm:ss)和 details[];每个明细包含菜品 uuid、weight。条码变体使用 JSONObject。当前响应模型未提供稳定业务字段。
5.4 通过餐盘码获取人员
POST /p/api/selectPlate
- Form 参数:
plate_code。 - 响应
data:StaffInfo[],字段见 4.1。
5.5 获取当餐营养累计
POST /p/api/currentMealNutrition
- Form 参数:
staff_uuid。 - 响应
data:
| 字段 | 说明 |
|---|---|
recommend_scope |
推荐范围 |
recommend_energy / reality_energy_sum |
能量推荐值 / 实际累计 |
recommend_protein / reality_protein_sum |
蛋白质推荐值 / 实际累计 |
recommend_carbohydrate / reality_carbohydrate_sum |
碳水推荐值 / 实际累计 |
recommend_fat / reality_fat_sum |
脂肪推荐值 / 实际累计 |
sucai |
蔬菜名称数组 |
shuiguo |
水果名称数组 |
meal_times |
餐段:1 早、2 中、3 晚 |
5.6 获取菜品库列表
POST /p/api/CaterList
Form 参数:
| 参数 | 说明 |
|---|---|
keyword |
搜索词 |
category |
菜品分类 |
page |
当前页 |
page_size |
每页数量 |
响应 data:
category[]:每项包含catergory、name、count;协议字段catergory保留了源码中的拼写。rows[]:每项包含uuid、name、file_path、category。
5.7 添加菜品到菜谱
POST /p/api/addRecipe
- Form 参数:
uuid(菜品 UUID)、code(终端设备编号)。 - 响应
data:数组,客户端没有定义元素结构。
5.8 获取餐厅餐段时间
POST /p/api/getRestaurantsInfo
- Form 参数:
id(餐厅 ID)。 - 响应
data:morning_start、morning_end、noon_start、noon_end、night_start、night_end。
5.9 从菜谱删除菜品
POST /p/api/delRecipe
- Form 参数:
code(终端设备编号)、uuid(菜品 UUID)。 - 响应
data:数组,客户端没有定义元素结构。
6. 第三方与运维 HTTP 接口
6.1 百度 OAuth Token
POST https://aip.baidubce.com/oauth/2.0/token
Query 参数:
| 参数 | 值/来源 |
|---|---|
grant_type |
固定 client_credentials |
client_id |
客户端内置凭据,本文脱敏 |
client_secret |
客户端内置凭据,本文脱敏 |
请求头:Content-Type: application/x-www-form-urlencoded;请求体为空。客户端读取响应 access_token 并保存到 MMKV。
代码注释称 Token 有效期 30 天,但刷新判断实际使用 60 * 60 * 30 毫秒,即约 108 秒,时间单位明显不一致。
6.2 百度人脸特征提取
POST https://aip.baidubce.com/rest/2.0/face/v1/feature?access_token={token}
请求头:Content-Type: application/json;连接和读取超时均为 8 秒。
{
"image": "人员头像 Base64",
"image_type": "BASE64",
"version": "Android_8001"
}
客户端在 error_code == 0 时读取 result.face_list[0].feature,Base64 解码后写入本地人脸库。
6.3 企业微信群机器人
地址不是硬编码固定值,而是由 /p/api/matecode 的 robot 对象下发并保存:报警、通知、主流程三条 URL。
请求:POST {动态机器人 URL},Content-Type: application/json。
普通通知/报警结构:
{
"msgtype": "markdown",
"markdown": {
"content": "包含客户、餐厅、设备编号、系统版本、MAC、IP、API 地址和事件内容的 Markdown"
}
}
主流程告警还包含 P0~P4 等级、主流程和子流程。客户端只以 HTTP 状态码 200 判断成功,不解析响应体业务码。
6.4 阿里云 RUM 配置
应用启动时通过阿里云 RUM SDK访问硬编码的 /RUM/config 配置地址,并使用硬编码 App ID 初始化。本文不记录完整标识值。
6.5 阿里云 SLS 日志上传
应用启动时创建 SLS Producer,区域接入点为 https://cn-beijing.log.aliyuncs.com,项目名、Logstore 与访问凭据均由客户端配置。日志内容包括时间、客户、餐厅、设备类型、终端编号、MAC 和日志详情。
当前源码中存在客户端静态 SLS 访问凭据;本文已脱敏,建议按第 9 节安全事项处理。
7. MQTT 接口
MQTT 配置由 /p/api/matecode 下发;客户端组装和连接规则如下:
| 项目 | 客户端行为 |
|---|---|
| Server URI | tcp://{ali_mqtt.endPoint} |
| Client ID | {groupId}@@@{terminalCode} |
| 用户名 | `Signature |
| 密码 | 使用 secretKey 对 Client ID 计算签名 |
| Topic | ali_mqtt.topic |
| QoS | 1 |
| 连接超时 | 3 秒 |
| Keep Alive | 90 秒 |
| 自动重连 | 开启 |
| Clean Session | 开启 |
接收消息按 SingleStaffDataBean 解析,并额外读取顶层 msg_uuid。人员数据保存成功后调用 /p/api/feedback 确认处理完成。
消息主要字段:id、staff_uuid、head_img_url、feature、face_token、name、status、msg_uuid。
8. 动态资源访问
8.1 人员头像
人员图片字段如果已经是 http:// 或 https:// 地址,Glide 直接 GET;否则使用当前业务 Base URL 与相对路径拼接后 GET。该访问不经过 CPTNetworkRequest,没有业务响应包装。
8.2 版本下载
/p/api/getNewVersion 返回的 url 由 ACTION_VIEW 交给系统浏览器打开,App 本身不负责下载、校验文件哈希或安装。
9. 接口风险与联调关注项
以下结论均直接来自当前客户端源码,未验证服务端实现:
- 客户端静态密钥风险:源码中存在可恢复的百度客户端凭据,以及阿里云 SLS AccessKey/Secret。应尽快轮换,并改为服务端代理、STS 或其他短期凭据机制。
- 敏感响应日志风险:网络日志拦截器记录完整请求和响应体;配对响应包含 MQTT 密钥和机器人 URL,人员接口包含人脸特征、头像及个人字段。应做字段级脱敏或禁止生产环境记录完整 Body。
- HTTP 可配置风险:基础设置允许明文
http://地址,人员数据、人脸特征和设备配置可能失去传输加密。生产环境应强制 HTTPS 并校验证书策略。 - 空
data覆盖业务码:客户端会将data == null的响应归一为code = 0,可能把业务失败误判为成功。 - 接口字段不一致:
getMeal的 JSON 变体使用searchKey,Form 变体使用keyword;subsidy_alance、catergory等拼写已形成客户端协议依赖。 - 方法注释与实参不一致:
equipmentStart的形参名写作配对码,但实际传设备编号;版本接口的终端类型注释与硬编码值不一致。 - 版本包完整性:客户端下载地址交给浏览器,未校验 APK 哈希、签名来源或下载域名白名单。
- MQTT 明文传输:Server URI 以
tcp://组装,未使用ssl://;若网络环境不受信,应评估 TLS MQTT。
10. 源码证据索引
| 内容 | 主要源码文件 |
|---|---|
| 业务接口定义 | app/src/main/java/com/zhct/traybinding/network/CPTNetworkRequest.java |
| 业务接口封装 | app/src/main/java/com/zhct/traybinding/network/CPTService.java、NetworkService.java |
| Retrofit/OkHttp 配置 | app/src/main/java/com/zhct/traybinding/network/CPTNetwork.java |
| 通用响应处理 | app/src/main/java/com/zhct/traybinding/network/ApiResultUtils.java、NetworkResult.java |
| 请求/响应模型 | app/src/main/java/com/zhct/traybinding/network/request/、response/ |
| 人盘绑定调用 | app/src/main/java/com/zhct/traybinding/fragment/HomeBindResultFragment.java、HomeBindResultWithBalanceFragment.java |
| 配对/升级调用 | app/src/main/java/com/zhct/traybinding/setting/SetBasicFragment.java |
| 启动初始化/硬件日志 | app/src/main/java/com/zhct/traybinding/main/HomeActivity.java |
| 心跳 | app/src/main/java/com/zhct/traybinding/workmanager/HeartBeatWorker.java |
| 人员与人脸同步 | app/src/main/java/com/zhct/traybinding/utils/StaffListManager.java、FaceDataUpdaters.java |
| 百度接口 | app/src/main/java/com/zhct/traybinding/baiduApi/GetToken.java、StaffListManager.java |
| 企业微信机器人 | app/src/main/java/com/zhct/traybinding/utils/EnterpriseAlertUploader.java |
| 阿里云 RUM/SLS | app/src/main/java/com/zhct/traybinding/application/CptApplication.java、SlsLogUploader.java |
| MQTT | app/src/main/java/com/zhct/traybinding/service/CustomMqttService.java、mqtt/MqttSimple.java |
11. 维护说明
后续接口变更时,至少同步检查:
CPTNetworkRequest的路径、请求格式与 Retrofit 方法声明。request/、response/和bean/中的字段映射。NetworkService、CPTService与真实业务调用点。- Base URL、第三方端点、MQTT 配置和动态机器人/资源地址。
- 本文“已调用/仅定义”状态、风险项与源码快照提交号。