- FaceDao新增queryByUserFaceId接口,实现按userFaceId精确查询 - FaceApi新增queryByUserFaceId方法,封装Dao查询逻辑 - LoginByFaceActivity插入人脸时,先按userFaceId查询,存在则更新避免重复 - NetViewModelV2同步人脸数据时,优先用userFaceId判重,减少重复入库 - 修正FaceEntity中userId字段数据库列名错误(user_id替代user_idd) - 增加注释说明及代码格式优化,提升代码可读性和健壮性
1273 lines
42 KiB
Markdown
1273 lines
42 KiB
Markdown
# 吐盘机(营养秤)接口文档
|
||
|
||
> Controller:`NutPickupScaleController`
|
||
> 模块前缀:`/neglect/pickup`
|
||
> Nacos 白名单:`/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>`:
|
||
|
||
```json
|
||
{
|
||
"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) |
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{
|
||
"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-会员 |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"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 |
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{
|
||
"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 | 否 | 菜品名称关键词,不传则返回当餐全部菜品 |
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{
|
||
"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` 字段) |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"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`
|
||
|
||
返回当前食堂 + 当前餐次下所有可供应菜品。无入参。
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{ }
|
||
```
|
||
|
||
**响应 `data`** — `List<NutTerminalAppFoodVO>`,字段同 P-03
|
||
|
||
---
|
||
|
||
#### 接口 P-05 — 菜品详情
|
||
|
||
**POST** `/neglect/pickup/food/detail`
|
||
|
||
**入参(Body JSON)** — `IdDTO`
|
||
|
||
| 字段 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `id` | Long | 是 | 菜品 id(foodId) |
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{ "id": 2001 }
|
||
```
|
||
|
||
**响应 `data`** — `NutTerminalAppFoodVO`,字段同 P-03
|
||
|
||
---
|
||
|
||
#### 接口 P-06 — 按多个菜品名称查询(顺序一致)
|
||
|
||
**POST** `/neglect/pickup/food/by-names`
|
||
|
||
开餐页面批量按名称查询菜品,返回顺序与传入 `nameList` 一致。
|
||
|
||
**入参(Body JSON)** — `NutPickupFoodNamesQuery`
|
||
|
||
| 字段 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `nameList` | List\<String\> | 是 | 菜品名称列表,至少 1 条 |
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{
|
||
"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 携带。
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{
|
||
"foodId": 2001,
|
||
"foodName": "宫保鸡丁",
|
||
"foodWeight": 5000,
|
||
"powerOnTime": "2026-06-29 10:30:00"
|
||
}
|
||
```
|
||
|
||
**响应 `data`** — 无(`Result<Void>`),仅以 `code` 判断成功
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{ "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(餐盘号) |
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{ "id": 88001 }
|
||
```
|
||
|
||
**响应 `data`** — `String`,主单 recordNo(`Result.saveSuccess` 包装,新建或刷新)
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"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`](../../platform-nutrition/nutrition-service/src/main/java/com/platform/nutrition/service/impl/NutPickupScaleAppServiceImpl.java) 在主单查找之前完成,过滤条件严格按 `(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,就餐时原样回传) |
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{
|
||
"userId": 88001,
|
||
"foodId": 2001,
|
||
"foodName": "宫保鸡丁",
|
||
"specId": 0,
|
||
"foodWeight": 200,
|
||
"eatWeight": 150,
|
||
"member": true,
|
||
"cookOrderId": 1000123
|
||
}
|
||
```
|
||
|
||
**响应 `data`** — `String`,主单 id(`Result.saveSuccess` 包装)
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"code": "00000",
|
||
"msg": "success",
|
||
"data": "1000456",
|
||
"total": 0
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### 接口 P-10 — 按用户 id(餐盘号)查本餐就餐数据
|
||
|
||
**POST** `/neglect/pickup/plate-food`
|
||
|
||
按餐盘号(= userId)查询本餐次已就餐明细,实时聚合主单 + 子表 + 营养现算。
|
||
|
||
**入参(Body JSON)** — `IdDTO`
|
||
|
||
| 字段 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `id` | Long | 是 | 用户 id(餐盘号) |
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{ "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` |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"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` 头携带。
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{
|
||
"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 |
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{ "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 | 提示信息(暂未启用) |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"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-联合结算;吐盘机无意义 |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"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` |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"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 |
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{ "id": 88001 }
|
||
```
|
||
|
||
**响应 `data`** — `BigDecimal`
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"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 | 否 | 食材名称(模糊) |
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{
|
||
"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 | 净菜类型名称(如 洗净米、肉片、豆腐块) |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"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 | 修改时间 |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"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 | 否 | 备注 |
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{
|
||
"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 | 分类名称(主食/荤菜/素菜/汤品/饮品) |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"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 | 否 | 菜品名称,支持模糊搜索 |
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{
|
||
"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) |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"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 列表
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"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 | 否 | 菜品名称,支持模糊搜索 |
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{
|
||
"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 | 最近采样时间 |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"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 |
|
||
|
||
**入参示例**
|
||
|
||
```json
|
||
{ "id": 2001 }
|
||
```
|
||
|
||
**响应 `data`** — `List<NutSamplingDetailVO>`
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `id` | String | 采集图片 id |
|
||
| `foodPic` | String | 采集图片 URL |
|
||
| `createTime` | String | 采样时间 |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"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 字段类型迁移注意事项
|
||
|
||
1. **ID 字段统一 Long**:老版 `foodId/userId/specId/foodMaterialId` 全为 String,新版统一为 Long;JSON 序列化时仍以 String 形式输出,避免 JS 精度丢失,但 APP 端反序列化目标类型需调整为 Long。
|
||
2. **重量字段统一 BigDecimal**:老版 `foodWeight/eatWeight` 为 String,新版改为 BigDecimal,杜绝字符串数字解析异常。
|
||
3. **价格单位变化**:`FoodInfo.price` 由「元/千克」改为「元/100g」,APP 端计价公式需同步调整:`总价 = 重量(g) × price / 100`。
|
||
4. **VIP 价格概念移除**:`vipPrice` 固定返回 null,会员优惠改走 `member/discount` 接口拿折扣系数。
|
||
5. **`personType` 字段新增**:人脸 VO 新增 `personType`(1-员工,2-工作人员,3-普通用户,4-外部人员,5-会员),用于设备端差异化提示。
|