文件
hl-api-changelog/changelogs-v2/2026-09/23_8230_团期订单支持用餐按团期ID生成保存查询与套用-修改接口-管理后台.md
T
2026-09-24 09:40:22 +08:00

23 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 8230 团期订单支持用餐:生成、保存、重置、查询、套用模版可只传团期ID admin lc(GIT) 修改接口 deployed verified verified mmg 04e08d1a9ddb8ee26f5313fb7a08e3c020225475 v2.1 2026-09-24 已部署 TEST 并经 Gateway 实测通过。用餐的查询、生成、保存、重置、套用模版 5 个接口加入团期维度:orderId 与 groupBatchId 必须且只能传一个,都传或都不传返回 400。只传 groupBatchId 时读写的是团期自己的用餐行(行上团期ID有值、订单ID为空);按订单读写的行此后团期ID为空,按团期查不到子订单的行。团期的出发/返回日期取团期出团日期 depart_date / 结束日期 end_date。前端结论(2026-09-23):现有子订单用餐页(MealTab)5 个调用点全只传 orderId,查询恒有 orderId 空值守卫,零 batchNo/groupBatchId 读写、零 589601 分支——「挂团订单保存勿再带 groupBatchId」「只传 batchNo 400」等破坏点前端零命中,基本行为零改动。团期维度用餐属新增能力,前端无团期用餐页面,建页为新产品需求待拍板,非本次同步范围。;前端纠正(2026-09-24):09-23 误把团期维度建页判出范围,用户指出后立项——团期详情新增「用餐」Tab(行程后,show:lazy),复用 MealTab 新增 groupBatchId prop 二选一 scope;mealInfo API 4 函数改 scope 对象+normalizeMealScope 前端断言;破坏点维持零命中;spec MealTab 30+mealInfo 5+batch 357+detail 389 全绿,checkpoint 13 项过 2026-09-23 dev-v3

order-v3: 团期订单支持用餐,5 个用餐接口可只传团期ID

服务: hl-order-service-v3 PR: #8251 Issue: #8230 日期: 2026-09-23 影响范围: 管理后台用餐信息的查询、生成、保存、重置与套用模版(订单、团期两种维度)


⚠️ 关键变化

  • 🔁 二选一(破坏性):查询、生成、保存、重置、套用模版这 5 个接口,orderId 与 groupBatchId 必须且只能传一个。都传返回 400「订单ID和团期ID只能传一个」;都不传返回 400「订单ID和团期ID必须传一个」。查询接口的 batchNo 不算数,只传 batchNo 视为两个都没传,同样 400。
  • 🔁 订单行不再带团期:按订单生成、保存、重置、套用出来的行,行上 groupBatchId、batchNo 一律为空。以前挂团订单的行会顺带写团期ID / 团期编号,现在不写。
  • 🔁 保存不再用 orderId + groupBatchId 一起传:以前保存时可以同时传两者并校验订单是否属于该团期(589601),现在同时传直接 400,589601 不再出现。
  • 🆕 团期维度:只传 groupBatchId 时读写的是团期自己的用餐行,行上 groupBatchId 有值、orderId 为空;按团期查询只返回团期自己的行,不含团里子订单的行。
  • ℹ️ 3.1 用 orderId + batchNo 组合此后查不到数据:订单行上已不存团期编号,这个组合固定返回空列表。

二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 查询用餐信息列表(3.1) GET /v3/admin/order/meal-info/list 修改 orderId / groupBatchId 二选一;只传团期ID只返回团期自己的行,顶层汇总按团期填
2 生成用餐信息(3.2) POST /v3/admin/order/meal-info/generate 修改 新增 groupBatchId,二选一;团期按团期产品当前行程生成
3 保存用餐信息(整单,3.3) POST /v3/admin/order/meal-info/save 修改 orderId 不再必填,二选一;只传团期ID保存团期行
4 重置用餐信息(3.4) POST /v3/admin/order/meal-info/reset 修改 新增 groupBatchId,二选一;团期删掉自己的行后重新生成
5 套用用餐模版(4.3) POST /v3/admin/order/meal-template/apply 修改 新增 groupBatchId,二选一;同一个模版可套到团期

出参字段一个都没增减。模版查询、存为模版、删除模版不变(模版不分订单、团期)。没有新增错误码。


三、接口详情

1. 查询用餐信息列表 GET /v3/admin/order/meal-info/list

VO: OrderMealInfoListReqVO → OrderMealInfoListRespVO

使用场景

按订单或按团期取用餐行及顶层汇总。两种维度用同一个接口,由传 orderId 还是 groupBatchId 区分。

入参字段表

字段 位置 类型 必填 约束 说明
orderId Query String 二选一 正数 按订单查。与 groupBatchId 必须且只能传一个
groupBatchId Query String 二选一 正数 按团期查,只返回团期自己的行
batchNo Query String 否 — 不参与二选一;只传它按都没传处理(400);与 orderId 组合固定查不到数据
其余筛选 Query — 否 — mealType、mealDateStart/End、dayNumber、settleType、keyword、limit 不变

出参字段表

字段 类型 说明
orderId String 按订单查为订单ID;按团期查为 null
groupBatchId / batchNo String 按订单查:仍回显订单所属团期(不挂团为 null);按团期查:该团期
departDate / returnDate String 按订单查:订单出发/返回日期;按团期查:团期出团日期 depart_date / 结束日期 end_date
personCount Integer 按订单查:订单人数;按团期查:团期报名人数
orderEditable Boolean 按团期查恒为 true
generated Boolean 按团期查:该团期有没有自己的行
items[].orderId / items[].groupBatchId String 订单行:orderId 有值、groupBatchId 为 null;团期行:groupBatchId 有值、orderId 为 null
items[].batchNo String 新写入的行一律为 null

请求示例

GET /v3/admin/order/meal-info/list?groupBatchId=2101996448340238338

响应示例

{
  "code": 200,
  "success": true,
  "data": {
    "orderId": null,
    "groupBatchId": "2101996448340238338",
    "batchNo": "Q202611042099750379129368577",
    "departDate": "2026-11-04",
    "returnDate": "2026-11-08",
    "personCount": 4,
    "orderEditable": true,
    "generated": true,
    "totalAmount": 0.00,
    "items": [
      { "mealInfoId": "…", "orderId": null, "groupBatchId": "2101996448340238338", "batchNo": null,
        "mealType": "LUNCH", "mealDate": "2026-11-04", "dayNumber": 1, "amount": 0.00 }
    ]
  }
}

按订单查(订单挂在该团期下)时顶层 groupBatchId 仍是 "2101996448340238338",但 items[].groupBatchId 为 null。

空数据 / 降级响应

  • 团期还没有自己的行:items: []、generated: false,顶层汇总照常填。
  • 团期里子订单有用餐行、团期自己没有:按团期查仍是 items: []。
  • orderId + batchNo:items: []。

错误响应

{ "code": 400, "message": "订单ID和团期ID只能传一个", "success": false, "data": null }

都不传(含只传 batchNo):400「订单ID和团期ID必须传一个」。按团期查没有团期查看权限:589507。订单维度的错误码不变。

业务边界

  • 二选一在入参校验阶段判断,先于任何权限、存在性判断。
  • 按团期查只按团期ID取行,不含团里子订单的行;按订单查只返回该订单的行。
  • 顶层 groupBatchId 是订单汇总回显,不代表行上存了团期ID。

2. 生成用餐信息 POST /v3/admin/order/meal-info/generate

VO: OrderMealInfoGenerateReqVO → OrderMealInfoListRespVO

使用场景

订单或团期还没有用餐行时,按产品行程生成空行。团期传 groupBatchId。

入参字段表

字段 位置 类型 必填 约束 说明
orderId Body String 二选一 正数 按订单产品快照生成(不变)
groupBatchId Body String 二选一 正数 新增。按团期产品当前行程生成团期行

出参字段表

字段 类型 说明
全部字段 — 与查询接口同维度的返回一致(团期维度见接口 1)
items[].dayNumber Integer 团期:第 d 天用餐日期 = depart_date + d − 1,天数到 end_date

请求示例

{ "groupBatchId": "2101996448340238338" }

响应示例

{
  "code": 200,
  "success": true,
  "data": {
    "orderId": null, "groupBatchId": "2101996448340238338",
    "departDate": "2026-11-04", "returnDate": "2026-11-08", "personCount": 4, "generated": true,
    "items": [
      { "orderId": null, "groupBatchId": "2101996448340238338", "mealType": "LUNCH", "mealDate": "2026-11-04", "dayNumber": 1, "amount": 0.00 },
      { "orderId": null, "groupBatchId": "2101996448340238338", "mealType": "DINNER", "mealDate": "2026-11-04", "dayNumber": 1, "amount": 0.00 }
    ]
  }
}

空数据 / 降级响应

  • 团期已有自己的行:不再生成,直接返回现有行(幂等)。
  • 团期 depart_date 或 end_date 为空:不生成,code 200,message 带 589602 文案。
  • 行程里含(酒店)/ 自理的餐、行程没有的天不生成;团期产品取不到行程时生成 0 行。

错误响应

{ "code": 400, "message": "订单ID和团期ID必须传一个", "success": false, "data": null }

都传:400「订单ID和团期ID只能传一个」。团期:无团期管理权限 589507、团期不存在 589500、end_date 早于 depart_date 589612。

业务边界

  • 团期生成的每天每餐取团期产品当前行程,不是某张子订单下单时的快照。
  • 团期不按团期状态拦截。
  • 按订单生成的行 groupBatchId 为空。

3. 保存用餐信息(整单) POST /v3/admin/order/meal-info/save

VO: OrderMealInfoBatchSaveReqVO → OrderMealInfoListRespVO

使用场景

一次提交某张订单或某个团期保存后应有的全部行:带行ID覆盖、不带新增、原来有而这次没传的软删。团期只传 groupBatchId,不要同时传 orderId。

入参字段表

字段 位置 类型 必填 约束 说明
orderId Body String 二选一 正数 不再必填。按订单保存
groupBatchId Body String 二选一 正数 含义变化:以前是「订单所属团期一致校验」,现在只传它表示按团期保存
items[] Body Array 是 — 保存后应有的全部行,字段不变;空数组表示一行都不留

出参字段表

字段 类型 说明
全部字段 — 与查询接口同维度的返回一致
items[].dayNumber Integer 团期行 = 用餐日期 − depart_date + 1;depart_date 为空时为 null

请求示例

{
  "groupBatchId": "2101996448340238338",
  "items": [
    { "mealType": "LUNCH", "mealDate": "2026-11-05", "restaurantName": "…", "dishName": "…",
      "unitPrice": 45.00, "tableCount": 0, "personCount": 4, "freePersonCount": 0,
      "freeAmount": 0, "otherCost": 0, "amount": 180.00, "settleType": "sign", "settleTypeName": "签单" }
  ]
}

响应示例

{
  "code": 200,
  "success": true,
  "data": {
    "orderId": null, "groupBatchId": "2101996448340238338", "departDate": "2026-11-04",
    "totalAmount": 180.00,
    "items": [
      { "mealInfoId": "…", "orderId": null, "groupBatchId": "2101996448340238338", "batchNo": null,
        "mealType": "LUNCH", "mealDate": "2026-11-05", "dayNumber": 2, "amount": 180.00 }
    ]
  }
}

空数据 / 降级响应

  • 团期传 items: []:该团期自己的行全部软删,返回 items: [],不影响子订单的行。

错误响应

{ "code": 400, "message": "订单ID和团期ID只能传一个", "success": false, "data": null }

都不传:400「订单ID和团期ID必须传一个」。团期:无团期管理权限 589507、团期不存在 589500、带的行ID不是本团期自己的行 589611、行查不到或已删 589606、金额对不上 589613。589601 不再返回。

业务边界

  • 团期保存只动团期自己的行,软删范围也只在团期自己的行里。
  • 按订单保存新增的行 groupBatchId 为空。
  • 任一行校验失败整批不写。

4. 重置用餐信息 POST /v3/admin/order/meal-info/reset

VO: OrderMealInfoResetReqVO → OrderMealInfoListRespVO

使用场景

删掉某张订单或某个团期自己的全部行,再按生成规则重新生成空行。团期传 groupBatchId。

入参字段表

字段 位置 类型 必填 约束 说明
orderId Body String 二选一 正数 按订单重置(不变)
groupBatchId Body String 二选一 正数 新增。按团期重置

出参字段表

字段 类型 说明
全部字段 — 与接口 2 生成的返回一致

请求示例

{ "groupBatchId": "2101996448340238338" }

响应示例

{
  "code": 200,
  "success": true,
  "data": {
    "orderId": null, "groupBatchId": "2101996448340238338", "generated": true,
    "items": [
      { "mealInfoId": "…(新行ID)", "orderId": null, "groupBatchId": "2101996448340238338", "mealType": "LUNCH", "mealDate": "2026-11-04", "dayNumber": 1, "amount": 0.00 }
    ]
  }
}

空数据 / 降级响应

  • 团期 depart_date 或 end_date 为空:原有团期行照样删掉、不生成,code 200,message 带 589602 文案。

错误响应

{ "code": 589612, "message": "返回日期早于出发日期,无法生成用餐信息", "success": false, "data": null }

end_date 早于 depart_date 时原有行不删。二选一 400、589507、589500 同接口 2。

业务边界

  • 团期重置只删团期自己的行,子订单的行不动;删和生成一起成功或一起失败。
  • 重置后行ID全部换新。

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

VO: MealTemplateApplyReqVO → OrderMealInfoListRespVO

使用场景

把一个模版按出发日铺开,接在现有行后面返回(只读,不写库),确认后再用接口 3 保存。模版不分订单、团期,同一个模版两边都能套。套到团期传 groupBatchId。

入参字段表

字段 位置 类型 必填 约束 说明
orderId Body String 二选一 正数 不再必填。套到订单
groupBatchId Body String 二选一 正数 新增。套到团期
templateId Body String 是 — 模版ID(不变)

出参字段表

字段 类型 说明
items[] Array 前段是现有行(团期:团期自己的行),后段是模版行(mealInfoId 为 null)
items[].mealDate String 团期:模版第 d 日 = depart_date + d − 1
items[].personCount Integer 团期按人的模版行 = 团期报名人数;按桌为 0
items[].orderId / groupBatchId String 套到团期:模版行 groupBatchId 有值、orderId 为 null;套到订单:模版行 groupBatchId 为 null
其余字段 — 与 #8125 相同

请求示例

{ "groupBatchId": "2101996448340238338", "templateId": "2102035945748684802" }

响应示例

{
  "code": 200,
  "success": true,
  "data": {
    "orderId": null, "groupBatchId": "2101996448340238338", "departDate": "2026-11-04", "personCount": 4,
    "items": [
      { "mealInfoId": "…", "orderId": null, "groupBatchId": "2101996448340238338", "mealType": "LUNCH", "mealDate": "2026-11-05", "dayNumber": 2 },
      { "mealInfoId": null, "orderId": null, "groupBatchId": "2101996448340238338", "mealType": "DINNER", "mealDate": "2026-11-06", "dayNumber": 3, "personCount": 4, "priceUnit": "person" }
    ]
  }
}

空数据 / 降级响应

  • 团期 depart_date 为空:只返回团期现有行,code 200,message 带 589602 文案。
  • 模版没有行:只返回现有行。

错误响应

{ "code": 400, "message": "订单ID和团期ID只能传一个", "success": false, "data": null }

都不传:400「订单ID和团期ID必须传一个」。团期:无团期管理权限 589507、团期不存在 589500。

业务边界

  • 套用不写库;保存时把返回的 items 原样用接口 3 提交,套到团期的就只传 groupBatchId 提交。
  • 团期套用的现有行只取团期自己的行,不含子订单的行。

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

场景 payload
✅ 团期生成 / 重置 { "groupBatchId": "…" }
✅ 团期保存 { "groupBatchId": "…", "items": [...] }
✅ 团期套用 { "groupBatchId": "…", "templateId": "…" }
✅ 团期查询 ?groupBatchId=…
✅ 订单维度 只传 orderId,其余同改动前
❌ 两个都传 { "orderId": "…", "groupBatchId": "…" } → 400「订单ID和团期ID只能传一个」
❌ 两个都不传 {} / 只传 batchNo → 400「订单ID和团期ID必须传一个」
  • 挂团订单保存时不要再带 groupBatchId(以前可带作一致校验,现在会 400)。
  • 团期的出发 / 返回日期、第几天都以后端返回为准(取团期 depart_date / end_date)。

五、数据库行为

  • 只传 groupBatchId 写入的行:团期ID有值,订单ID、团期编号为空。
  • 只传 orderId 写入的行:订单ID有值,团期ID、团期编号为空。
  • 团期保存、重置的软删范围只在团期自己的行;子订单的行不受影响。
  • 套用模版不写库。存量数据无需迁移。

六、边界行为

  • 二选一 400 先于权限、存在性判断,库里零写入。
  • 团期写(生成 / 保存 / 重置 / 套用)要团期管理权限,查询要团期查看权限,不足 589507;团期不存在 589500;不按团期状态拦截。
  • 团期 depart_date / end_date 为空:生成、重置、套用返回 code 200,message 为「订单出发或返回日期为空,无法生成用餐信息」(沿用 589602 文案),查询照常。
  • orderId + batchNo 查询:固定空列表。

六.6、修改前后对比

字段级对比

字段 改动前 改动后
3.2 / 3.4 / 4.3 入参 groupBatchId 无 新增,与 orderId 二选一
3.3 / 4.3 入参 orderId 必填 与 groupBatchId 二选一
3.3 入参 groupBatchId 与订单所属团期一致校验(589601) 只传它表示按团期保存;与 orderId 同传 400
订单行 items[].groupBatchId / batchNo 挂团订单有值 null

行为级对比

行为 改动前 改动后
3.1 只传团期ID 连同团里子订单的行一起返回,汇总为 null 只返回团期自己的行,汇总按团期填
3.1 都不传 查没挂订单也没挂团期的行 400
3.1 orderId + batchNo 按订单 + 团期编号筛 空列表
3.3 都传 按订单保存 400

六.7、影响评估

  • 是否破坏向后兼容: 是。都传、都不传、只传 batchNo 由成功变为 400;订单行不再带团期ID
  • 前端是否必须同步上线: 是。挂团订单保存不能再带 groupBatchId;团期用餐走只传 groupBatchId
  • 前端 workaround 清理点: 挂团订单保存时附带 groupBatchId 的处理;依赖订单行 groupBatchId / batchNo 判断归属的处理

七、不影响范围

  • 仅影响: 上述 5 个用餐接口
  • 零影响: 模版查询、存为模版、删除模版;金额公式;订单维度的权限与错误码(589601 除外)

八、测试环境已验证

部署提交 b86e635c7(含合并提交 6ae15b3ed),Deploy Panel 任务 23cffa4a;经 Gateway(https://api.test.1814.love)用真实 TEST 身份(SUPER_ADMIN)由固定脚本实测 73 项全部通过。团期 2101996448340238338(团期编号 Q202611042099750379129368577,出团 2026-11-04、结束 2026-11-08、报名 4 人),子订单 2101996448319266818:

只传 groupBatchId 调 3.2 生成                 → 12 行,与团期产品当前行程逐天逐餐一致;第 1 天(自理/含营地/含特色餐)只有午、晚 ✓
生成的行                                       → groupBatchId=团期、orderId=null、batchNo=null;mealDate=2026-11-04+d−1 ✓
再调 3.2                                       → 行数、行ID不变(幂等)✓
改一行后调 3.4 重置                            → 原行全部软删,重新生成与首次逐行一致 ✓
同一个模版只传 groupBatchId / 只传 orderId 调 4.3 → 两边都能套;团期模版行第 d 日落 2026-11-04+d−1、按人行人数=4、orderId=null ✓
只传 groupBatchId 调 3.3 保存 2 行              → groupBatchId 有值、orderId=null;dayNumber:11-05→2、11-06→3 ✓
再保存改一行、少传一行                          → 改的变了(105.00),少传的软删 ✓
子订单按订单保存 1 行后 3.1 按订单查回           → 行上 groupBatchId=null;顶层仍回显所属团期 ✓
只传 groupBatchId 调 3.1                       → 查不到子订单那行,只有团期保存的行 ✓
3.1/3.2/3.3/3.4/4.3 都传                       → 400「订单ID和团期ID只能传一个」(5/5)✓
3.1/3.2/3.3/3.4/4.3 都不传、3.1 只传 batchNo    → 400「订单ID和团期ID必须传一个」(6/6),零写入 ✓
只传 groupBatchId 调 3.1                       → departDate=2026-11-04、returnDate=2026-11-08,与团期详情一致 ✓
团期不存在 / 带子订单行ID / 带不存在行ID / 金额不符 → 589500 / 589611 / 589606 / 589613,零写入 ✓

十、相关文档

关联 / 联系人

链接

联系人