--- schema: "hl-changelog/v2" ticket: "frontend" title: "调整订单弹窗手机号/证件号脱敏值误回传:未修改字段被当改动提交,后端报『格式非法』" consumer: "admin" change_type: "前端缺陷" author: "wx(GIT)" backend_status: "not_required" gateway_status: "not_required" frontend_status: "implemented" frontend_owner: "mmg" frontend_ref: "d4d25a1c" target_release: "" verified_at: "2026-08-12" status_note: "后端零改动,契约已支持『不改不传』。调整订单弹窗里手机号/证件号是脱敏回显(如 185****2756、110101****1234)。若用户没改这两列,前端不应把脱敏值回传后端——后端按『值变化』判改动,脱敏串 ≠ 明文会被误判为『改了』,再走格式校验报『手机号格式非法(应为 11 位数字)/证件号格式非法』。契约:AdjustmentSubmitReqVO.updates.people.travelers.update[].phone/idNo 传 null(或整个字段省略)= 保留原值不动;只有用户输入了新的完整明文值才提交。快照 GET /v3/admin/order/{id}/adjustment/snapshot?scope=PEOPLE 与订单详情 customerInfo.travelers 均返回明文(admin 端专用),可编辑初始值应取明文,不要取脱敏串。前端 2026-08-12 已修复并交付:真根因比本条所述更准——①buildTravelerPayload 未填敏感字段回传 ''(''≠null 后端误判改动对空串跑格式校验);②订单级紧急电话 buildEmergencyPhonePayload 原回传 originalEmergencyPhone 明文/脱敏串,用户只改姓名也泄漏脱敏串。修复:TravelerInfoEditor 捕获提交形态基线 baselineTravelerPayload(脱敏字段已省略)+紧急电话「脱敏或与基线一致→null(不改不传)」,buildAdjustmentPeopleUpdate 加 baselineTravelers 对 update 项逐字段 diff「改才传、不改省略」、只剩 id 未改项剔除,toAdjustmentTraveler 防御剔除含「*」的 idCardNo/phone/emergencyPhone;不传基线保持原全量行为向后兼容。order-v2 29 文件 231 用例全绿,checkpoint 全过。" updated_at: "2026-08-12" base: "dev-v3" --- # 调整订单弹窗手机号/证件号脱敏值误回传(前端) > **页面**:订单 → 调整订单弹窗 → 出行人编辑 → 手机号 / 证件号两列 > **后端**:本条**零改动**。后端契约已支持「不改不传」,问题在前端把脱敏值当成了改动提交。 --- ## 一、现象 调整订单弹窗中,出行人的手机号、证件号以**脱敏**形式回显(如手机号 `185****2756`、证件号 `110101****1234`)。用户**没有修改**这两列就提交,后端报错: - `手机号格式非法(应为 11 位数字)` - 或 `证件号格式非法` ## 二、根因(前端) 后端判定「某字段是否被修改」的口径是:**值与库里明文比对,不同即视为改动**。脱敏串(`185****2756`)≠ 明文(`18500002756`),前端若把回显的脱敏值原样回传,后端会误判为「用户改了手机号」,进而对脱敏串跑格式校验 → 报格式非法。 ## 三、契约(后端已支持,无需改) `POST /v3/admin/order/{id}/adjustment/submit`,`updates.people.travelers.update[]` 单项(`TravelerEditVO`): | 字段 | 不改时 | 要改时 | |---|---|---| | `phone` | 传 `null` 或**整个字段省略** → 保留原值 | 传新的完整 11 位明文 | | `idNo` | 传 `null` 或**整个字段省略** → 保留原值 | 传新的完整明文证件号 | | 其余字段同理 | null/省略 = 保留 | 传新明文 | > 后端对每个字段按 `newVal != null && !newVal.equals(oldVal)` 判改动;`null`/省略即跳过该校验与更新。 ## 四、前端该做的 1. **未修改的字段不要回传**:手机号/证件号若用户没动,提交时该字段传 `null` 或直接从 `update` 项里省略,**绝不把脱敏回显值回传**。 2. **改动检测以「用户是否输入新值」为准**,不要以「脱敏串 vs 空」判断;只有用户输入了新的完整明文,才放进提交体。 3. **可编辑初始值取明文**:快照 `GET /v3/admin/order/{id}/adjustment/snapshot?scope=PEOPLE` 与订单详情 `customerInfo.travelers` 均返回**明文**(admin 端专用)。若弹窗需要可编辑回填,应取这两个接口的明文,而不是某处的脱敏串——当前弹窗显示脱敏值,说明前端用的不是这两个明文源,需排查取值来源。 ## 五、验收 - [ ] 调整订单时只改人数/日期、不动手机号和证件号,提交成功,不报「手机号/证件号格式非法」 - [ ] 显式把手机号改成新的完整 11 位,提交后生效 - [ ] 显式把证件号改成新的完整明文,提交后生效 - [ ] 脱敏回显仍在(不回显明文给用户看),但未改不回传