From de167a0c1c76cabd9d024a8bf49e8030d3bf04f9 Mon Sep 17 00:00:00 2001 From: API Changelog Bot Date: Mon, 7 Sep 2026 01:45:02 +0800 Subject: [PATCH] =?UTF-8?q?changelog:=20#7210=20=E5=9B=A2=E6=9C=9F?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=91=98=E7=A1=AE=E8=AE=A4/=E6=89=93?= =?UTF-8?q?=E5=9B=9E=E6=94=B9=E9=80=A0=20M1/M2=E2=80=94=E2=80=94confirm-ch?= =?UTF-8?q?eck=20=E9=A2=84=E6=A3=80=E3=80=81589533/589534/589535=E3=80=81r?= =?UTF-8?q?eject=20body=20=E7=A0=B4=E5=9D=8F=E6=80=A7=E5=8F=98=E6=9B=B4?= =?UTF-8?q?=E3=80=81=E9=80=90=E5=8D=95=E5=85=A5=E5=8F=A3=E6=9D=83=E9=99=90?= =?UTF-8?q?=EF=BC=88=E4=BF=AE=E6=94=B9=E6=8E=A5=E5=8F=A3=C2=B7=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=90=8E=E5=8F=B0=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01XYL5S9SsBtkg7aGyFAbrrQ --- ..._团期需求确认打回改造-修改接口-管理后台.md | 656 ++++++++++++++++++ 1 file changed, 656 insertions(+) create mode 100644 changelogs-v2/2026-09/07_7210_团期需求确认打回改造-修改接口-管理后台.md diff --git a/changelogs-v2/2026-09/07_7210_团期需求确认打回改造-修改接口-管理后台.md b/changelogs-v2/2026-09/07_7210_团期需求确认打回改造-修改接口-管理后台.md new file mode 100644 index 00000000..13389528 --- /dev/null +++ b/changelogs-v2/2026-09/07_7210_团期需求确认打回改造-修改接口-管理后台.md @@ -0,0 +1,656 @@ +--- +schema: "hl-changelog/v2" +ticket: "7210" +title: "团期管理员确认 / 打回改造(M1/M2)" +consumer: "admin" +author: "wx(GIT)" +change_type: "修改接口" +backend_status: "deployed" +gateway_status: "verified" +frontend_status: "pending" +frontend_owner: "mmg" +frontend_ref: "" +target_release: "" +verified_at: "2026-09-07" +status_note: "后端已合 dev-v3(PR #7220、#7222)并部署测试服(order-v3 + user-service,HEAD 5ab5a6cbe),网关实测 AC-2/3/4/5/6/7/9/10/11/12/14/15/20/21 通过。破坏性变更:reject body 从可选改必填(orderIds/reason),前端与后端需同步上线。" +updated_at: "2026-09-07" +base: "dev-v3" +--- + +# 团期模块:管理员确认 / 打回改造(M1/M2) + +> **服务**: `hl-order-service-v3`、`hl-user-service`(权限种子) +> **Issue**: #7210 +> **PR**: 待合并后回填 +> **日期**: 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)。 + +--- + +## 二、变更接口清单 + +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---|---|---|---|---|---| +| 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 升序) | + +#### 请求示例 + +```json +GET /v3/admin/order/group-batch/1867000000001/requirement/confirm-check +``` + +#### 响应示例 + +```json +{ + "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=[]`。 + +#### 错误响应 + +```json +{ + "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 | 本次放行的子订单 ID | +| `data.skippedOrderIds` | List | 本次未动的子订单 ID | + +#### 请求示例 + +```json +POST /v3/admin/order/group-batch/1867000000001/requirement/confirm +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "groupBatchId": "1867000000001", + "requirementConfirmed": true, + "dispatchedOrderIds": ["60123456789001"], + "skippedOrderIds": ["60123456789002"] + } +} +``` + +#### 空数据 / 降级响应 + +dispatchedOrderIds 与 skippedOrderIds 中至少一个非空。 + +#### 错误响应 + +```json +{ + "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 | 被打回的需求条目 | + +#### 请求示例 + +```json +POST /v3/admin/order/group-batch/1867000000001/requirement/reject + +{ + "orderIds": [60123456789001], + "reason": "房间需求与套餐不匹配", + "resourceType": "ALL" +} +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "groupBatchId": "1867000000001", + "requirementConfirmed": false, + "rejected": [ + { + "orderId": "60123456789001", + "resourceType": "HOTEL", + "requirementId": "90011223344" + } + ] + } +} +``` + +#### 空数据 / 降级响应 + +rejected 列表大小等于成功打回的数量。 + +#### 错误响应 + +```json +{ + "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 | 无返回内容 | + +#### 请求示例 + +```json +POST /v3/admin/order/60123456789001/hotel-requirement/reject + +{ + "returnRemark": "房型不符" +} +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": null +} +``` + +#### 空数据 / 降级响应 + +无。 + +#### 错误响应 + +```json +{ + "code": 589507, + "message": "无操作权限", + "success": false, + "data": null +} +``` + +#### 业务边界条目 + +- 新增权限 group-batch:demand:confirm +- 源状态放宽 {PENDING_REVIEW, PENDING} +- 已分房改报 589535 + +--- + +### 5. 子订单打回车需求 `POST /v3/admin/order/{id}/vehicle-requirement/reject` + +**VO**: `RejectReqVO → Void` + +#### 使用场景 + +团期管理员逐单打回定制师的用车需求。 + +#### 入参字段表 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|---|---|---|---|---|---| +| `id` | Path | Long(String) | ✓ | 子订单 ID | - | +| `returnRemark` | Body | String | ✓ | @NotBlank | 打回原因 | + +#### 出参字段表 + +| 字段 | 类型 | 说明 | +|---|---|---| +| data | null | 无返回内容 | + +#### 请求示例 + +```json +POST /v3/admin/order/60123456789001/vehicle-requirement/reject + +{ + "returnRemark": "车型调整" +} +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": null +} +``` + +#### 空数据 / 降级响应 + +无。 + +#### 错误响应 + +```json +{ + "code": 589507, + "message": "无操作权限", + "success": false, + "data": null +} +``` + +#### 业务边界条目 + +- 新增权限 group-batch:demand:confirm +- 源状态放宽 {PENDING_REVIEW, PENDING} + +--- + +### 6. 子订单分房(房) `POST /v3/admin/order/{id}/hotel-requirement/dispatch` + +**VO**: `DispatchReqVO → Void` + +#### 使用场景 + +房务将确认的房需求派给酒店。 + +#### 入参字段表 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|---|---|---|---|---|---| +| `id` | Path | Long(String) | ✓ | 子订单 ID | - | +| `dispatchRemark` | Body | String | 否 | - | 分房备注 | + +#### 出参字段表 + +| 字段 | 类型 | 说明 | +|---|---|---| +| data | null | 无返回内容 | + +#### 请求示例 + +```json +POST /v3/admin/order/60123456789001/hotel-requirement/dispatch + +{ + "dispatchRemark": "已向酒店下单" +} +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": null +} +``` + +#### 空数据 / 降级响应 + +无。 + +#### 错误响应 + +```json +{ + "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 | 无返回内容 | + +#### 请求示例 + +```json +POST /v3/admin/order/60123456789001/vehicle-requirement/dispatch + +{ + "dispatchRemark": "已通知车队" +} +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": null +} +``` + +#### 空数据 / 降级响应 + +无。 + +#### 错误响应 + +```json +{ + "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 打回、房控同步、待办、站内信 | + +--- + +## 六.7、影响评估 + +- **破坏向后兼容**:**是** —— reject 必填参数改变;旧客户端传空 body 改为 400 +- **前端是否必须同步上线**:**是** —— 破坏性变更,前后端需同一版本发布 +- **前端需清理的分支**:打回弹窗改传 orderIds;确认前必调 confirm-check;reject 响应改为带 rejected[] + +--- + +## 七、不影响范围 + +- 订单创建/修改 +- 抢单池列表与房务认领流程本身(放行后的团单需求按既有规则以 PENDING 进池;本单只是不做抢单池 SSE 广播,团单整团汇总进池形态归 H 系列工单) +- 权限体系(仅新增一个权限码) +- 网关路由(/v3/admin/** 通配不变) +- 数据库表结构(order-v3 无新表无列变更;hl-user-service 仅 DML) + +--- + +## 八、测试环境已验证 + +待后端网关实测通过后补充。 + +--- + +## 十、相关文档 + +- 工单正文:#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](https://git.1814.love:8443/wx/HL/issues/7210) +- **PR**: 待合并后回填 +- **Merge commit**: 待合并后回填 + +### 联系人 + +- **后端负责人**: wx +- **前端负责人(hl-ui)**: mmg