文件
hl-api-changelog/changelogs-v2/2026-09/21_8093_套用用餐模版改只读返回组合结果与模版桌人创建人搜索删除-修改接口-管理后台.md
T
lc和Claude Opus 5 1653a52e59
changelog-filename-gate / validate (push) Failing after 2s
docs(order-v3): #8093 Changelog 补齐五、数据库行为与 4.2/4.4 缺失小节
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 16:52:25 +08:00

22 KiB
原始文件 Blame 文件历史

schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
schema ticket title consumer author change_type backend_status gateway_status frontend_status frontend_owner frontend_ref target_release verified_at status_note updated_at base
hl-changelog/v2 8093 套用用餐模版改为只读返回组合结果,模版加桌数人数与创建人、模糊搜索与删除 admin lc(GIT) 修改接口 deployed verified pending 套用用餐模版由写库改为只读:只返回「模版+订单出发日」组合出来的行,不含订单原有行、库里一行不动;订单原有行由前端把这些行原样提交整单保存时按现有规则软删。行上人数、桌数、价钱、桌/人、金额后端已算好。模版列表新增创建人姓名与行上桌数、人数、桌/人;模版名由精确改模糊并新增创建人模糊搜索;新增删除模版接口。前端必须按本文改调用方式。 2026-09-21 dev-v3

order-v3: 套用用餐模版改为只读返回组合结果,模版加桌数人数与创建人、模糊搜索与删除

服务: hl-order-service-v3 PR: #8105 Issue: #8093 日期: 2026-09-21 影响范围: 管理后台订单详情「用餐」页签的套用模版与模版列表;新增删除模版


⚠️ 关键变化

  • 🔁 套用模版不再写库(破坏性):POST /v3/admin/order/meal-template/apply 由写接口变为只读接口。调用它不会把模版内容存进订单,返回里也不再包含这张订单原来的用餐行,只返回「模版 + 订单出发日」组合出来的行。原来的行要等前端把这些行原样提交整单保存(POST /v3/admin/order/meal-info/save)时,才按现有「原来有而这次没传上来的软删」规则去掉。前端如果沿用「套用成功后重新查一次列表就当保存好了」的做法,用户的套用结果不会入库。
  • ✅ 套用返回的行后端已算好:人数、桌数、价钱、桌/人、金额都由后端给出,免人数 / 免金额 / 其他成本为 0,前端直接展示,不需要再算金额。
  • 🆕 套用返回的行新增 priceUnit(桌/人):由桌数是否为 0 派生,取值 person / table,不存库。3.1–3.4 的行没有这个字段。
  • 🔁 模版名搜索由精确改为模糊:templateName 改为「包含即命中」。原来传全名的调用仍能命中,但会一并带出名称含该串的其他模版。
  • 🆕 模版列表新增创建人:模版级新增 creatorName(中文姓名),并新增同名入参按创建人模糊搜索。
  • 🆕 新增删除模版接口 POST /v3/admin/order/meal-template/delete。

二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 套用用餐模版 POST /v3/admin/order/meal-template/apply 修改 由写库改为只读;返回内容变化;行上新增 priceUnit
2 查询用餐模版 GET /v3/admin/order/meal-template/list 修改 新增入参 creatorName;templateName 改模糊;出参新增 creatorName 与行上 tableCount/personCount/priceUnit
3 保存为用餐模版 POST /v3/admin/order/meal-template/save 修改 入参不变;模版一并存下源用餐行的桌数、人数;出参行新增上述三个字段
4 删除用餐模版 POST /v3/admin/order/meal-template/delete 新增 按模版ID软删该模版全部行

3.1 查询、3.2 生成、3.3 整单保存、3.4 重置的入参与出参一个字段都没变。


三、接口详情

1. 套用用餐模版 POST /v3/admin/order/meal-template/apply

VO: MealTemplateApplyReqVO → OrderMealInfoListRespVO

使用场景

订单详情「用餐」页签点「套用模版」,把某个模版的内容按订单出发日铺开,展示给用户预览;用户确认后再点保存。

入参字段表

字段 位置 类型 必填 约束 说明
orderId Body String 是 雪花 ID 订单 ID(不变)
templateId Body String 是 雪花 ID 模版 ID(不变)

出参字段表

字段 类型 说明
items Array 内容变化。只含这个模版套出来的行,不含该订单原来的用餐行
items[].mealInfoId String 恒为 null:这些行还没入库
items[].dayNumber Integer 模版的第几日
items[].mealDate String 订单出发日 + dayNumber − 1(出发日是第 1 日)
items[].restaurantId / restaurantName / dishId / dishName / unitPrice / settleType / settleTypeName — 取模版,原样返回
items[].tableCount Integer 后端算好。取模版的桌数
items[].personCount Integer 后端算好。桌数为 0(按人)取订单人数;桌数不为 0(按桌)为 0
items[].priceUnit String 新增。person(桌数为 0)/ table(桌数不为 0),派生值,不存库
items[].freePersonCount / freeAmount / otherCost — 恒为 0
items[].amount Number 后端算好。按人 = 单价 ×(人数 − 免人数)− 免金额 + 其他成本;按桌 = 单价 × 桌数 − 免金额 + 其他成本
totalAmount Number 本次返回各行金额之和
orderId / groupBatchId / batchNo / departDate / returnDate / personCount / orderEditable / generated — 口径与 3.1 相同,未变

请求示例

POST /v3/admin/order/meal-template/apply
Authorization: Bearer <admin token>
Content-Type: application/json

{ "orderId": "2101846199160188929", "templateId": "2101952572174860290" }

响应示例

订单出发日 2026-11-10、订单人数 2,模版 3 行(早餐默认行、午餐按人 30 元、晚餐按桌 888 元 × 2 桌):

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "orderId": "2101846199160188929",
    "departDate": "2026-11-10",
    "personCount": 2,
    "orderEditable": true,
    "generated": true,
    "totalAmount": 1836.00,
    "items": [
      {
        "mealInfoId": null,
        "mealType": "BREAKFAST", "dayNumber": 1, "mealDate": "2026-11-10",
        "restaurantName": "HL8093-TEST-默认餐厅", "dishName": "HL8093-TEST-默认餐",
        "unitPrice": 0.00, "tableCount": 0, "personCount": 2, "priceUnit": "person",
        "freePersonCount": 0, "freeAmount": 0.00, "otherCost": 0.00, "amount": 0.00
      },
      {
        "mealInfoId": null,
        "mealType": "LUNCH", "dayNumber": 1, "mealDate": "2026-11-10",
        "restaurantName": "HL8093-TEST-按人餐厅", "dishName": "HL8093-TEST-按人餐",
        "unitPrice": 30.00, "tableCount": 0, "personCount": 2, "priceUnit": "person",
        "freePersonCount": 0, "freeAmount": 0.00, "otherCost": 0.00, "amount": 60.00,
        "settleType": "sign", "settleTypeName": "签单"
      },
      {
        "mealInfoId": null,
        "mealType": "DINNER", "dayNumber": 1, "mealDate": "2026-11-10",
        "restaurantName": "HL8093-TEST-按桌餐厅", "dishName": "HL8093-TEST-按桌餐",
        "unitPrice": 888.00, "tableCount": 2, "personCount": 0, "priceUnit": "table",
        "freePersonCount": 0, "freeAmount": 0.00, "otherCost": 0.00, "amount": 1776.00,
        "settleType": "cash", "settleTypeName": "现付"
      }
    ]
  }
}

空数据 / 降级响应

  • 模版一行都没有:items 为 []、totalAmount 为 0.00,code 仍为 200。
  • 订单没有出发日期:无法对天,items 为 [],code 200,message 为「订单缺少出发日期」提示(589602 文案)。

错误响应

{ "code": 589607, "message": "订单已完成或已取消,不能修改用餐信息", "success": false, "data": null }

订单不可写按 581045 / 581008;订单不存在按订单模块现有错误码。这些判断与改动前一致。

业务边界

  • 调用套用不改库:调用前后用 3.1 按该订单查询,返回逐字段完全一致。
  • 模版第 d 日超出订单行程天数时不做限制,照落在出发日 + d − 1。
  • 模版值原样带出,不核对餐食、餐厅是否还存在或已下架。

2. 查询用餐模版 GET /v3/admin/order/meal-template/list

VO: MealTemplateListReqVO → List<MealTemplateRespVO>

使用场景

「套用模版」弹层里选模版,支持按模版名、创建人搜索。

入参字段表

字段 位置 类型 必填 约束 说明
templateId Query String 否 雪花 ID 精确查;传了就忽略下面两个条件
templateName Query String 否 ≤ 500 字符 由精确匹配改为模糊匹配(包含即命中)
creatorName Query String 否 ≤ 100 字符 新增。按创建人中文姓名模糊匹配(包含即命中,忽略大小写)

组合口径:templateName 与 creatorName 同传取同时满足的模版;只传一个按该条件筛;都不传返回全部;传 templateId 时按 ID 精确查且不受这两个条件影响。

出参字段表

字段 类型 说明
[].templateId / templateName — 不变
[].creatorName String 新增。创建人中文姓名:企微姓名,没绑企微取登录名;取不到时为 null
[].items[].tableCount Integer 新增。桌数,0 表示按人算
[].items[].personCount Integer 新增。人数(模版内容回显用)
[].items[].priceUnit String 新增。person / table,由桌数派生,不存库
[].items[] 其余字段 — restaurantId、restaurantName、dishId、dishCode、dishName、mealType、dayNumber、unitPrice、settleType、settleTypeName 均不变

请求示例

GET /v3/admin/order/meal-template/list?templateName=HL8093&creatorName=%E5%88%98
Authorization: Bearer <admin token>

creatorName 是中文时必须按 URL 编码传。

响应示例

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": [
    {
      "templateId": "2101952572174860290",
      "templateName": "HL8093-TEST-桌人模版",
      "creatorName": "刘畅",
      "items": [
        {
          "mealType": "LUNCH", "dayNumber": 1,
          "restaurantName": "HL8093-TEST-按人餐厅", "dishName": "HL8093-TEST-按人餐",
          "unitPrice": 30.00, "tableCount": 0, "personCount": 4, "priceUnit": "person",
          "settleType": "sign", "settleTypeName": "签单"
        },
        {
          "mealType": "DINNER", "dayNumber": 1,
          "restaurantName": "HL8093-TEST-按桌餐厅", "dishName": "HL8093-TEST-按桌餐",
          "unitPrice": 888.00, "tableCount": 2, "personCount": 0, "priceUnit": "table",
          "settleType": "cash", "settleTypeName": "现付"
        }
      ]
    }
  ]
}

空数据 / 降级响应

  • data 为 []:没有同时满足条件的模版。
  • 用户服务取不到姓名时,该模版 creatorName 为 null,列表照常返回;此时若传了 creatorName 条件,该模版不会被返回。

错误响应

{ "code": 400, "message": "创建人姓名最多100字符", "success": false, "data": null }

业务边界

  • 按模版 ID 分组,重名的是各自独立的模版;列表按模版 ID 升序(保存先后)。
  • 模版名片段里的 %、_ 已做转义,不会被当通配符放大匹配范围。

3. 保存为用餐模版 POST /v3/admin/order/meal-template/save

VO: MealTemplateSaveReqVO → MealTemplateRespVO

使用场景

订单详情「用餐」页签上把当前排好的用餐行「保存为模版」,供以后套到别的订单上。

入参字段表

字段 位置 类型 必填 约束 说明
templateName Body String 是 ≤ 500 字符 不变
mealInfoIds Body Array 是 非空 不变

入参没有变化,前端不需要多传字段。

出参字段表

字段 类型 说明
creatorName String 新增。当前操作人的中文姓名
items[].tableCount / personCount / priceUnit — 新增,口径同 4.1
templateId / templateName / items[] 其余字段 — 不变

请求示例

POST /v3/admin/order/meal-template/save
Authorization: Bearer <admin token>
Content-Type: application/json

{ "templateName": "HL8093-TEST-桌人模版", "mealInfoIds": ["2101952551211728898", "2101952551157202945"] }

响应示例

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "templateId": "2101952572174860290",
    "templateName": "HL8093-TEST-桌人模版",
    "creatorName": "刘畅",
    "items": [
      {
        "mealType": "DINNER", "dayNumber": 1,
        "restaurantName": "HL8093-TEST-按桌餐厅", "dishName": "HL8093-TEST-按桌餐",
        "unitPrice": 888.00, "tableCount": 2, "personCount": 0, "priceUnit": "table",
        "settleType": "cash", "settleTypeName": "现付"
      }
    ]
  }
}

空数据 / 降级响应

不存在空数据形态:mealInfoIds 一行都取不到时走错误响应(589606)。企微姓名取不到时 creatorName 为 null,模版照常保存成功。

错误响应

{ "code": 589606, "message": "没有可保存为模版的用餐信息", "success": false, "data": null }

业务边界

  • 模版现在会一并存下源用餐行的桌数、人数;改动前不存,所以已有的老模版这两项都是 0(等同「按人算、人数未知」),套用时按人的行人数仍取订单人数,金额不受影响。
  • 每次保存生成新的模版 ID,不覆盖已有模版。

4. 删除用餐模版 POST /v3/admin/order/meal-template/delete

VO: MealTemplateDeleteReqVO → Result<Void>

使用场景

模版列表上删除某个模版。

入参字段表

字段 位置 类型 必填 约束 说明
templateId Body String 是 雪花 ID 要删除的模版 ID

请求示例

POST /v3/admin/order/meal-template/delete
Authorization: Bearer <admin token>
Content-Type: application/json

{ "templateId": "2101953000000000001" }

出参字段表

字段 类型 说明
code Integer 200 表示删除成功;模版不存在或已删除同样返回 200
data null 恒为 null,该接口不返回业务数据

响应示例

{ "code": 200, "message": "成功", "success": true, "data": null }

空数据 / 降级响应

不存在空数据形态:data 恒为 null。删除一个不存在或已删除的模版属于正常成功路径,不是降级,code 仍为 200。

错误响应

{ "code": 400, "message": "模版ID不能为空", "success": false, "data": null }

业务边界

  • 幂等:模版不存在或已经删过,同样返回成功,前端不需要处理「已删除」的失败分支。
  • 软删该模版的全部行;已经保存到订单上的用餐行不受影响。
  • 权限门槛与查询、保存一致(房务 / 组长角色 581045)。

四、契约约束与正确调用方式

  • 套用后必须再调一次整单保存,流程改为:点「套用模版」→ 调 4.3 拿到组合结果 → 在页面上展示(可让用户继续改)→ 用户点「保存」→ 把这些行(连同用户的修改)提交 POST /v3/admin/order/meal-info/save。只调 4.3 不调 3.3,什么都不会入库。
  • 提交 3.3 时这些行不带 mealInfoId(为 null),后端按新增处理;订单原来的行因为没被传上来,按现有规则软删。
  • priceUnit 是只读派生字段,提交 3.3 时带上也会被后端忽略;不要把它当成可编辑项,也不要用它反推桌数。
  • 判断一行「按人还是按桌」只看 tableCount 是否为 0,priceUnit 只是同一判断的展示形式,两者不会互相矛盾。
  • 套用返回的金额已经算好,前端不要再算一遍;用户在页面上改了人数 / 桌数 / 单价后仍按原有方式由前端试算、以 3.3 保存后的后端结果为准。
  • creatorName 作为 query 参数传中文时必须 URL 编码。
  • 老模版的 tableCount / personCount 都是 0,属于正常数据,不是异常。

五、数据库行为

只写前端可观察到的行为,不涉及表结构细节。

  • 套用模版(4.3)不产生任何写入:调用前后用 3.1 按该订单查询,返回逐字段完全一致;不新增、不覆盖、不软删任何用餐行。
  • 订单原有用餐行在整单保存(3.3)时才被去掉:沿用现有规则——这次没传上来的行按软删处理,历史记录仍可追溯,不是物理删除。
  • 保存为模版(4.2) 新增一个模版,同时把源用餐行的桌数、人数一并存下;不改动源用餐行。
  • 删除模版(4.4)是软删,且只作用于该模版自身;已经保存到订单上的用餐行不受影响。对不存在或已删除的模版重复调用不产生写入,仍返回成功。
  • 改动前保存的老模版没有桌数、人数,读取时一律按 0 返回(等同「按人算、人数未知」)。

六、边界行为

  • 模版第 d 日超出订单行程天数:不拦截,照落在出发日 + d − 1。
  • 订单没有出发日期:返回 items: [] 并带提示文案,不报错。
  • 模版为空:返回 items: []、totalAmount: 0.00。
  • 创建人姓名取不到(用户服务异常或查不到该管理员):creatorName 为 null,列表仍正常返回;传了创建人条件时这类模版不返回。

六.6、修改前后对比

项 改动前 改动后
套用是否写库 是(覆盖 / 新建) 否,只读
套用返回内容 该订单全部用餐行(含原有行) 只有模版套出来的行
套出来的行桌数 / 人数 / 金额 都是 0 后端算好(桌数取模版,按人行人数取订单人数,金额按公式)
行上 priceUnit 无 套用返回的行与模版行有(3.1–3.4 仍无)
模版名搜索 精确匹配 模糊匹配
创建人 不返回、不能搜 返回 creatorName,可模糊搜
模版行 tableCount / personCount 不存、不返回 存并返回
删除模版 无接口 新增 4.4

六.7、影响评估

  • 是否破坏向后兼容: 是。4.3 不再写库且返回内容变化,沿用旧流程会导致套用结果不入库
  • 前端是否必须同步上线: 是,必须按第四节改套用流程
  • 前端 workaround 清理点: 去掉「套用成功后直接重查列表」的假设;去掉前端自己算套用行金额的代码

七、不影响范围

  • 仅影响: 用餐模版 4.1 / 4.2 / 4.3 与新增的 4.4
  • 零影响:
    • 3.1 查询、3.2 生成、3.3 整单保存、3.4 重置的入参、出参与行为
    • order_meal_info 表结构与金额公式
    • 订单、团期、结算、房务等其他模块

八、测试环境已验证

部署提交 cc4fb69ed,经 Gateway 用真实 TEST 身份(SUPER_ADMIN)由固定脚本实测 32 项全部通过:

套用零写入(订单 2101846199160188929,原有 10 行)   → 调用前后 3.1 整份 JSON 逐字段一致 ✓
套用返回行数                                         → 3 行 = 模版行数,订单原有 10 行不在返回里 ✓
套用返回行ID                                         → mealInfoId 全为 null ✓
第几日 / 用餐日期                                     → dayNumber=1、mealDate=2026-11-10(出发日+0)✓
按人行(桌数 0,单价 30)                             → 人数=订单人数 2、priceUnit=person、金额 60.00 ✓
按桌行(桌数 2,单价 888)                            → 人数=0、priceUnit=table、金额 1776.00 ✓
免人数 / 免金额 / 其他成本                            → 全为 0 ✓
totalAmount                                          → 1836.00 = 各行金额之和 ✓
原样回提整单保存(假订单)                            → 原 3 行全部软删,只剩套用的 3 行,内容一致 ✓
4.1 创建人                                           → 7 个模版全部返回中文姓名「刘畅」✓
4.2 桌数人数快照                                      → 早/午/晚三行与源用餐行逐项一致(0/0、0/4、2/0)✓
模版名模糊 templateName=HL8093                        → 只返回名称含该片段的模版 ✓
创建人模糊 creatorName=刘                             → 7/7 命中;传对不上的片段返回空 ✓
两条件同传                                           → 取交集;任一条件对不上返回空 ✓
传 templateId                                        → 精确查,忽略另外两个条件 ✓
删除模版                                             → 删后查不到、其他模版不变、重复删除仍成功 ✓
已取消订单套用                                        → 589607 ✓
部署前已有 4 个模版                                   → 原有字段逐字段不变 ✓

十、相关文档

关联 / 联系人

链接

联系人