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

11 KiB
Raw Blame History

配比秤(新设备)— 采样模式 API 文档

Controller: NutRatioScaleController 路径前缀: /neglect/ratio-scaleNacos 白名单 /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: <设备编码>

根据餐厅查餐品名称,供硬件端选择目标菜品(有该餐品时回显其构成)。

请求体

{
  "keyword": "西兰花",       // 选填 — 菜品名称或编号模糊搜索
  "pageNum": 1,              // 必填 — 页码
  "pageSize": 20             // 必填 — 每页条数
}

响应

{
  "code": "00000",
  "msg": "操作成功",
  "data": [
    {
      "foodId": "2091839370283118593",   // 菜品id
      "foodCode": "FOOD00012",           // 菜品编号
      "foodName": "清炒西兰花"            // 菜品名称
    }
  ],
  "total": 1
}

逻辑说明

  • 数据源:nut_foodstatus=1 上架)
  • 过滤:canteen_id = 当前食堂
  • 关键词模糊匹配 food_namefood_code
  • 排序:id DESC

二、查菜品构成

GET /neglect/ratio-scale/food/{foodId}/composition
X-DEVICE-CODE: <设备编码>

根据菜品 id 查询已有菜品的主辅料+调料构成及熟重,供硬件端回显构成数据。

响应

{
  "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
  • foodWeightnut_food_cook.output_weight 反查

三、食材模糊搜索

POST /neglect/ratio-scale/mater-search
Content-Type: application/json
X-DEVICE-CODE: <设备编码>

称量食材前,从食材库检索食材(设备对应食堂食材)。

请求体

{
  "keyword": "萝卜",          // 选填 — 模糊匹配食材名称和别名
  "pageNum": 1,              // 必填 — 页码
  "pageSize": 20             // 必填 — 每页条数
}

响应

{
  "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_namealias
  • 排序:mater_name ASC

四、提交采样(落库味养创新)

POST /neglect/ratio-scale/constitute/save
Content-Type: application/json
X-DEVICE-CODE: <设备编码>

⚠️ 接口变更标注:原提交接口含 cookMode(区分制作/采样),现制作模式已废弃,本接口统一为「提交采样」,入参去掉 cookModefoodId 字段。

后厨称量食材 + 熟重后提交,后端落库到 味养创新实验nut_innovation,人工创新,状态 = 实验中)。

请求体

{
  "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
    }
  ]
}

响应

{
  "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重复 菜品食材不能重复,重复食材idxxx
熟重/用量 ≤ 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),分页返回、按提交时间倒序,供硬件端回看。

请求体

{
  "pageNum": 1,              // 必填 — 页码
  "pageSize": 20             // 必填 — 每页条数
}

响应

{
  "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 已转化