diff --git a/changelogs-v2/2026-08/23_6210_调整订单弹窗客户自订勾选未回显重交丢失-前端缺陷-管理后台.md b/changelogs-v2/2026-08/23_6210_调整订单弹窗客户自订勾选未回显重交丢失-前端缺陷-管理后台.md index 70f2f595..cf349a0e 100644 --- a/changelogs-v2/2026-08/23_6210_调整订单弹窗客户自订勾选未回显重交丢失-前端缺陷-管理后台.md +++ b/changelogs-v2/2026-08/23_6210_调整订单弹窗客户自订勾选未回显重交丢失-前端缺陷-管理后台.md @@ -3,64 +3,148 @@ schema: "hl-changelog/v2" ticket: "6210" title: "调整订单弹窗「客户自订」勾选未回显,重交后自订标记被静默抹掉" consumer: "admin" -author: "kimi(wx)" change_type: "前端缺陷" -backend_status: "deployed" -gateway_status: "verified" +author: "kimi(wx)" +backend_status: "not_required" +gateway_status: "not_required" frontend_status: "verified" frontend_owner: "mmg" frontend_ref: "97baecb6" -target_release: "" +target_release: "hl-ui@97baecb6" verified_at: "2026-08-23" -status_note: "前端缺陷:调整订单弹窗酒店 tab 未绑定 days[].customerSelfBooked——快照已返回该字段但「客户自订」勾选框恒不勾,且自订晚被按普通晚渲染默认空段;重交时标记丢失(null 落库),该晚变回「待房务配房」,房务会重复配房。后端读/写/换版链路实证无 bug。修复:回显绑定 + 原样重交该字段。" +status_note: "前端缺陷:调整订单弹窗酒店 tab 未绑定 days[].customerSelfBooked——快照接口已返回该字段但「客户自订」勾选框恒不勾,且自订晚被按普通晚渲染默认空段;重交时标记丢失落库,该晚变回「待房务配房」,房务会重复配房。后端读/写/换版链路实证无 bug。前端已修复并验证(ref=97baecb6)。" updated_at: "2026-08-23" base: "dev-v3" -generated: "2026-08-23T15:45:00+08:00" --- -# 调整订单弹窗「客户自订」勾选未回显,重交后自订标记被静默抹掉(#6210) +# 【前端缺陷·管理后台】调整订单弹窗「客户自订」勾选未回显,重交后自订标记丢失(#6210) -> 前端缺陷,待前端修复。后端契约完整(快照已返回字段、upsert 原样落库),DB 实测 + 网关实证。 +> **PR**: 无(前端缺陷,后端零改动) | **服务**: hl-order-service-v3 | **作者**: wx | **更新时间**: 2026-08-23 -## 现象(TEST 实证,订单 HL20260823145314586 / 团号 26-7603) +> 前端已修复并验证(frontend_ref=97baecb6,verified 2026-08-23);本文保留缺陷定位与契约口径备查。 -「调整订单」弹窗 → 酒店安排 tab,每晚左侧「**客户自订**」勾选框(#5838 引入):**此前标过自订的晚,打开修改弹窗时框是空的**;更严重的是在该弹窗里做任何修改重交后,自订标记被静默抹掉。 +## ⚠️ 关键变化 -## 证据链(DB + 调整记录 + 网关实测,三证闭环) +调整订单弹窗酒店 tab 的快照接口**一直返回** `hotelRequirement.days[].customerSelfBooked` 字段(#5838 交付)。前端此前未消费该字段——勾选框不回显、重交不带回——导致顾问在弹窗里修改任何酒店需求内容后,已标记的「客户自订」晚被静默抹掉,变回「待房务配房」。 + +## 1. 背景与现象(TEST 实测订单 HL20260823145314586) 该订单 2026-08-27 出行、6 天 5 晚、酒店 6 间: -| 时间 | 事件 | days JSON 事实 | -|------|------|----------------| -| 14:57:23 | 顾问经弹窗提交需求 v1 | 第 1/3/4/5 晚 `customerSelfBooked: true`、`segments: []`;第 2 晚呼伦贝尔香格里拉大酒店 | -| 15:18:25 | 顾问经弹窗再次提交(v2,调整记录仅 HOTEL_REQ 一项,非改期/改人数触发) | **全部 5 晚 `customerSelfBooked: null`**;第 1/3/4/5 晚各自多出一个默认空段(roomCount=1 + 空候选)——自订晚被按普通晚渲染的形态 | +| 时间 | 操作 | 结果 | +|------|------|------| +| 14:57 | 顾问在调整订单弹窗提交住宿需求:第 1/3/4/5 晚勾「客户自订」,第 2 晚选呼伦贝尔香格里拉大酒店 | 保存正确,4 晚自订标记在案 | +| 15:18 | 顾问再次打开弹窗修改需求(删除第 2 晚一个空候选)后提交 | **4 晚自订标记全部丢失**;且这 4 晚被各自补了一条默认空需求段(每段 1 间 + 空候选),形态与「未勾选过自订的普通晚」一致 | -- `order_adjustment_record`:两次均为徐莱经弹窗提交的「酒店需求已调整」,无 SCHEDULE/PEOPLE 记录 → 排除后端内部换版丢值。 -- 网关实测(2026-08-23):`GET /v3/admin/order/{id}/adjustment/snapshot?scope=HOTEL_REQ` 返回 200,`hotelRequirement.days[]` **每项均含 `customerSelfBooked` 键**(当前值为 null 是因 v2 数据已丢,契约本身完整)。 -- 后端代码链路(origin/dev-v3):快照 `AdjustmentService.buildHotelReqFromDb` → `RequirementService.parseHotelDays` 显式读该键(L2927,带防丢注释);upsert 按请求原样落库;改期/改天数换版走同一 parseHotelDays 入口保留标记。**读/写/换版三条链路均无 bug。** +之后任何人再打开该订单的调整弹窗:「客户自订」勾选框均为空(数据已丢),这 4 晚对房务显示为「待配房」,**存在房务重复配房风险**。 -## 前端缺陷点(三处,同源) +## 2. 变更接口清单 -1. **回显未绑定**:打开弹窗拉快照后,未把 `hotelRequirement.days[].customerSelfBooked === true` 绑定到对应晚的「客户自订」勾选框。 -2. **自订晚被当普通晚渲染**:自订晚(segments 为空)被补了默认空段结构展示(v2 数据形态实证)。 -3. **重交丢字段**:提交调整时未带上 `days[].customerSelfBooked`(快照契约注释明确要求「无损回显 + 原样重交」),null 落库后该晚变回「待房务配房」。 +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---|------|------|------|----------|------| +| 1 | 调整订单快照 | GET | `/v3/admin/order/{orderId}/adjustment/snapshot?scope=HOTEL_REQ` | 无变更(契约澄清) | 回显源:`hotelRequirement.days[].customerSelfBooked` 必须绑定到勾选框 | +| 2 | 统一提交调整 | POST | `/v3/admin/order/{orderId}/adjustment/submit` | 无变更(契约澄清) | `updates.hotelRequirement.days[]` 必须原样带回 `customerSelfBooked` | +| 3 | 提交/修改/调整房型需求 | PUT | `/v3/admin/order/{orderId}/hotel-requirement` | 无变更(契约澄清) | 同上字段语义 | -## 涉及接口(后端契约均无需改动) +## 3. 接口详情 -| 接口 | 说明 | -|------|------| -| `GET /v3/admin/order/{id}/adjustment/snapshot?scope=HOTEL_REQ` | 回显源:`hotelRequirement.days[].customerSelfBooked`(Boolean,true=该晚客人自订) | -| `POST /v3/admin/order/{id}/adjustment/submit`(updates.hotelRequirement.days) | 重交时必须原样带回 `customerSelfBooked` | -| `PUT /v3/admin/order/{id}/hotel-requirement` | 同字段语义(三分支 upsert) | +### 3.1 调整订单快照(回显源) -字段语义(#5838):`customerSelfBooked=true` → 该晚客人自己订酒店、房务无需配房;不计入配房进度分母、不列「未配房」;自订晚 `segments` 可为空(可带备注如「客人自订汉庭,勿重复订」)。 +- **使用场景**:打开「调整订单」弹窗时加载当前生效的住宿需求,逐晚回显 +- **认证**:管理后台 JWT +- **入参**:`orderId`(路径参数,Long,必填);`scope=HOTEL_REQ`(query,只取酒店需求子域;空=全量) +- **出参**(`hotelRequirement` 节点,当前无需求时整个节点为 null): -## 修复要求(前端) +| 字段 | 类型 | 说明 | +|------|------|------| +| id | String | 需求行 ID | +| version | Integer | 版本号 | +| status | String | 需求状态(PENDING/PROCESSING/DONE 等) | +| days | Array | 逐晚需求,结构同提交入参 | +| days[].dayNumber | Integer | 晚次序号(1 起) | +| **days[].customerSelfBooked** | **Boolean/null** | **客户自订标记:true=该晚客人自己订酒店、房务无需配房;null/false=普通晚** | +| days[].segments | Array | 该晚需求段(自订晚通常为空数组) | +| specialTags | Array | 特殊诉求标签 | +| remark | String | 备注 | -1. 弹窗初始化:`days[i].customerSelfBooked === true` → 第 i 晚「客户自订」勾选框置勾,且该晚按自订态渲染(候选/段区域禁用或隐藏,与首次标记自订时的交互一致)。 -2. 提交组装:每晚原样带上 `customerSelfBooked`(勾选=true,未勾=false/null),**不得因用户没动过该晚而丢键**。 -3. 勾选自订的晚提交时 `segments` 传空数组(与 #5838 提交形态一致),不要补默认空段。 +**示例(典型成功,测试服实测)** -## 数据善后(TEST 订单 HL20260823145314586) +请求: +``` +GET /v3/admin/order/2091418470443810817/adjustment/snapshot?scope=HOTEL_REQ +Authorization: Bearer {admin-token} +(无请求体) +``` -v2 已丢第 1/3/4/5 晚自订标记,这 4 晚当前对房务显示为「待配房」。待前端修复部署后,由顾问重新打开调整弹窗把这 4 晚重新勾「客户自订」提交即可走正常业务路径恢复(v3);如需立即恢复可联系后端 SQL 补数(另起数据单,需 wx 确认)。 +响应(节选,days 每项都带 customerSelfBooked 键): +```json +{ + "code": 200, + "data": { + "hotelRequirement": { + "id": "2091424805864583169", + "version": 2, + "status": "PROCESSING", + "days": [ + { "dayNumber": 1, "customerSelfBooked": null, "segments": [ { "roomCount": 1, "candidates": [ { "hotelId": null, "hotelName": null } ] } ] }, + { "dayNumber": 2, "customerSelfBooked": null, "segments": [ { "roomCount": 2, "budget": "560.00", "candidates": [ { "hotelId": "2023714929877450753", "hotelName": "呼伦贝尔香格里拉大酒店" } ] } ] } + ] + } + }, + "success": true +} +``` + +### 3.2 统一提交调整 / 房型需求 upsert(重交) + +两个写口(§2 表 #2/#3)的 `days[]` 元素结构与快照出参一致,**契约要求「无损回显 + 原样重交」**:快照读到的 `customerSelfBooked` 必须在提交时带回,后端按请求原样保存。 + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| days[].dayNumber | Integer | ✅ | 晚次序号 | +| days[].customerSelfBooked | Boolean | 否 | true=客户自订;不传/null/false=普通晚(**不传即丢标记**) | +| days[].segments | Array | 条件必填 | 自订晚可为空数组;非自订晚为空 → 400(582098「第{0}晚缺少用房需求,请填写房间需求或标记为客户自订」) | + +## 4. 契约约束(✅/❌ payload 对照) + +| 场景 | payload(单晚) | 结果 | +|------|-----------------|------| +| ✅ 标记自订 | `{"dayNumber":1,"customerSelfBooked":true,"segments":[]}` | 保存自订标记,房务不配该晚 | +| ✅ 自订+备注 | `{"dayNumber":1,"customerSelfBooked":true,"segments":[],"remark":"客人自订汉庭,勿重复订"}` | 同上,备注透出给房务 | +| ✅ 普通晚 | `{"dayNumber":2,"customerSelfBooked":false,"segments":[...]}` 或省略该键 | 正常配房需求 | +| ❌ 回显后丢键重交 | 快照读到 `customerSelfBooked:true`,提交时省略该键 | **自订标记被抹为普通晚,房务开始对该晚配房**(本缺陷事故形态) | +| ❌ 自订晚被补默认空段 | 未勾自订的晚被前端自动塞 `{"roomCount":1,"candidates":[{}]}` | 该晚被当成「等房控统筹」的真实需求保存 | + +## 5. 前端修复要求(已落地,ref=97baecb6) + +1. **回显绑定**:弹窗初始化时 `days[i].customerSelfBooked === true` → 第 i 晚「客户自订」勾选框置勾,并按自订态渲染(候选/需求段区域禁用或隐藏,与首次勾选自订时的交互一致)。 +2. **原样重交**:提交组装时每晚带上 `customerSelfBooked`(勾选=true,未勾=false 或省略),**不得因用户没动过该晚而丢键**。 +3. **自订晚不补空段**:勾选自订的晚提交 `segments: []`,不要自动补默认空需求段;未勾自订且 segments 为空的晚按现有校验提示用户(后端 582098 兜底)。 + +## 6. 边界行为 + +- 快照中历史需求(#5838 上线前提交)无此标记 → `customerSelfBooked` 为 null,按未勾选处理,属正常。 +- 该晚已有房务配房记录时再标自订 → 400(582097「第{0}晚已配房,不能改为客户自订,请先删除该晚配房」)。 +- 后端对自订晚不计入配房进度分母、不列「未配房」提示,房务侧行程 Tab 显示「客户自订」。 + +## 7. 测试环境已验证 + +``` +GET /v3/admin/order/2091418470443810817/adjustment/snapshot?scope=HOTEL_REQ → 200 + days[] 每项含 customerSelfBooked 键 ✓ +``` + +验证订单:`HL20260823145314586`(出行 2026-08-27,6 天 5 晚)。 + +## 8. 数据善后(TEST 订单 HL20260823145314586) + +该订单第 1/3/4/5 晚自订标记已丢,当前对房务显示为「待配房」。前端修复已部署(ref=97baecb6):由顾问重新打开调整弹窗把这 4 晚重新勾「客户自订」提交即可恢复(走正常业务路径生成新版本);如需立即恢复可联系后端补数(需 wx 确认后另起数据单)。 + +## 关联 / 联系人 + +### 链接 + +- **Issue**: [#6210](https://git.1814.love:8443/wx/HL/issues/6210)(已关闭,含完整定位证据链) + +### 联系人 + +- **后端负责人**: @wx