# 订单调整弹窗：出行人 tab + 改期 tab（管理后台）

- 端类型：管理后台
- 变更类型：修改接口（出参/入参扩展 + **travelers 脱敏→明文，含破坏性**）
- 关联 Issue：#4458（+ follow-up #4477）　PR：#4468 / #4478
- 日期：2026-06-27

---

## ① 接口背景

订单调整弹窗的两个端点（`GET .../adjustment/snapshot` 预填 + `POST .../adjustment/submit` 统一提交）本期改造：
1. 原「出行人数」tab（仅改 adultCount/childCount 整数）→「出行人」tab：管理真实出行人名单（增/删/改），人数由名单按类型自动派生，加减人触发算价。
2. 新增「改期」tab：在"确认订单行程"之前允许修改出发日期；改期后订单退回「资源准备中」+ 配房配车重置。

两 tab 所有数据**一次 submit 一起提交**，零新端点、零 DDL。

---

## ② 变更清单

| 方法 | 路径 | 变更 |
|---|---|---|
| GET | `/v3/admin/order/{id}/adjustment/snapshot` | 出参新增 `schedule` 块；`travelers` 脱敏→明文；`editableTabLocksHint` 按状态门控 PEOPLE/SCHEDULE |
| POST | `/v3/admin/order/{id}/adjustment/submit` | 入参 `updates.travelers` 启用（原空转）+ 新增 `updates.schedule`；出参新增改期字段 |

统一响应 `Result<T>`：`{ code, message, data, success }`，code=200 成功。

**破坏性提示**：`snapshot.travelers` 由**脱敏**视图改为**明文**视图（姓名/证件/手机为真实值，供 admin 编辑表单回填）。前端如有按脱敏展示逻辑需自行脱敏。

---

## ③ 可改窗口（两 tab 不同，前端按 editableTabLocksHint 控制）

| tab | 可改窗口 | 起锁点 |
|---|---|---|
| 出行人（PEOPLE） | flowStatus ≤ 待出行（PENDING_DEPARTURE） | 出行中 TRAVELLING 起锁 |
| 改期（SCHEDULE） | flowStatus ≤ 待确认（PENDING_CONFIRM） | 待出行 PENDING_DEPARTURE 起锁 |

---

## ④ 入参

### snapshot
无变化（仅 path `id`）。

### submit —— `updates` 扩展
```jsonc
{
  "editReason": "客户加1人并改出发日",     // ≥5字，强制审计
  "tabLocks": ["PEOPLE","SCHEDULE"],       // 本次改了哪些 tab
  "confirmDiffHash": "...",                // 防并发(拿 snapshot 时记录回送)
  "updates": {
    "travelers": {                          // 出行人 tab（原定义但未生效，本期启用）
      "add":    [ { "name":"李四","travelerType":"ADULT","idCardType":"ID_CARD","idCardNo":"...","phone":"...","birthday":"1990-03-07" } ],
      "update": [ { "id":"92001","name":"张三","idCardNo":"..." } ],
      "remove": [ "92003" ]                 // 出行人 id
    },
    "schedule": { "departDate": "2026-07-15" }   // 改期 tab（新增），仅传新出发日
    // 仍兼容 basic / itinerary / hotelRequirement / vehicleRequirement / feeChanges
  }
}
```

**travelers 行字段**：name / travelerType（ADULT/CHILD/YOUNG_CHILD/BABY）/ idCardType / idCardNo / phone / birthday；update 项带 `id`。
**schedule**：`departDate`（`yyyy-MM-dd`，必填非空；returnDate 由后端按行程天数派生，不传）。

---

## ⑤ 出参

### snapshot —— 新增 `schedule` 块
| 字段 | 类型 | 说明 |
|---|---|---|
| schedule.departDate | String(date) | 当前出发日 |
| schedule.returnDate | String(date) | 当前返回日（派生） |
| schedule.tripDays | Integer | 行程天数 |
| schedule.canEditDate | Boolean | 能否改期（flowStatus ≤ 待确认 = true） |
| schedule.lockReason | String | 不能改期时的原因（可改时 null） |

其余：`travelers`（现为明文：name/idCardNo/phone 真实值）、`basic`（含 adult/child/youngChild/baby 人数回显，编辑入口已移至出行人 tab）、`editableTabLocksHint`（含 PEOPLE/SCHEDULE 取决于状态）不变结构。

### submit —— 新增字段
| 字段 | 类型 | 说明 |
|---|---|---|
| changedDims | Array | 本次变更维度，新增 `DEPART_DATE`（改期）；出行人变人数为 `HEADCOUNT` |
| priceDelta | String(金额) | 价格差额（正=加费，负=优惠，0=无差额） |
| newDepartDate | String(date) | 改期后新出发日（改期时返回） |
| newReturnDate | String(date) | 改期后新返回日 |
| newFlowStatus | String | 改期后流程状态（恒 `RESOURCE_PREPARING`） |
| assignmentDeletedCount | Integer | 改期重置作废的配房配车 assignment 行数 |

---

## ⑥ 枚举 / 数据字典

- travelerType：ADULT 成人 / CHILD 儿童(6-12) / YOUNG_CHILD 幼童(2-5,占座不占床) / BABY 婴儿(0-1,不占座不占床)
- flowStatus（相关）：RESOURCE_PREPARING 资源准备中 / PENDING_CONFIRM 待确认 / PENDING_DEPARTURE 待出行 / TRAVELLING 出行中
- changedDims：HEADCOUNT 人数 / DEPART_DATE 出发日期 / TRIP_DAYS 行程天数 / ITINERARY / HOTEL / VEHICLE
- editableTabLocksHint 取值：BASIC / PEOPLE / SCHEDULE / ITINERARY / HOTEL_REQ / VEHICLE_REQ / FEE

---

## ⑦ 错误码

| code | 含义 | 触发 |
|---|---|---|
| 587034 | 已出行，出行人不可调整 | flowStatus ≥ 出行中 时改出行人 |
| 587035 | 行程已确认，出发日期不可修改 | flowStatus ≥ 待出行 时改期（请取消重下） |
| 587036 | 团期子订单出行人调整暂不支持 | 团期子订单走出行人增删致人数变化（本期拦截） |
| 587037 | 出发日期格式非法，请使用 yyyy-MM-dd 格式 | schedule.departDate 格式错 |
| 587038 | 出发日期不能早于今天 | 改期到过去日期 |
| 581041 | 所选出发日期不可售或未配置价格 | 改期到无价格日历的日期 |
| 587002 | 订单已是终态不可调整 | COMPLETED/CANCELLED |

---

## ⑧ 示例

### 改期（成功）
请求：`{ "editReason":"客户改出发日","tabLocks":["SCHEDULE"],"updates":{"schedule":{"departDate":"2026-06-27"}} }`
响应：`{ "code":200,"data":{ "changedDims":["DEPART_DATE","TRIP_DAYS"],"priceDelta":"0.00","newDepartDate":"2026-06-27","newReturnDate":"2026-06-29","newFlowStatus":"RESOURCE_PREPARING","assignmentDeletedCount":3 } }`

### 出行人新增（成功）
请求：`{ "editReason":"客户加1人","tabLocks":["PEOPLE"],"updates":{"travelers":{"add":[{"name":"李四","travelerType":"ADULT","idCardType":"ID_CARD","idCardNo":"...","phone":"138...","birthday":"1990-03-07"}]}} }`
响应：`{ "code":200,"data":{ "changedDims":["HEADCOUNT"],"priceDelta":"3105.00" } }`（人数派生回写 order_main，价差落加费）

### 异常
- 改期到过去日期：`{ "code":587038,"message":"出发日期不能早于今天" }`
- 出行中改出行人：`{ "code":587034,"message":"已出行，出行人不可调整" }`

---

## ⑨ 业务边界

- 出行人人数由名单按 travelerType 自动派生回写 order_main（4 档：成人/儿童/幼童/婴儿），不再手填。
- 算价：加减人 / 改期（价格日历差）由后端调产品侧 fetchQuote 权威重算差额，**前端不传金额**；差额落 order_surcharge（正）/ order_discount（负）。多 tab 同时提交时单次合并算价（终态 vs 原态），无交叉误差。
- 改期：改 departDate + returnDate 联动 + 全行程逐日 stayDate 位移 + 退回 RESOURCE_PREPARING + 配房配车作废重配；**不涉及合同保险**（合同保险在确认行程后才触发，改期发生在之前）。
- 出行人变更（已确认/已存在合同保险时）经 TravelerChangedEvent 自动作废重签。
- 团期子订单出行人增删致人数变化本期拦截（587036），团期容量联动后续专项。

---

## ⑩ 修改前后对比

| | 修改前 | 修改后 |
|---|---|---|
| 出行人数 tab | 仅改 adultCount/childCount 整数 | 管真实出行人名单，人数派生 |
| snapshot.travelers | 脱敏 | 明文（admin 编辑回填） |
| updates.travelers | 定义存在但 submit 空转不生效 | 启用（add/update/remove 落地） |
| 改期 | 禁止（出发日不可改） | 确认行程前可改，带级联 |
| submit 出参 | 无改期字段 | + newDepartDate/newReturnDate/newFlowStatus/assignmentDeletedCount + changedDims.DEPART_DATE |

---

## ⑪ 影响评估 / 回滚

- **破坏性**：snapshot.travelers 脱敏→明文，前端展示需自行脱敏。其余为新增（向后兼容）。
- 前端尚未对接本弹窗两 tab，按此一次对接即可。
- 回滚：后端 revert PR #4468 #4478。

---

## ⑫ 注意事项

- Long ID + 金额均字符串化返回（防 JS 精度）。
- 改期/出行人为写操作，前端需防重复点击 + loading。
- 提交成功后刷新走 snapshot 重新拉取（改期后 flowStatus 已变 RESOURCE_PREPARING）。
- 改期所选新出发日须为产品可售日期（有价格日历），否则 581041。

---

## ⑬ 关联 / 联系人

- Issue：https://git.1814.love:8443/wx/HL/issues/4458 ・ https://git.1814.love:8443/wx/HL/issues/4477
- PR：https://git.1814.love:8443/wx/HL/pulls/4468 ・ https://git.1814.love:8443/wx/HL/pulls/4478
- 后端负责人：腰苏图
- 已部署测试服并网关实调验证通过（snapshot/改期/出行人三能力均生效）。
