- FaceDao新增queryByUserFaceId接口,实现按userFaceId精确查询 - FaceApi新增queryByUserFaceId方法,封装Dao查询逻辑 - LoginByFaceActivity插入人脸时,先按userFaceId查询,存在则更新避免重复 - NetViewModelV2同步人脸数据时,优先用userFaceId判重,减少重复入库 - 修正FaceEntity中userId字段数据库列名错误(user_id替代user_idd) - 增加注释说明及代码格式优化,提升代码可读性和健壮性
42 KiB
吐盘机(营养秤)接口文档
Controller:
NutPickupScaleController模块前缀:/neglect/pickupNacos 白名单:/nutrition/neglect/**(无需 Sa-Token) 设备上下文:请求头X-DEVICE-CODE生成日期:2026-06-29 对照老版:Downloads/营养秤_API_DOC.md(v1.0.0,2026-05-26)
一、服务器环境
| 环境 | 地址 | 端口 |
|---|---|---|
| 本地 | http://localhost |
24810 |
| 测试 | https://dev.yixiong-tech.com |
8083 |
| 生产 | https://api.dm.yixiong-tech.com |
8443 |
接口完整地址 = {baseUrl}/neglect/pickup/{sub-path}
二、请求头(全局)
| Header | 是否必填 | 说明 |
|---|---|---|
Content-Type |
是 | application/json(上传接口 multipart/form-data) |
X-DEVICE-CODE |
是 | 设备唯一编码,由 GlobalData.deviceId 注入;服务端据此解析食堂、餐次等上下文 |
X-Access-Token |
否 | JWT Token,吐盘机白名单接口不强制校验 |
authorization |
否 | 固定授权码 57ee87183f2a4fa59683ec9ef41c8f5d |
三、通用响应格式
所有接口统一返回 Result<T>:
{
"code": "00000",
"msg": "success",
"data": { },
"total": 0
}
| 字段 | 类型 | 说明 |
|---|---|---|
code |
String | "00000" 表示成功,其它为业务/系统错误码 |
msg |
String | 响应描述 |
data |
T | 业务数据,类型随接口变化 |
total |
int | 分页总条数,不分页接口为 0 |
Long 类型 ID 在 JSON 中序列化为 String,避免 JS 精度丢失。
四、接口详情
4.1 人脸数据同步
接口 P-01 — 获取全量人脸数据
POST /neglect/pickup/face/page
设备开机或重置本地特征库时调用,分页拉取全量人脸特征。
入参(Body JSON) — BasePageQuery
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
pageNum |
Long | 是 | 页码,从 1 开始 |
pageSize |
Long | 是 | 每页条数,建议 100 |
column |
String | 否 | 排序字段 |
order |
String | 否 | 排序方向(asc/desc) |
入参示例
{
"pageNum": 1,
"pageSize": 100
}
响应 data — List<NutTerminalAppFaceVO>
| 字段 | 类型 | 说明 |
|---|---|---|
userFaceId |
String | 人脸记录 id |
userId |
String | 用户 id |
faceFeature |
String | 人脸特征码(Base64 字符串) |
faceUpdateTimestamp |
Long | 人脸更新时间戳(毫秒) |
cardNo |
String | 会员卡号;非会员或未发卡为空 |
member |
Boolean | 是否会员 |
faceDeleted |
Boolean | 是否已删除(true 表示用户/人脸已注销,APP 端需清理本地缓存) |
personType |
String | 人员类型:1-员工,2-工作人员,3-普通用户,4-外部人员,5-会员 |
响应示例
{
"code": "00000",
"msg": "success",
"data": [
{
"userFaceId": "1024",
"userId": "88001",
"faceFeature": "ArcFaceBase64...",
"faceUpdateTimestamp": 1748000000000,
"cardNo": "M2024001",
"member": true,
"faceDeleted": false,
"personType": "5"
}
],
"total": 128
}
接口 P-02 — 获取增量人脸数据
POST /neglect/pickup/face/increment
按时间戳增量同步,仅返回 update_time 严格大于 timestamp 的记录(含已删除记录,APP 端据此清理本地缓存)。
入参(Body JSON) — NutTerminalAppFaceIncrementQuery(继承 BasePageQuery)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
pageNum |
Long | 是 | 页码 |
pageSize |
Long | 是 | 每页条数 |
column |
String | 否 | 排序字段(继承) |
order |
String | 否 | 排序方向(继承) |
timestamp |
Long | 是 | 上次同步时间戳(毫秒),首次同步传 0 |
入参示例
{
"pageNum": 1,
"pageSize": 100,
"timestamp": 1748000000000
}
响应 data — 同 P-01,List<NutTerminalAppFaceVO>
4.2 菜品查询
接口 P-03 — 按名称模糊搜索菜品
POST /neglect/pickup/food/search
按菜品名称关键词分页模糊搜索。结果按当前食堂 + 当餐次过滤。
入参(Body JSON) — NutTerminalAppFoodSearchQuery(继承 BasePageQuery)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
pageNum |
Long | 是 | 页码 |
pageSize |
Long | 是 | 每页条数 |
name |
String | 否 | 菜品名称关键词,不传则返回当餐全部菜品 |
入参示例
{
"pageNum": 1,
"pageSize": 20,
"name": "宫保鸡丁"
}
响应 data — List<NutTerminalAppFoodVO>
| 字段 | 类型 | 说明 |
|---|---|---|
cookOrderId |
String | 按单烹制 id(就餐时需回传给下单接口) |
foodId |
String | 菜品 id |
foodName |
String | 菜品名称 |
calorie |
BigDecimal | 能量(kcal/100g) |
protein |
BigDecimal | 蛋白质(g/100g) |
fat |
BigDecimal | 脂肪(g/100g) |
carbohydrate |
BigDecimal | 碳水化合物(g/100g) |
price |
BigDecimal | 称重基础价(元/100g),对应 nut_food.weight_base_price |
specPrice |
BigDecimal | 默认规格售价(元) |
vipPrice |
BigDecimal | VIP 售卖价;新系统暂无该概念,固定返回 null |
specWeight |
BigDecimal | 默认规格重量(g) |
stapleFood |
BigDecimal | 主食占比(g/100g):grain + potato |
fruitsVegetables |
BigDecimal | 果蔬占比(g/100g):vegetable + fruits |
meatEggs |
BigDecimal | 肉蛋占比(g/100g):livestock + birds + aquatic + egg |
recommendCalorie |
BigDecimal | 推荐能量;菜品层面无意义,固定 0 |
foodMaterialId |
String | 餐品营养表 id(默认主料 mater_id) |
specId |
String | 默认规格 id |
foodImg |
String | 菜品图片 URL(首张图片型 media) |
tablewareStatus |
Boolean | 是否含餐具;当前未建模,固定 false |
tablewareWeight |
Integer | 餐具重量(g);当前未建模,固定 0 |
foodLabel |
String | 菜品标签(tags 字段) |
响应示例
{
"code": "00000",
"msg": "success",
"data": [
{
"cookOrderId": "CO20260629-001",
"foodId": "2001",
"foodName": "宫保鸡丁",
"calorie": 195.5,
"protein": 8.2,
"fat": 12.1,
"carbohydrate": 9.3,
"price": 0.28,
"specPrice": 6.00,
"vipPrice": null,
"specWeight": 200,
"stapleFood": 9.3,
"fruitsVegetables": 2.0,
"meatEggs": 8.2,
"recommendCalorie": 0,
"foodMaterialId": "3001",
"specId": "2001-1",
"foodImg": "https://cdn.yixiong.com/food/2001.jpg",
"tablewareStatus": false,
"tablewareWeight": 0,
"foodLabel": "招牌,微辣"
}
],
"total": 1
}
接口 P-04 — 当餐菜品列表
POST /neglect/pickup/food/current-meal
返回当前食堂 + 当前餐次下所有可供应菜品。无入参。
入参示例
{ }
响应 data — List<NutTerminalAppFoodVO>,字段同 P-03
接口 P-05 — 菜品详情
POST /neglect/pickup/food/detail
入参(Body JSON) — IdDTO
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
Long | 是 | 菜品 id(foodId) |
入参示例
{ "id": 2001 }
响应 data — NutTerminalAppFoodVO,字段同 P-03
接口 P-06 — 按多个菜品名称查询(顺序一致)
POST /neglect/pickup/food/by-names
开餐页面批量按名称查询菜品,返回顺序与传入 nameList 一致。
入参(Body JSON) — NutPickupFoodNamesQuery
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
nameList |
List<String> | 是 | 菜品名称列表,至少 1 条 |
入参示例
{
"nameList": ["宫保鸡丁", "西红柿炒鸡蛋", "米饭"]
}
响应 data — List<NutTerminalAppFoodVO>,字段同 P-03
4.3 开餐 / 加菜
接口 P-07 — 开餐(记录初始制作量)
POST /neglect/pickup/meal/start
档口开餐时记录菜品初始制作量,作为余量监控的起始锚点。
入参(Body JSON) — NutTerminalAppStartMealDTO
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
foodId |
Long | 是 | 菜品 id |
foodName |
String | 否 | 菜品名称(冗余) |
foodWeight |
BigDecimal | 是 | 食物重量(克) |
powerOnTime |
LocalDateTime | 否 | 开机时间(设备上报),格式 yyyy-MM-dd HH:mm:ss |
设备编码、食堂 id 等终端上下文由
X-DEVICE-CODE头解析,无需 DTO 携带。
入参示例
{
"foodId": 2001,
"foodName": "宫保鸡丁",
"foodWeight": 5000,
"powerOnTime": "2026-06-29 10:30:00"
}
响应 data — 无(Result<Void>),仅以 code 判断成功
响应示例
{ "code": "00000", "msg": "success", "data": null, "total": 0 }
接口 P-08 — 加菜(追加制作量)
POST /neglect/pickup/meal/add
开餐过程中追加制作量,累加到该菜品当前制作总量。
入参 / 响应 — 同 P-07(NutTerminalAppStartMealDTO / Result<Void>)
4.4 就餐记录
接口 P-09a — 取餐盘(记录开始就餐时刻)
POST /neglect/pickup/plate-pickup
记录用户"开始就餐"的时刻(取餐盘时间)。调用一次 = upsert 到 nut_pickup_order 的 plate_pickup_time 字段。
使用约束:
- 本接口是 P-09 提交单道菜就餐记录 的强前置:未取盘直接打菜会返回错误
msg: "请先取餐盘再提交就餐记录"。 - upsert 语义:当日 + 当前餐次 + 当前食堂已有
pickup_method='plate_only'且plate_pickup_time非空的主单 → 刷新时间戳,共用一条主单;否则新建pickup_method='plate_only'的独立主单(无子表、无占位流水,不进入支付链路)。 - 不限制设备(取盘机 vs 营养秤可以是不同设备),按
userId关联。
入参(Body JSON) — IdDTO
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
Long | 是 | 用户 id(餐盘号) |
入参示例
{ "id": 88001 }
响应 data — String,主单 recordNo(Result.saveSuccess 包装,新建或刷新)
响应示例
{
"code": "00000",
"msg": "success",
"data": "M-20260709-0001",
"total": 0
}
设备编码、食堂 id、餐线 id、餐次等终端上下文由请求头
X-DEVICE-CODE解析,无需 DTO 携带。
接口 P-09 — 提交单道菜就餐记录
POST /neglect/pickup/eat
调用一次 = 一道菜的就餐数据;同一用户同一餐次多次调用按主单聚合:
- 主单查找规则:
(userId, eatDay=今日, mealType=当前餐次, pickup_end_time IS NULL) - 命中则只追加子表 + 更新主单合计;未命中则新建主单 + 1 条子表
强前置校验(取盘校验):
本接口被调用前,业务端必须保证当前用户当日在当前食堂、当前餐次存在一条 pickup_method='plate_only' 且 plate_pickup_time 非空的主单(即已先调用 P-09a 取餐盘)。否则直接抛业务异常:
msg: "请先取餐盘再提交就餐记录"
该校验由
NutPickupScaleAppServiceImpl#submitEat在主单查找之前完成,过滤条件严格按(userId, canteenId, eatDay, mealType, pickup_method='plate_only', plate_pickup_time IS NOT NULL)命中,避免跨餐次/跨食堂误判。
入参(Body JSON) — NutTerminalAppEatDTO
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
userId |
Long | 是 | 用户 id(餐盘号 = userId) |
foodId |
Long | 是 | 菜品 id |
foodName |
String | 是 | 菜品名称(冗余存储,便于历史回溯) |
specId |
Long | 否 | 菜品规格 id;无规格传 0 |
foodWeight |
BigDecimal | 是 | 菜品总重量(克) |
eatWeight |
BigDecimal | 是 | 实际食用重量(克),可为 0 |
member |
Boolean | 否 | 是否会员(仅作冗余记录用;新表 person_type 由 nut_user 实际身份决定) |
cookOrderId |
Long | 否 | 按单烹制 id(终端菜品列表返回的 cookOrderId,就餐时原样回传) |
入参示例
{
"userId": 88001,
"foodId": 2001,
"foodName": "宫保鸡丁",
"specId": 0,
"foodWeight": 200,
"eatWeight": 150,
"member": true,
"cookOrderId": 1000123
}
响应 data — String,主单 id(Result.saveSuccess 包装)
响应示例
{
"code": "00000",
"msg": "success",
"data": "1000456",
"total": 0
}
接口 P-10 — 按用户 id(餐盘号)查本餐就餐数据
POST /neglect/pickup/plate-food
按餐盘号(= userId)查询本餐次已就餐明细,实时聚合主单 + 子表 + 营养现算。
入参(Body JSON) — IdDTO
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
Long | 是 | 用户 id(餐盘号) |
入参示例
{ "id": 88001 }
响应 data — NutTerminalAppPlateFoodVO
| 字段 | 类型 | 说明 |
|---|---|---|
name |
String | 用户姓名 |
calorie |
BigDecimal | 本餐热量(kcal) |
grain |
BigDecimal | 谷类摄入量(g) |
fruitsVegetables |
BigDecimal | 果蔬摄入量(g) |
other |
BigDecimal | 肉蛋豆摄入量(g) |
eatWeightSum |
Integer | 食用总重量(g) |
incomeSum |
BigDecimal | 菜品总收入价格(元) |
discountSum |
BigDecimal | 优惠总价格(元);当前固定 0 |
recommendCalorie |
BigDecimal | 推荐能量(kcal);当前固定 0 |
maxCalorie |
BigDecimal | 能量上限(kcal);当前固定 0 |
minCalorie |
BigDecimal | 能量下限(kcal);当前固定 0 |
grainRecommend / grainNearExcess / grainExcess |
String | 谷类推荐/即将超量/超量描述(当前固定空) |
fruitsVegetablesRecommend / fruitsVegetablesNearExcess / fruitsVegetablesExcess |
String | 果蔬推荐/即将超量/超量描述(当前固定空) |
otherRecommend / otherNearExcess / otherExcess |
String | 肉蛋豆推荐/即将超量/超量描述(当前固定空) |
message |
String | 提示信息(暂未启用) |
list |
List<Food> | 本餐菜品明细列表,见下表 |
NutTerminalAppPlateFoodVO.Food 子对象:
| 字段 | 类型 | 说明 |
|---|---|---|
foodId |
String | 菜品 id |
foodName |
String | 菜品名称 |
foodMaterialId |
String | 菜品营养表 id(默认主料 mater_id) |
specId |
String | 餐品规格 id;无规格为 0 |
eatWeight |
Integer | 食用重量(g) |
deviceWeight |
Integer | 记录 eatWeight 时秤的当前重量(g) |
initWeight |
Integer | 记录前秤重量(g)= realWeight + eatWeight |
eatNum |
Integer | 份数 |
price |
BigDecimal | 菜品单价(元) |
discount |
BigDecimal | 优惠价格(元);当前固定 0 |
income |
BigDecimal | 菜品收入(元) |
isSyncData |
Boolean | 是否已同步标识;新接口固定 true |
orderFrom |
Integer | 来源:1-营养秤,2-档口机;当前固定 1 |
响应示例
{
"code": "00000",
"msg": "success",
"data": {
"name": "张三",
"calorie": 293.25,
"grain": 75.0,
"fruitsVegetables": 30.0,
"other": 124.5,
"eatWeightSum": 229,
"incomeSum": 6.50,
"discountSum": 0,
"recommendCalorie": 0,
"maxCalorie": 0,
"minCalorie": 0,
"grainRecommend": "",
"grainNearExcess": "",
"grainExcess": "",
"fruitsVegetablesRecommend": "",
"fruitsVegetablesNearExcess": "",
"fruitsVegetablesExcess": "",
"otherRecommend": "",
"otherNearExcess": "",
"otherExcess": "",
"message": "",
"list": [
{
"foodId": "2001",
"foodName": "宫保鸡丁",
"foodMaterialId": "3001",
"specId": "0",
"eatWeight": 150,
"deviceWeight": 350,
"initWeight": 500,
"eatNum": 1,
"price": 6.50,
"discount": 0,
"income": 6.50,
"isSyncData": true,
"orderFrom": 1
}
]
},
"total": 0
}
接口 P-11 — 推送菜品实时重量
POST /neglect/pickup/weight
设备在称重过程中持续推送当前菜品重量。服务端按 (deviceCode, foodId) 写入 Redis,TTL 60s,BI/监控屏读取后自动刷新展示,无心跳即过期降级。
入参(Body JSON) — NutTerminalAppScaleWeightDTO
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
foodId |
Long | 是 | 菜品 id |
foodWeight |
Integer | 是 | 当前菜品重量(克),不能为负 |
设备编码由
X-DEVICE-CODE头携带。
入参示例
{
"foodId": 2001,
"foodWeight": 425
}
响应 data — 无(Result<Void>)
4.5 公共能力
接口 P-12 — 用户当日就餐营养
POST /neglect/pickup/user/current-food
按用户 id 累加当日全部已就餐主单(不仅本餐次),按子表 food_weight × 营养项/100g 现算。
入参(Body JSON) — IdDTO
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
Long | 是 | 用户 id |
入参示例
{ "id": 88001 }
响应 data — NutTerminalAppUserNutritionVO
| 字段 | 类型 | 说明 |
|---|---|---|
name |
String | 用户姓名 |
calorie |
BigDecimal | 已摄入热量(kcal) |
fruitsVegetables |
BigDecimal | 果蔬摄入量(g) |
meatEggs |
BigDecimal | 肉蛋摄入量(g) |
stapleFood |
BigDecimal | 主食摄入量(g) |
maxCalorie |
BigDecimal | 能量上限(kcal);当前固定 0 |
minCalorie |
BigDecimal | 能量下限(kcal);当前固定 0 |
recommendCalorie |
BigDecimal | 推荐能量(kcal);当前固定 0 |
stapleFoodRecommend / stapleFoodNearExcess / stapleFoodExcess |
String | 主食推荐/即将超量/超量描述(当前固定空) |
fruitsVegetablesRecommend / fruitsVegetablesNearExcess / fruitsVegetablesExcess |
String | 果蔬推荐/即将超量/超量描述(当前固定空) |
meatEggsRecommend / meatEggsNearExcess / meatEggsExcess |
String | 肉蛋推荐/即将超量/超量描述(当前固定空) |
message |
String | 提示信息(暂未启用) |
响应示例
{
"code": "00000",
"msg": "success",
"data": {
"name": "张三",
"calorie": 588.5,
"fruitsVegetables": 60.0,
"meatEggs": 124.5,
"stapleFood": 150.0,
"maxCalorie": 0,
"minCalorie": 0,
"recommendCalorie": 0,
"stapleFoodRecommend": "",
"stapleFoodNearExcess": "",
"stapleFoodExcess": "",
"fruitsVegetablesRecommend": "",
"fruitsVegetablesNearExcess": "",
"fruitsVegetablesExcess": "",
"meatEggsRecommend": "",
"meatEggsNearExcess": "",
"meatEggsExcess": "",
"message": ""
},
"total": 0
}
接口 P-13 — 虹软 SDK 设备配置
GET /neglect/pickup/device/config
无入参(设备编码由 X-DEVICE-CODE 头传递)。终端 APP 启动时调一次缓存到本地,不需要持续轮询。
响应 data — NutTerminalAppDeviceConfigVO
| 字段 | 类型 | 说明 |
|---|---|---|
arcsoftAppId |
String | 虹软 ArcFace SDK App Id |
arcsoftSdkKey |
String | 虹软 ArcFace SDK Key |
arcsoftActiveKey |
String | 虹软 ArcFace 激活码 |
payType |
Integer | 档口秤结算方式:1-独立结算,2-联合结算;吐盘机无意义 |
响应示例
{
"code": "00000",
"msg": "success",
"data": {
"arcsoftAppId": "8cXr...",
"arcsoftSdkKey": "FpHn...",
"arcsoftActiveKey": "3aEb...",
"payType": null
},
"total": 0
}
接口 P-14 — 当前餐次信息
GET /neglect/pickup/meal/current
无入参。餐次时段当前由 MealPeriodHelper 硬编码(公司全局统一),不在任何区间时返回最近的下一餐。
响应 data — NutTerminalAppMealInfoVO
| 字段 | 类型 | 说明 |
|---|---|---|
mealName |
String | 餐次名称(早餐/午餐/晚餐/加餐) |
mealTimeStart |
LocalDateTime | 餐次开始时间,格式 yyyy-MM-dd HH:mm:ss |
mealTimeEnd |
LocalDateTime | 餐次结束时间,格式 yyyy-MM-dd HH:mm:ss |
响应示例
{
"code": "00000",
"msg": "success",
"data": {
"mealName": "午餐",
"mealTimeStart": "2026-06-29 11:30:00",
"mealTimeEnd": "2026-06-29 13:00:00"
},
"total": 0
}
接口 P-15 — 会员折扣率
POST /neglect/pickup/member/discount
按用户 id 返回折扣系数(如 0.9 表示九折)。
入参(Body JSON) — IdDTO
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
Long | 是 | 用户 id |
入参示例
{ "id": 88001 }
响应 data — BigDecimal
响应示例
{
"code": "00000",
"msg": "success",
"data": 0.90,
"total": 0
}
4.6 食材库存 / 净菜加工
接口 P-16 — 食材库存搜索
POST /neglect/pickup/ingredient/search
按食材名称模糊搜索,按溯源码分组返回。
入参(Body JSON) — NutIngredientSearchQuery(继承 BasePageQuery)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
pageNum |
Long | 是 | 页码 |
pageSize |
Long | 是 | 每页条数 |
keyword |
String | 否 | 食材名称(模糊) |
入参示例
{
"pageNum": 1,
"pageSize": 20,
"keyword": "白菜"
}
响应 data — List<NutIngredientInventoryVO>
| 字段 | 类型 | 说明 |
|---|---|---|
materId |
Long | 食材 id |
materName |
String | 食材名称 |
traceCode |
String | 溯源码 |
totalWeight |
BigDecimal | 总库存量(kg) |
vegTypeList |
List<NutMaterVegTypeOptionVO> | 净菜类型列表 |
NutMaterVegTypeOptionVO 子对象:
| 字段 | 类型 | 说明 |
|---|---|---|
vegTypeId |
Long | 净菜类型 id |
vegTypeName |
String | 净菜类型名称(如 洗净米、肉片、豆腐块) |
响应示例
{
"code": "00000",
"msg": "success",
"data": [
{
"materId": 1001,
"materName": "大白菜",
"traceCode": "HV2026060001",
"totalWeight": 125.50,
"vegTypeList": [
{ "vegTypeId": 11, "vegTypeName": "洗净叶菜" },
{ "vegTypeId": 12, "vegTypeName": "菜段" }
]
}
],
"total": 1
}
接口 P-17 — 加工步骤字典
GET /neglect/pickup/dict/process-step
无入参。返回净菜加工步骤字典(清洗/去皮/切割/分拣/综合加工)。
响应 data — List<NutDictItemVO>
| 字段 | 类型 | 说明 |
|---|---|---|
id |
Long | 主键 id |
dictType |
String | 所属字典类型编码 |
dictCode |
String | 字典值(存入业务表的实际值) |
dictLabel |
String | 显示名称 |
sortOrder |
Integer | 排序 |
isBuiltin |
Short | 是否系统内置(1-是,0-否) |
status |
Short | 状态(1-启用,0-禁用) |
remark |
String | 备注说明 |
updateBy |
Long | 修改人 id |
updateByName |
String | 修改人姓名 |
createTime |
LocalDateTime | 创建时间 |
updateTime |
LocalDateTime | 修改时间 |
响应示例
{
"code": "00000",
"msg": "success",
"data": [
{ "id": 501, "dictType": "PROCESS_STEP", "dictCode": "WASH", "dictLabel": "清洗", "sortOrder": 1, "isBuiltin": 1, "status": 1, "remark": "", "updateBy": 1, "updateByName": "system", "createTime": "2026-05-20 09:00:00", "updateTime": "2026-05-20 09:00:00" },
{ "id": 502, "dictType": "PROCESS_STEP", "dictCode": "PEEL", "dictLabel": "去皮", "sortOrder": 2, "isBuiltin": 1, "status": 1, "remark": "", "updateBy": 1, "updateByName": "system", "createTime": "2026-05-20 09:00:00", "updateTime": "2026-05-20 09:00:00" },
{ "id": 503, "dictType": "PROCESS_STEP", "dictCode": "CUT", "dictLabel": "切割", "sortOrder": 3, "isBuiltin": 1, "status": 1, "remark": "", "updateBy": 1, "updateByName": "system", "createTime": "2026-05-20 09:00:00", "updateTime": "2026-05-20 09:00:00" },
{ "id": 504, "dictType": "PROCESS_STEP", "dictCode": "SORT", "dictLabel": "分拣", "sortOrder": 4, "isBuiltin": 1, "status": 1, "remark": "", "updateBy": 1, "updateByName": "system", "createTime": "2026-05-20 09:00:00", "updateTime": "2026-05-20 09:00:00" },
{ "id": 505, "dictType": "PROCESS_STEP", "dictCode": "MIXED", "dictLabel": "综合加工", "sortOrder": 5, "isBuiltin": 1, "status": 1, "remark": "", "updateBy": 1, "updateByName": "system", "createTime": "2026-05-20 09:00:00", "updateTime": "2026-05-20 09:00:00" }
],
"total": 0
}
接口 P-18 — 净菜加工新增
POST /neglect/pickup/clean-process/add
提交一条净菜加工记录,关联毛菜批次与食材溯源。
入参(Body JSON) — NutSupCleanProcessDTO
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
Long | 否 | 主键 id(修改时必填) |
batchNo |
String | 否 | 加工批次号,如 PROC-001,全局唯一 |
traceCode |
String | 是 | 溯源码(来源 nut_farm_harvest.trace_code) |
materialId |
Long | 是 | 食材 id,FK→nut_mater_base.id |
ingredientName |
String | 是 | 食材名称 |
vegTypeId |
Long | 否 | 净菜类型 id,FK→nut_mater_veg_type.id |
requiredCleanWeight |
BigDecimal | 否 | 净菜需求重量(kg),来源毛菜清洗任务的 required_weight |
rawBatchNo |
String | 否 | 关联毛菜秤批次号 LC-xxx(毛菜秤提交时自动写入) |
processStep |
String | 是 | 加工步骤:清洗/去皮/切割/分拣/综合加工 |
rawWeight |
BigDecimal | 是 | 毛菜重量(kg) |
cleanWeight |
BigDecimal | 否 | 净菜重量(kg),加工完成后填写 |
yieldRate |
BigDecimal | 否 | 出净率(%),= clean_weight / raw_weight * 100,应用层计算回填 |
operator |
String | 否 | 加工人员姓名,不传时从登录态自动取 |
startTime |
LocalDateTime | 是 | 加工开始时间 |
endTime |
LocalDateTime | 否 | 加工结束时间 |
qcResult |
Short | 否 | 质检结果(0-待检,1-合格,2-不合格),不传默认 0 |
inboundStatus |
Short | 否 | 入库状态(0-未入库,1-已入库) |
cameraCode |
String | 否 | 关联摄像头编号 |
videoUrl |
String | 否 | 加工监控视频地址 |
opType |
Short | 否 | 操作类型(1-设备自动,2-人工录入) |
deviceType |
String | 否 | 设备类型(字典值),如 CLEAN_PROCESS_SCALE |
deviceCode |
String | 否 | 设备编码 |
remark |
String | 否 | 备注 |
入参示例
{
"traceCode": "HV2026060001",
"materialId": 1001,
"ingredientName": "大白菜",
"vegTypeId": 11,
"processStep": "清洗",
"rawWeight": 50.0,
"cleanWeight": 45.0,
"startTime": "2026-06-29 14:00:00",
"endTime": "2026-06-29 14:20:00",
"deviceType": "CLEAN_PROCESS_SCALE",
"deviceCode": "CPS-001",
"opType": 1
}
响应 data — 无(Result<Void>)
4.7 采样-分类 / 菜品搜索
接口 P-19 — 采样菜品分类列表
GET /neglect/pickup/sampling/categories
无入参。返回采样页面用的餐品分类列表。
响应 data — List<NutFoodClassSimpleVO>
| 字段 | 类型 | 说明 |
|---|---|---|
classId |
String | 分类 id |
className |
String | 分类名称(主食/荤菜/素菜/汤品/饮品) |
响应示例
{
"code": "00000",
"msg": "success",
"data": [
{ "classId": "1", "className": "主食" },
{ "classId": "2", "className": "荤菜" },
{ "classId": "3", "className": "素菜" },
{ "classId": "4", "className": "汤品" },
{ "classId": "5", "className": "饮品" }
],
"total": 0
}
接口 P-20 — 采样菜品搜索
POST /neglect/pickup/sampling/food/search
按分类 + 名称模糊搜索,从按单烹制按食堂 + 日期 + 餐次过滤。
入参(Body JSON) — NutSamplingFoodSearchQuery(继承 BasePageQuery)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
pageNum |
Long | 是 | 页码 |
pageSize |
Long | 是 | 每页条数 |
categoryId |
Long | 否 | 分类 id,null 或 0 表示全部 |
foodName |
String | 否 | 菜品名称,支持模糊搜索 |
入参示例
{
"pageNum": 1,
"pageSize": 20,
"categoryId": 2,
"foodName": "鸡"
}
响应 data — List<NutSamplingFoodVO>
| 字段 | 类型 | 说明 |
|---|---|---|
cookOrderId |
String | 按单烹制 id |
foodId |
String | 菜品 id |
foodName |
String | 菜品名称 |
foodImg |
String | 菜品图片 URL |
classId |
String | 分类 id |
className |
String | 分类名称 |
mainIngredientName |
String | 主要食材名称 |
calorie |
BigDecimal | 能量(kcal/100g) |
响应示例
{
"code": "00000",
"msg": "success",
"data": [
{
"cookOrderId": "CO20260629-001",
"foodId": "2001",
"foodName": "宫保鸡丁",
"foodImg": "https://cdn.yixiong.com/food/2001.jpg",
"classId": "2",
"className": "荤菜",
"mainIngredientName": "鸡胸肉",
"calorie": 195.5
}
],
"total": 1
}
4.8 采样-保存采集数据
接口 P-21 — 保存采集图片及向量
POST /neglect/pickup/sampling/save(multipart/form-data)
提交一道菜的采样图片及特征向量,返回上传成功的图片 URL 列表。
入参(multipart 表单字段)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
foodId |
Long | 是 | 菜品 id(form 字段) |
foodName |
String | 是 | 菜品名称(form 字段) |
version |
String | 是 | 模型版本号(form 字段) |
foodVector |
String | 是 | 菜品特征向量(JSON 数组字符串,form 字段) |
foodPics |
MultipartFile[] | 是 | 菜品图片文件列表(file part) |
响应 data — List<String>,上传成功的图片 URL 列表
响应示例
{
"code": "00000",
"msg": "success",
"data": [
"https://cdn.yixiong.com/sample/2001_v1_1.jpg",
"https://cdn.yixiong.com/sample/2001_v1_2.jpg",
"https://cdn.yixiong.com/sample/2001_v1_3.jpg"
],
"total": 0
}
4.9 采样历史
接口 P-22 — 采样历史分页(按菜品聚合)
POST /neglect/pickup/sampling/history/page
按菜品聚合返回采样历史,每条含 3 张缩略图。
入参(Body JSON) — NutSamplingHistoryQuery(继承 BasePageQuery)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
pageNum |
Long | 是 | 页码 |
pageSize |
Long | 是 | 每页条数 |
categoryId |
Long | 否 | 分类 id,null 或 0 表示全部 |
foodName |
String | 否 | 菜品名称,支持模糊搜索 |
入参示例
{
"pageNum": 1,
"pageSize": 10,
"foodName": "鸡"
}
响应 data — List<NutSamplingHistoryVO>
| 字段 | 类型 | 说明 |
|---|---|---|
foodId |
String | 菜品 id |
foodName |
String | 菜品名称 |
foodImg |
String | 菜品图片 URL |
className |
String | 分类名称 |
mainIngredientName |
String | 主要食材名称 |
calorie |
BigDecimal | 能量(kcal/100g) |
totalCount |
Long | 采样总条数 |
previewUrls |
List<String> | 已采集图片缩略图(最多 3 张) |
lastSampleTime |
String | 最近采样时间 |
响应示例
{
"code": "00000",
"msg": "success",
"data": [
{
"foodId": "2001",
"foodName": "宫保鸡丁",
"foodImg": "https://cdn.yixiong.com/food/2001.jpg",
"className": "荤菜",
"mainIngredientName": "鸡胸肉",
"calorie": 195.5,
"totalCount": 12,
"previewUrls": [
"https://cdn.yixiong.com/sample/2001_v1_1.jpg",
"https://cdn.yixiong.com/sample/2001_v1_2.jpg",
"https://cdn.yixiong.com/sample/2001_v1_3.jpg"
],
"lastSampleTime": "2026-06-28 17:45:00"
}
],
"total": 1
}
接口 P-23 — 菜品采样全部图片
POST /neglect/pickup/sampling/history/detail
按菜品 id 查询采样全部图片(最多 50 条)。
入参(Body JSON) — IdDTO
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
Long | 是 | 菜品 id |
入参示例
{ "id": 2001 }
响应 data — List<NutSamplingDetailVO>
| 字段 | 类型 | 说明 |
|---|---|---|
id |
String | 采集图片 id |
foodPic |
String | 采集图片 URL |
createTime |
String | 采样时间 |
响应示例
{
"code": "00000",
"msg": "success",
"data": [
{ "id": "9001", "foodPic": "https://cdn.yixiong.com/sample/2001_v1_1.jpg", "createTime": "2026-06-28 17:45:00" },
{ "id": "9002", "foodPic": "https://cdn.yixiong.com/sample/2001_v1_2.jpg", "createTime": "2026-06-28 17:45:01" }
],
"total": 0
}
五、接口速查表
| 接口号 | 接口名称 | 方法 | 路径 |
|---|---|---|---|
| P-01 | 全量人脸数据 | POST | /neglect/pickup/face/page |
| P-02 | 增量人脸数据 | POST | /neglect/pickup/face/increment |
| P-03 | 模糊搜索菜品 | POST | /neglect/pickup/food/search |
| P-04 | 当餐菜品列表 | POST | /neglect/pickup/food/current-meal |
| P-05 | 菜品详情 | POST | /neglect/pickup/food/detail |
| P-06 | 按多名菜品查询 | POST | /neglect/pickup/food/by-names |
| P-07 | 开餐(初始制作量) | POST | /neglect/pickup/meal/start |
| P-08 | 加菜(追加制作量) | POST | /neglect/pickup/meal/add |
| P-09a | 取餐盘(记录开始就餐时刻) | POST | /neglect/pickup/plate-pickup |
| P-09 | 提交单道菜就餐记录 | POST | /neglect/pickup/eat |
| P-10 | 餐盘号查本餐就餐数据 | POST | /neglect/pickup/plate-food |
| P-11 | 推送菜品实时重量 | POST | /neglect/pickup/weight |
| P-12 | 用户当日就餐营养 | POST | /neglect/pickup/user/current-food |
| P-13 | 虹软 SDK 设备配置 | GET | /neglect/pickup/device/config |
| P-14 | 当前餐次信息 | GET | /neglect/pickup/meal/current |
| P-15 | 会员折扣率 | POST | /neglect/pickup/member/discount |
| P-16 | 食材库存搜索 | POST | /neglect/pickup/ingredient/search |
| P-17 | 加工步骤字典 | GET | /neglect/pickup/dict/process-step |
| P-18 | 净菜加工新增 | POST | /neglect/pickup/clean-process/add |
| P-19 | 采样菜品分类列表 | GET | /neglect/pickup/sampling/categories |
| P-20 | 采样菜品搜索 | POST | /neglect/pickup/sampling/food/search |
| P-21 | 保存采集图片及向量 | POST | /neglect/pickup/sampling/save |
| P-22 | 采样历史分页 | POST | /neglect/pickup/sampling/history/page |
| P-23 | 菜品采样全部图片 | POST | /neglect/pickup/sampling/history/detail |
六、版本差异(对照老版 营养秤_API_DOC.md v1.0.0 / 2026-05-26)
6.1 全局差异
| 维度 | 老版 | 新版 | 影响 |
|---|---|---|---|
| 路径前缀 | /terminal/neglect/...(混杂 common/app、nutrition/scale/app、boothMachine/app) |
统一 /neglect/pickup/... |
全部接口路径变更,APP 端需更新 Retrofit baseUrl 映射 |
| 响应包装 | { "code": "00000", "msg": "...", "data": {} } |
{ "code": "00000", "msg": "...", "data": {}, "total": 0 } |
新增 total 字段(分页接口返回总条数,非分页为 0) |
| 鉴权 | 全局硬编码 X-Access-Token + authorization |
Nacos 白名单 /nutrition/neglect/**,不强制校验 Sa-Token |
APP 端可继续保留请求头,但服务端不再据此鉴权 |
| 设备上下文 | DTO 内冗余携带 deviceId |
统一由 X-DEVICE-CODE 请求头解析 |
DTO 字段精简(详见各接口差异) |
| HTTP 方法 | 大量使用 GET + Query String | 项目规范强制 POST + @RequestBody,仅查询类无入参接口保留 GET |
多个老 GET 接口改为 POST + body(详见下表) |
6.2 逐接口差异
| 老接口号 | 老路径 / 方法 | 新路径 / 方法 | 入参变化 | 响应变化 |
|---|---|---|---|---|
| 2.1 | POST /terminal/neglect/common/app/faceFeature/list |
POST /neglect/pickup/face/page |
入参从 {pageNum, pageSize} 升级为 BasePageQuery(含 column/order 排序字段),pageNum/pageSize 类型由 Integer 改为 Long |
字段精简:移除 faceFeatureString、faceFeatureStr 备用字段,新增 personType 字段 |
| 2.2 | POST /terminal/neglect/common/app/faceFeature/increment/list |
POST /neglect/pickup/face/increment |
入参 pageNum/pageSize 由 Long 保留为 Long;timestamp 含义不变 |
同 2.1 |
| 2.3 | POST /terminal/neglect/nutrition/scale/app/startMealService |
拆为两个接口:POST /neglect/pickup/meal/start(type=1)+ POST /neglect/pickup/meal/add(type=2) |
拆分:老接口靠 type 字段区分 0-就餐/1-初始制作量/2-后期加菜,新版按业务拆为独立 endpoint;就餐数据走 P-09 /eat;DTO 字段精简,移除 deviceId、specId、foodMaterialId、type、currentScaleWeight,新增 powerOnTime |
响应仍为空对象 |
| 2.4 | POST /terminal/neglect/nutrition/scale/app/userEatFood |
POST /neglect/pickup/eat |
字段类型:userId/foodId/specId 由 String 改为 Long;foodWeight/eatWeight 由 String 改为 BigDecimal;移除 deviceId、foodMaterialId;新增 cookOrderId(按单烹制回传) |
响应 data 由空 Object 改为 String(主单 id) |
| 2.5 | GET /terminal/neglect/boothMachine/app/getUserCurrentFoodDetails?id=xxx |
POST /neglect/pickup/user/current-food |
方法由 GET 改为 POST;入参从 Query id 改为 IdDTO body |
字段语义不变;maxCalorie/minCalorie/recommendCalorie 当前固定 0;各 *Recommend/*NearExcess/*Excess 描述字段当前固定空字符串 |
| 2.6 | GET /terminal/neglect/nutrition/scale/app/getFoodInfoByPlateNumber?userId=xxx |
POST /neglect/pickup/plate-food |
方法由 GET 改为 POST;入参从 Query userId 改为 IdDTO body(id 即 userId/餐盘号) |
子对象 Food 字段类型对齐:eatWeight/deviceWeight/initWeight/eatNum 改为 Integer,price/discount/income 改为 BigDecimal;isSyncData 固定 true、orderFrom 固定 1 |
| 2.7 | POST /terminal/neglect/boothMachine/app/getFoodsByFoodNameList |
POST /neglect/pickup/food/search |
入参从 {name, pageNum, pageSize}(String)改为 NutTerminalAppFoodSearchQuery(Long + name),name 改为非必填 |
FoodInfo 字段语义变化:price 单位由「元/千克」改为「元/100g」;vipPrice 固定 null;recommendCalorie 固定 0;新增 cookOrderId;tablewareStatus 固定 false、tablewareWeight 固定 0 |
| 2.8 | GET /terminal/neglect/boothMachine/app/getFoodsByCurrentMeal |
POST /neglect/pickup/food/current-meal |
方法由 GET 改为 POST;无入参 | 同 2.7 |
| 2.9 | GET /terminal/neglect/common/app/getfoodInfoByFoodId?foodId=xxx |
POST /neglect/pickup/food/detail |
方法由 GET 改为 POST;入参从 Query foodId 改为 IdDTO body |
同 2.7 |
| 2.10 | GET /terminal/neglect/common/app/getYxEquipmentByEquipmentCode |
GET /neglect/pickup/device/config |
路径变更,方法保留 GET,无入参 | 新增 payType 字段(吐盘机无意义,仅档口秤用) |
| 2.11 | POST /terminal/neglect/nutrition/scale/app/updateScaleRealTimeWeight |
POST /neglect/pickup/weight |
DTO 字段精简:移除 deviceId(由请求头携带),保留 foodId/foodWeight;类型 foodId 由 String 改为 Long |
响应仍为空 |
| 2.12 | GET /terminal/neglect/common/app/getCurrentPlaceMeal |
GET /neglect/pickup/meal/current |
路径变更,方法保留 GET | 字段类型由 String 改为 LocalDateTime(仍按 yyyy-MM-dd HH:mm:ss 序列化) |
| 2.13 | GET /terminal/neglect/common/app/getMemberDiscount?userId=xxx |
POST /neglect/pickup/member/discount |
方法由 GET 改为 POST;入参从 Query userId 改为 IdDTO body |
返回类型由 Double 改为 BigDecimal |
6.3 新版新增接口(老版无对应)
| 接口号 | 路径 | 用途 |
|---|---|---|
| P-06 | /neglect/pickup/food/by-names |
按多个菜品名称查询(顺序一致),开餐页面批量查询 |
| P-08 | /neglect/pickup/meal/add |
加菜(从老 2.3 拆分独立) |
| P-16 | /neglect/pickup/ingredient/search |
食材库存搜索(按溯源码分组) |
| P-17 | /neglect/pickup/dict/process-step |
加工步骤字典 |
| P-18 | /neglect/pickup/clean-process/add |
净菜加工记录新增 |
| P-19 | /neglect/pickup/sampling/categories |
采样菜品分类列表 |
| P-20 | /neglect/pickup/sampling/food/search |
采样菜品搜索 |
| P-21 | /neglect/pickup/sampling/save |
保存采集图片及向量 |
| P-22 | /neglect/pickup/sampling/history/page |
采样历史分页 |
| P-23 | /neglect/pickup/sampling/history/detail |
菜品采样全部图片 |
6.4 字段类型迁移注意事项
- ID 字段统一 Long:老版
foodId/userId/specId/foodMaterialId全为 String,新版统一为 Long;JSON 序列化时仍以 String 形式输出,避免 JS 精度丢失,但 APP 端反序列化目标类型需调整为 Long。 - 重量字段统一 BigDecimal:老版
foodWeight/eatWeight为 String,新版改为 BigDecimal,杜绝字符串数字解析异常。 - 价格单位变化:
FoodInfo.price由「元/千克」改为「元/100g」,APP 端计价公式需同步调整:总价 = 重量(g) × price / 100。 - VIP 价格概念移除:
vipPrice固定返回 null,会员优惠改走member/discount接口拿折扣系数。 personType字段新增:人脸 VO 新增personType(1-员工,2-工作人员,3-普通用户,4-外部人员,5-会员),用于设备端差异化提示。