文件
hl-api-changelog/changelogs-v2/2026-09/07_7210_团期需求确认打回改造-修改接口-管理后台.md
T
2026-09-08 10:23:44 +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 7210 团期管理员确认 / 打回改造(M1/M2) admin wx(GIT) 修改接口 deployed verified verified mmg 96ef0c07 2026-09-08 前端已交付并验证(commit 96ef0c07):团级 confirm-check/confirm/reject 三封装+新建「查看需求」RequirementTab(demand:confirm 权限挂载、进入与点确认前各调预检、ready!==true 置灰+missing 缺失清单、confirm 展示 dispatched/skipped 并刷新);按户打回破坏性必填(orderIds 必填非空逐元素 String 透传、reason NForm rules 必填+maxlength 500、resourceType 恒传 ALL);逐单打回/分房四端点封装+两卡按钮(demand:confirm 显隐)+新建 Reject/DispatchRequirementModal;rework 逐项(NIGHTS_MISMATCH/DAY_NUMBER_INVALID 分支+expectedNights/actualNights、housekeeper 驳回入口 present 即显+disabledReason 置灰直显、逐单打回后刷团级 requirementConfirmed 缓存、冻结期重提在位);修复顶层挂 store 致不挂 Pinia spec 失败回归(改回调内惰性获取);对抗 review PASS,checkpoint 全绿(Vitest 全量+生产构建)。 2026-09-08 dev-v3

团期模块:管理员确认 / 打回改造(M1/M2)

服务: hl-order-service-v3、hl-user-service(权限种子) Issue: #7210 PR: #7220、#7222、#7242(复审返工) 日期: 2026-09-07 影响范围: 管理后台团期详情「查看需求」Tab,逐单详情页面打回/分房入口

⚠️ 关键变化

三条核心改造:

  1. M1 整体确认需求:缺失校验 → 置标记 → 逐户 PENDING_REVIEW→PENDING + 房控同步 → afterCommit 通知房务。缺失时硬拒绝 589533,零写入;成功后返回已放行户与已有户两份清单。新增预检端点 confirm-check。

  2. M2 按户打回需求:逐户 CAS 打回定制师、清 claimer、同步房控、开待办、发站内信。破坏性变更:body 从可选改必填(orderIds 必填非空、reason 必填 ≤512、resourceType 新增可选)。

  3. 逐单打回放宽与权限统一:源状态由 {PENDING_REVIEW} 放宽为 {PENDING_REVIEW, PENDING};已分房守卫改报 589535(批量与逐单入口都先判已分房再判源状态:房务认领后需求为 PROCESSING,已分房户一律 589535「请先由房务调整配房后再打回」,不会落成 589534)。逐单 reject/dispatch 四入口新增权限守卫 group-batch:demand:confirm (589507)。

  4. 复审返工(PR #7242):① 权限判定改按网关注入的当前角色(token 的 X-Admin-Role)而不是库里 current_role_id——短信登录得到的临时定制师身份即使库角色是 ADMIN,也对 confirm / confirm-check / reject 与四个逐单入口一律 589507(前端可据此提示「请用持码角色登录」);撤权 / 授权最迟 10 分钟生效(角色权限码缓存)。② 逐单打回(房 / 车)改经团级编排:同时清团级 requirement_confirmed 并写团级时间线 BATCH_REQUIREMENT_REJECT(extra 含本户 orderId),与整体确认 / 按户打回共用团级锁;请求 / 响应 / 错误码不变,前端团期详情在逐单打回成功后需刷新团级「已确认」状态。


二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 需求缺失预检(新增) GET /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check 新增接口 整体确认前的缺失清单
2 整体确认需求 POST /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm 响应 VO 改造 返回 GroupBatchRequirementConfirmRespVO 替代 Void
3 按户打回需求(破坏性) POST /v3/admin/order/group-batch/{groupBatchId}/requirement/reject 请求体必填改造+响应 VO orderIds/reason 必填;响应返回 GroupBatchRequirementRejectRespVO
4 子订单打回房需求 POST /v3/admin/order/{id}/hotel-requirement/reject 权限新增+源状态放宽 接 group-batch:demand:confirm;对 PENDING 团单放开;已分房改报 589535
5 子订单打回车需求 POST /v3/admin/order/{id}/vehicle-requirement/reject 权限新增+源状态放宽 接 group-batch:demand:confirm;源状态放宽
6 子订单分房(房) POST /v3/admin/order/{id}/hotel-requirement/dispatch 权限新增 接 group-batch:demand:confirm
7 子订单分房(车) POST /v3/admin/order/{id}/vehicle-requirement/dispatch 权限新增 接 group-batch:demand:confirm

三、接口详情

1. 需求缺失预检 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check

VO: GroupBatchRequirementCheckRespVO

使用场景

团期管理员在「查看需求」Tab 进入与点「确认」前调用,根据 ready 置灰确认按钮、根据 missing 展示缺失户。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long(String) ✓ 团期主订单 ID order_group_batch.group_batch_id

出参字段表

字段 类型 说明
data.groupBatchId Long(String) 团期 ID
data.batchStatus String 团期当前状态
data.ready Boolean missing 为空且 batchStatus∈{RESOURCE_PREPARING,MATERIAL_PREPARING} 时 true
data.missing[] List 缺失户清单(按 orderId 升序)

请求示例

GET /v3/admin/order/group-batch/1867000000001/requirement/confirm-check

响应示例

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "groupBatchId": "1867000000001",
    "batchStatus": "RESOURCE_PREPARING",
    "ready": false,
    "missing": [
      {
        "orderId": "60123456789001",
        "orderNo": "HL2609010001",
        "consultantId": "10001",
        "consultantName": "李四",
        "reason": "NOT_SUBMITTED"
      }
    ]
  }
}

空数据 / 降级响应

所有户齐备时 ready=true,missing=[]。

错误响应

{
  "code": 589507,
  "message": "无操作权限",
  "success": false,
  "data": null
}

业务边界条目

  • 缺失判定:NOT_SUBMITTED(needs_hotel=1 无 active 房需求行);ROOM_CATEGORY_MISSING(非自订晚某段首方案缺房型或房数<1);INVALID_REQUIREMENT(days 为空 / 缺住宿日期 / 非自订晚 segments 或 rooms 为空 / JSON 损坏)
  • 权限:需 group-batch:demand:confirm
  • 零副作用:纯读接口

2. 整体确认需求 POST /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm

VO: GroupBatchRequirementConfirmRespVO

使用场景

团期管理员确认全团需求齐备,允许房务向酒店下单。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long(String) ✓ 团期主订单 ID -

出参字段表

字段 类型 说明
data.requirementConfirmed Boolean 固定 true
data.dispatchedOrderIds List<Long(String)> 本次放行的子订单 ID
data.skippedOrderIds List<Long(String)> 本次未动的子订单 ID

请求示例

POST /v3/admin/order/group-batch/1867000000001/requirement/confirm

响应示例

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "groupBatchId": "1867000000001",
    "requirementConfirmed": true,
    "dispatchedOrderIds": ["60123456789001"],
    "skippedOrderIds": ["60123456789002"]
  }
}

空数据 / 降级响应

dispatchedOrderIds 与 skippedOrderIds 中至少一个非空。

错误响应

{
  "code": 589533,
  "message": "仍有 2 户未提交需求",
  "success": false,
  "data": null
}

业务边界条目

  • 团期必须为 RESOURCE_PREPARING 或 MATERIAL_PREPARING,否则 589501
  • 任一户缺失→589533 零写入
  • 权限需 group-batch:demand:confirm

3. 按户打回需求 POST /v3/admin/order/group-batch/{groupBatchId}/requirement/reject

VO: RejectRequirementReqVO → GroupBatchRequirementRejectRespVO

使用场景

团期管理员多选户打回,逐户退回定制师。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long(String) ✓ 团期主订单 ID -
orderIds Body List ✓ @NotEmpty 破坏性变更:改前可选现必填
reason Body String ✓ @NotBlank @Size(max=512) 破坏性变更
resourceType Body String 否 默认 ALL 新增

出参字段表

字段 类型 说明
data.requirementConfirmed Boolean 固定 false
data.rejected[] List 被打回的需求条目

请求示例

POST /v3/admin/order/group-batch/1867000000001/requirement/reject

{
  "orderIds": [60123456789001],
  "reason": "房间需求与套餐不匹配",
  "resourceType": "ALL"
}

响应示例

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "groupBatchId": "1867000000001",
    "requirementConfirmed": false,
    "rejected": [
      {
        "orderId": "60123456789001",
        "resourceType": "HOTEL",
        "requirementId": "90011223344"
      }
    ]
  }
}

空数据 / 降级响应

rejected 列表大小等于成功打回的数量。

错误响应

{
  "code": 400,
  "message": "请至少选择一个要打回的子订单",
  "success": false,
  "data": null
}

业务边界条目

  • 全量前置校验,任一违规则整单零副作用
  • 权限需 group-batch:demand:confirm

4. 子订单打回房需求 POST /v3/admin/order/{id}/hotel-requirement/reject

VO: RejectReqVO → Void

使用场景

团期管理员逐单打回定制师的房需求。

入参字段表

字段 位置 类型 必填 约束 说明
id Path Long(String) ✓ 子订单 ID -
returnRemark Body String ✓ @NotBlank 打回原因

出参字段表

字段 类型 说明
data null 无返回内容

请求示例

POST /v3/admin/order/60123456789001/hotel-requirement/reject

{
  "returnRemark": "房型不符"
}

响应示例

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

空数据 / 降级响应

无。

错误响应

{
  "code": 589507,
  "message": "无操作权限",
  "success": false,
  "data": null
}

业务边界条目

  • 新增权限 group-batch:demand:confirm
  • 源状态放宽 {PENDING_REVIEW, PENDING}
  • 已分房改报 589535
  • 复审返工(PR #7242):打回成功同时清团级 requirement_confirmed=0 并写团级时间线 BATCH_REQUIREMENT_REJECT(extra.orderIds=[本户]),与 confirm / reject 共用团级锁——前端在逐单打回成功后须刷新团期「已确认」标记与时间线;普通单仍 582083;「非团单」判定收紧为「解析不到所属团期行」(有 productBatchId 但团期行已删的脏数据由可打回变为 582083,错误码不变);权限改按 token 当前角色判

5. 子订单打回车需求 POST /v3/admin/order/{id}/vehicle-requirement/reject

VO: RejectReqVO → Void

使用场景

团期管理员逐单打回定制师的用车需求。

入参字段表

字段 位置 类型 必填 约束 说明
id Path Long(String) ✓ 子订单 ID -
returnRemark Body String ✓ @NotBlank 打回原因

出参字段表

字段 类型 说明
data null 无返回内容

请求示例

POST /v3/admin/order/60123456789001/vehicle-requirement/reject

{
  "returnRemark": "车型调整"
}

响应示例

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

空数据 / 降级响应

无。

错误响应

{
  "code": 589507,
  "message": "无操作权限",
  "success": false,
  "data": null
}

业务边界条目

  • 新增权限 group-batch:demand:confirm
  • 源状态放宽 {PENDING_REVIEW, PENDING}
  • 复审返工(PR #7242):同房侧,打回成功清团级 requirement_confirmed=0 + 团级时间线 + 共锁;普通单仍 582083;权限改按 token 当前角色判

6. 子订单分房(房) POST /v3/admin/order/{id}/hotel-requirement/dispatch

VO: DispatchReqVO → Void

使用场景

房务将确认的房需求派给酒店。

入参字段表

字段 位置 类型 必填 约束 说明
id Path Long(String) ✓ 子订单 ID -
dispatchRemark Body String 否 - 分房备注

出参字段表

字段 类型 说明
data null 无返回内容

请求示例

POST /v3/admin/order/60123456789001/hotel-requirement/dispatch

{
  "dispatchRemark": "已向酒店下单"
}

响应示例

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

空数据 / 降级响应

无。

错误响应

{
  "code": 589507,
  "message": "无操作权限",
  "success": false,
  "data": null
}

业务边界条目

  • 新增权限 group-batch:demand:confirm
  • 其余行为不变

7. 子订单分房(车) POST /v3/admin/order/{id}/vehicle-requirement/dispatch

VO: DispatchReqVO → Void

使用场景

车务将确认的用车需求派给供应商。

入参字段表

字段 位置 类型 必填 约束 说明
id Path Long(String) ✓ 子订单 ID -
dispatchRemark Body String 否 - 分房备注

出参字段表

字段 类型 说明
data null 无返回内容

请求示例

POST /v3/admin/order/60123456789001/vehicle-requirement/dispatch

{
  "dispatchRemark": "已通知车队"
}

响应示例

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

空数据 / 降级响应

无。

错误响应

{
  "code": 589507,
  "message": "无操作权限",
  "success": false,
  "data": null
}

业务边界条目

  • 新增权限 group-batch:demand:confirm
  • 其余行为不变

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

正确 / 错误 payload 对照

场景 payload 预期
✅ 确认:所有户齐备 POST /confirm(无 body) 200,放行所有 PENDING_REVIEW 户
❌ 确认:某户缺需求 POST /confirm(无 body) 589533,零写入
✅ 打回:必填字段齐全 { "orderIds": […], "reason": "…" } 200,逐户打回
❌ 打回:缺 orderIds { "reason": "…" } 400
❌ 打回:orderIds 空数组 { "orderIds": [], "reason": "…" } 400

调用约束

  • 确认前必调 confirm-check 展示缺失清单、置灰按钮
  • 打回弹窗改传 orderIds 数组 + reason
  • 逐单入口四个均需 group-batch:demand:confirm,无权限返 589507

五、数据库行为

order-v3:

  • 需求表:CAS 打回行 status/is_active/return_remark/returned_at/returned_by
  • 订单表:同步 room_control_status 为 PENDING / REJECTED_TO_CONSULTANT
  • 团期表:requirement_confirmed → 1(M1)/ 0(M2)
  • 时间线表:写 REQUIREMENT_DISPATCHED / BATCH_REQUIREMENT_REJECT 两条

hl-user-service:

  • Flyway DML 种子 V20260906_006(INSERT 权限码 + ADMIN/SUPER_ADMIN 关联)

六、边界行为

  • 团期查不到 → 589500
  • M1 仅认 RESOURCE_PREPARING/MATERIAL_PREPARING;M2 不限但冻结期有例外
  • 并发互斥:同一团期 confirm/reject 最多一个进入;5s 内连点被 Idempotent 拒
  • 幂等:M1 重复调用第二次 dispatchedOrderIds 为空
  • 权限缓存:Redis TTL 24h,Flyway 后需清缓存或重登

六.5、枚举 / 数据字典

缺失原因

值 中文 触发
NOT_SUBMITTED 未提交房需求 needs_hotel=1 无 active 行
ROOM_CATEGORY_MISSING 房型或房数缺失 非自订晚某段首候选缺字段
INVALID_REQUIREMENT 需求数据不完整 days 为空 / 缺住宿日期 / 非自订晚 segments 或 rooms 为空 / JSON 损坏

六.6、修改前后对比

字段级对比

接口 字段 改前 改后
confirm 响应 类型 Result Result
reject 请求 orderIds 无 必填 @NotEmpty
reject 请求 reason 可选 必填 @NotBlank @Size(max=512)
reject 请求 resourceType 无 新增 HOTEL/VEHICLE/ALL 默认 ALL
reject 响应 类型 Result Result
hotel-requirement/reject 源状态 {PENDING_REVIEW} 放宽 {PENDING_REVIEW, PENDING}
hotel-requirement/reject 已分房错误码 582086 改为 589535

行为级对比

行为 改前 改后
整体确认 仅置标记,无缺失校验 缺失校验→置标记→逐户放行→通知房务
按户打回 置团级标记不改户状态 逐户 CAS 打回、房控同步、待办、站内信
逐单打回(房 / 车) 只改需求行,团级 requirement_confirmed 不动、无团级时间线、不共锁 复审返工:同时清团级标记 + 团级时间线(extra 含本户)+ 与 confirm / reject 共锁
团期权限判定(含既有六码) 按库 current_role_id(短信登录临时身份可借库角色权限) 复审返工:按 token 当前角色 X-Admin-Role;SUPER_ADMIN 恒放行;角色权限码缓存 10 分钟

六.7、影响评估

  • 破坏向后兼容:是 —— reject 必填参数改变;旧客户端传空 body 改为 400
  • 前端是否必须同步上线:是 —— 破坏性变更,前后端需同一版本发布
  • 前端需清理的分支:打回弹窗改传 orderIds;确认前必调 confirm-check;reject 响应改为带 rejected[]

七、不影响范围

  • 订单创建/修改
  • 抢单池列表与房务认领流程本身(放行后的团单需求按既有规则以 PENDING 进池;本单只是不做抢单池 SSE 广播,团单整团汇总进池形态归 H 系列工单)
  • 权限体系(仅新增一个权限码)
  • 网关路由(/v3/admin/** 通配不变)
  • 数据库表结构(order-v3 无新表无列变更;hl-user-service 仅 DML)

八、测试环境已验证

  • 原验收(2026-09-07,团 A 2096412454643802114):AC-2/3/4/5/6/7/9/10/11/12/14/15/20/21/22 网关实测通过(含 50 户整体确认、confirm × reject 并发串行、冻结期闭环、589535 优先于 589534)。
  • 复审返工(PR #7242,order-v3 d482d08f9 / user-service d482d08f9):AC-24:admin(库角色 ADMIN 持码)短信登录得临时 CUSTOMIZER token,打 confirm-check / confirm / reject 与四个逐单入口共 7 次全部 589507,前后 DB 快照(团期标记 + 四户订单 + 房车需求 + 时间线计数)逐字节相同;密码重登后短信 token 立即失效(单会话顶号),ADMIN 200、SUPER_ADMIN 200、不持码 CUSTOMIZER 589507。AC-26:整团确认 requirement_confirmed=1 后逐单打回房需求 → 200、需求 PENDING→REJECTED_TO_CONSULTANT / is_active=0、requirement_confirmed=0、时间线新增 BATCH_REQUIREMENT_REJECT 且 extra.orderIds=["2096633951715033089"];恢复确认后逐单打回车需求同样生效(extra.orderIds=["2096633972502003714"])且房侧行未受影响;普通单房 / 车逐单打回均 582083、零写入、无残留时间线。6/6 检查通过,证据 verify_7210_rework_evidence.json。

九、复审返工(2026-09-07,PR #7242)

项 问题 修正 前端影响
P1 权限 守卫经 hasPermission(adminId) 按库角色判权,短信登录的临时定制师身份借库角色(ADMIN)通过团期管理员动作 新增内部端点 GET /internal/user/admin/role-has-permission,守卫改按 token 当前角色判;覆盖 confirm / confirm-check / reject 与四个逐单入口及既有六个团期权限码 无契约变化。临时定制师身份对这些入口一律 589507,可引导切回持码角色;撤权最迟 10 分钟生效
P2 逐单打回 hotel-requirement/reject、vehicle-requirement/reject 只改需求行,整团确认后逐单打回会留下「该户未提交、整团已确认」 逐单打回改经团级编排:清 requirement_confirmed + 团级时间线 BATCH_REQUIREMENT_REJECT + 共锁 无契约变化。逐单打回成功后刷新团期详情的「已确认」标记与时间线
P2 附带收紧 「非团单」旧判法只看 productBatchId 是否为空 改为「能否解析出所属团期行」 有 productBatchId 但团期行已删的脏数据由「可打回」变为 582083,错误码与文案不变

部署顺序强约束:hl-user-service 必须先于 hl-order-service-v3 上线。守卫改打新内部端点 role-has-permission,user-service 未部署时 Feign 404 降级 false,会让全部团期权限码(含看板 / 芯片 / 导出 / 成团 / 财务)对所有人返 589507,超管也不例外。


十、相关文档

第二轮复审返工要点(2026-09-07)

本次对外前端变更汇总(已同步 #7149 文件):

项 变更 前端影响
① 打回原因长度 512 → 500(五个接口统一) 打回 / 分房备注输入框 maxlength="500";501+ 字返 400
② confirm-check reason 新增 NIGHTS_MISMATCH、DAY_NUMBER_INVALID 与对应字段 expectedNights、actualNights 若穷举 switch/case,补两个分支;直接透传后端 message
③ 房务置灰口径 改按订单整体判已分房;新增 disabledReason 字段「本单尚有挂在历史需求版本上的配房未清理」 按 disabledReason 文案直接显示,无需按码分支
④ 需求改版 房务已配房自动跟随迁移到新版本 打回→重提后房务看板数据仍存在;逐单详情需刷新
⑤ 冻结期重提 被打回户在冻结期可重提(REJECTED_TO_ADMIN→PENDING_REVIEW);后期阶段允许整团确认 被打回户重提入口恢复;整团确认入口全阶段显示;缓存 requirementConfirmed 需刷新
  • 工单正文:#7210 接口变更节、口径与定案节、验收标准 AC-1~AC-22
  • 接口文档:docs/group/团期模块接口文档-v2.0.html §0C.2、GB-ADM-012/013、§3.1
  • 实现方案:docs/group/团期房务实现方案-v1.0.html §3.5

关联 / 联系人

链接

  • Issue: #7210
  • PR: #7220、#7222、#7242(复审返工)
  • Merge commit: 2e5812fdf(#7220)、5ab5a6cbe(#7222)、8d3b75671(#7242)

联系人

  • 后端负责人: wx
  • 前端负责人(hl-ui): mmg