Files
DishMatch/配比秤-采样模式-API文档.md
T
mazengfei 94bcdb3d9b feat(ratio-scale): 新增烹饪时长采集及调料放置时间支持
- 配比秤采样提交接口新增字段 cookStart,传递烹饪开始时间
- 食材构成中调料项新增 putTime 字段,记录调料首次使用时间
- 设备端提交采样时食材构造调整,调料按名称匹配 putTime 填充
- 新增对烹饪时长的后端计算功能,时长单位为分钟自动向上取整
- 采样列表接口响应新增 cookStart 与 cookDuration 字段,用于显示烹饪时长
- 配比秤采样模式相关API文档同步更新,废弃制作模式接口及字段
- 烹饪完成接口要求强化传递 cookStart,后端基于此计算并更新烹饪时长
- 关联数据库迁移支持烹饪时长字段持久化及历史记录完善
2026-09-21 14:21:17 +08:00

352 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 配比秤(新设备)— 采样模式 API 文档
> Controller: `NutRatioScaleController`
> 路径前缀: `/neglect/ratio-scale`Nacos 白名单 `/nutrition/neglect/**`,无需 Sa-Token
> 设备上下文通过请求头 `X-DEVICE-CODE` 解析(`TerminalContextHelper`,据此拿到食堂 id
> 日期: 2026-09-10
>
> **序列化规则**:Long 类型字段响应中均为字符串(Jackson `ToStringSerializer`),`BigDecimal` 为普通数字
> **单位约定**
> - 提交采样的熟重 `foodWeight` 单位为 **克 (g)**
> - 食材称量用量 `useWeight` 单位为 **克 (g)**
---
## 业务背景
配比秤「采样」复用 **味养创新(nut_innovation** 的人工创新实验流程,不再直接落 `nut_food` 主表。
### 完整流程(3 步)
```
① 提交采样(设备端) → 落库味养创新实验,状态 = 1 实验中
② 提交评测(味养创新后台)→ 计算营养 + 完善检验信息,状态 = 2 已评测
③ 转化餐品(味养创新后台)→ 走 nut_food 新建餐品流程关联,状态 = 9 已转化
```
### 设备端职责边界
配比秤设备端只负责 **① 提交采样**(称量食材 + 熟重 → 写味养创新实验)。后续的 **② 提交评测**、**③ 转化餐品** 走味养创新已有的后台接口(`/nut/innovation`),不在设备端范围内。
### 采样交互流程
```
搜菜品(food-search
├─ 有目标餐品 → 查菜品构成(food/{foodId}/composition)回显 → 可增删构成
└─ 无目标餐品 → 食材模糊搜索(mater-search)自己添加食材/调料
提交采样(constitute/save)→ 落库味养创新
```
### 食材分类枚举
| 分类 | 名称 | 说明 |
|:----:|------|------|
| 1 | 主材 | 菜品主要食材 |
| 2 | 辅材 | 菜品辅助食材 |
| 3 | 调料 | 油盐酱醋等 |
---
## 接口清单
| 序号 | 接口 | 路径 | 用途 |
|:----:|------|------|------|
| 一 | 搜菜品 | `POST /neglect/ratio-scale/food-search` | 按名称模糊查上架菜品 |
| 二 | 查菜品构成 | `GET /neglect/ratio-scale/food/{foodId}/composition` | 按菜品id查主辅料+调料,回显构成 |
| 三 | 食材模糊搜索 | `POST /neglect/ratio-scale/mater-search` | 采样称量前检索食材 |
| 四 | 提交采样 | `POST /neglect/ratio-scale/constitute/save` | **落库味养创新实验** |
| 五 | 已提交采样列表 | `POST /neglect/ratio-scale/sample-list` | 按日期查已提交采样,默认当天 |
---
## 一、搜菜品
```
POST /neglect/ratio-scale/food-search
Content-Type: application/json
X-DEVICE-CODE: <设备编码>
```
根据餐厅查餐品名称,供硬件端选择目标菜品(有该餐品时回显其构成)。
### 请求体
```json
{
"keyword": "西兰花", // 选填 — 菜品名称或编号模糊搜索
"pageNum": 1, // 必填 — 页码
"pageSize": 20 // 必填 — 每页条数
}
```
### 响应
```json
{
"code": "00000",
"msg": "操作成功",
"data": [
{
"foodId": "2091839370283118593", // 菜品id
"foodCode": "FOOD00012", // 菜品编号
"foodName": "清炒西兰花" // 菜品名称
}
],
"total": 1
}
```
### 逻辑说明
- 数据源:`nut_food``status=1` 上架)
- 过滤:`canteen_id` = 当前食堂
- 关键词模糊匹配 `food_name``food_code`
- 排序:`id DESC`
---
## 二、查菜品构成
```
GET /neglect/ratio-scale/food/{foodId}/composition
X-DEVICE-CODE: <设备编码>
```
根据菜品 id 查询已有菜品的主辅料+调料构成及熟重,供硬件端回显构成数据。
### 响应
```json
{
"code": "00000",
"msg": "操作成功",
"data": {
"foodId": "2091839370283118593", // 菜品id
"foodName": "清炒西兰花", // 菜品名称
"foodWeight": 450.0, // 熟重(g)
"ingredients": [
{
"materId": "1979825467306471454", // 食材id
"materName": "樱桃萝卜", // 食材名称
"useWeight": 300.0, // 用量(g)
"isMain": 1, // 1=主材 / 2=辅材 / 3=调料
"isMainName": "主材"
}
]
}
}
```
### 逻辑说明
- 数据源:`nut_food_composition`(按 `food_id` 查全部构成)
- 食材名称从 `nut_mater_base` **批量反查**(无 N+1
- `foodWeight``nut_food_cook.output_weight` 反查
---
## 三、食材模糊搜索
```
POST /neglect/ratio-scale/mater-search
Content-Type: application/json
X-DEVICE-CODE: <设备编码>
```
称量食材前,从食材库检索食材(设备对应食堂食材)。
### 请求体
```json
{
"keyword": "萝卜", // 选填 — 模糊匹配食材名称和别名
"pageNum": 1, // 必填 — 页码
"pageSize": 20 // 必填 — 每页条数
}
```
### 响应
```json
{
"code": "00000",
"msg": "操作成功",
"data": [
{
"id": "1979825467306471454", // 食材id
"materName": "樱桃萝卜", // 食材名称
"materCode": "04041012", // 食材编码
"alias": null, // 别名
"materFirstClass": "04", // 食材一级分类
"materSecondClass": "043", // 食材二级分类
"materUrl": null, // 食材图片url
"canteenId": "2" // 归属食堂id
}
],
"total": 1
}
```
### 逻辑说明
- 数据源:`nut_mater_base`
- 过滤:`canteen_id` = 当前食堂(由 `X-DEVICE-CODE` 解析)
- 关键词模糊匹配 `mater_name``alias`
- 排序:`mater_name ASC`
---
## 四、提交采样(落库味养创新)
```
POST /neglect/ratio-scale/constitute/save
Content-Type: application/json
X-DEVICE-CODE: <设备编码>
```
> ⚠️ **接口变更标注**:原提交接口含 `cookMode`(区分制作/采样),现制作模式已废弃,本接口统一为「提交采样」,入参去掉 `cookMode`、`foodId` 字段。
后厨称量食材 + 熟重后提交,后端落库到 **味养创新实验**`nut_innovation`,人工创新,状态 = 实验中)。
### 请求体
```json
{
"foodName": "清炒西兰花", // 必填 — 菜品名称
"foodWeight": 500, // 必填 — 熟重(g),必须 > 0
"items": [ // 必填 — 食材构成列表,至少1条
{
"materId": 20001, // 必填 — 食材idnut_mater_base.id
"useWeight": 300, // 必填 — 食材称量用量(g),必须 > 0
"isMain": 1 // 必填 — 食材分类: 1=主材 / 2=辅材 / 3=调料
},
{
"materId": 30001,
"useWeight": 50,
"isMain": 3
}
]
}
```
### 响应
```json
{
"code": "00000",
"msg": "操作成功",
"data": null
}
```
### 处理流程
```
1. 校验食材构成非空 + materId 非空且唯一
2. 反查食材名称(nut_mater_base + 一级分类名称(nut_mater_class
3. 构建味养创新实验 DTO
- foodName → food_name
- foodWeight → food_weight(熟重)
- items → 食材构成(mater_id + mater_name + mater_cat + amount_g + is_main
- canteenId → 从 X-DEVICE-CODE 解析
- startDate → 回填当天(实验开始日期)
- source / deviceCode → 来源标识(2) + 设备编码
- innovGoal → 默认值「配比秤采样」
4. 调用味养创新 manualAdd,落库 nut_innovationstatus=1 实验中)+ nut_innovation_ing(食材构成)
5. 自动初始化营养:按食材构成 + 熟重计算每100g熟重营养,写入草稿评测事件 nut_innovation_evalstatus=0+ 营养维度 nut_innovation_eval_nutri7 项:热量/蛋白/碳水/脂肪/维C/膳食纤维/钠,mineral 留空)
```
> 注:设备端不传 `foodCategory`(餐品分类),落库为空,后期在味养创新后台维护;`innovGoal`(创新目标)后端填默认值「配比秤采样」,后续可改。
### 异常场景
| 场景 | 错误信息 |
|------|---------|
| 食材构成列表为空 | `请完善菜品构成信息` |
| 食材id为空 | `菜品食材不能为空` |
| 食材id重复 | `菜品食材不能重复,重复食材id:xxx` |
| 熟重/用量 ≤ 0 | 参数校验:`熟重必须大于0` / `食材用量必须大于0` |
### 涉及数据表
| 表名 | 操作 | 说明 |
|------|:--:|------|
| `nut_innovation` | 新增 | 味养创新实验(status=1 实验中,含熟重 food_weight |
| `nut_innovation_ing` | 新增 | 食材构成(mater_id + mater_name + mater_cat + amount_g + is_main |
| `nut_innovation_eval` | 新增 | 草稿评测事件(status=0,采样时初始化) |
| `nut_innovation_eval_nutri` | 新增 | 营养维度(7 项自动计算值,mineral 留空) |
| `nut_mater_base` | 查询 | 反查食材名称 + 营养数据(计算营养) |
| `nut_mater_class` | 查询 | 反查一级分类名称 |
---
## 五、已提交采样列表
```
POST /neglect/ratio-scale/sample-list
Content-Type: application/json
X-DEVICE-CODE: <设备编码>
```
查询本食堂已提交的采样记录(味养创新实验 `source=2`),分页返回、按提交时间倒序,供硬件端回看。
### 请求体
```json
{
"pageNum": 1, // 必填 — 页码
"pageSize": 20 // 必填 — 每页条数
}
```
### 响应
```json
{
"code": "00000",
"msg": "操作成功",
"data": [
{
"innovId": "2097486806812893186", // 味养创新实验id
"innovNo": "INN-H-2026-001", // 实验编号
"foodName": "清炒西兰花", // 餐品名称
"foodWeight": 500.0, // 熟重(g)
"status": 1, // 状态: 1实验中/2已评测/9已转化
"statusName": "实验中", // 状态中文
"createTime": "2026-09-11 10:30:00" // 提交时间
}
],
"total": 1
}
```
### 逻辑说明
- 数据源:`nut_innovation`
- 过滤:`canteen_id` = 当前食堂 + `source` = 2(配比秤采样,后台手动为 1)
- 排序:`create_time DESC`(查所有,不分日期)
---
## 数据链路图(提交采样 → 味养创新)
```
nut_mater_base (食材库)
│ 称量 mater_id + use_weight(g) + 熟重 food_weight(g)
POST /constitute/save
├── 生成 nut_innovation (味养创新实验,status=1 实验中,含 food_weight)
├── 生成 nut_innovation_ing (食材构成:mater_id + mater_name + mater_cat + amount_g + is_main)
└── 自动算营养 → nut_innovation_eval(草稿) + nut_innovation_eval_nutri(7项)
后续(味养创新后台,非设备端):
├── 提交评测 → 复核营养 + 补味道/口感/色泽,status=2 已评测
└── 转化餐品 → nut_food(新建餐品流程),convert_food_id 关联,status=9 已转化
```