# 【修改接口·管理后台】调整订单出行人 tab 支持订单级紧急联系人提交 (#4908)

> **PR**: #4909 | **服务**: hl-order-service-v3 | **更新时间**: 2026-07-11 18:00

## 1. 接口背景

调整订单弹窗的出行人 tab 已能读取订单级紧急联系人姓名和电话，但提交接口此前只能通过 `updates.travelers` 提交出行人增删改，无法在同一个 tab 内提交订单级紧急联系人。

本次在统一提交接口中新增 `updates.people` 结构，前端可以在出行人 tab 一次性提交订单级紧急联系人和出行人增删改。

## 2. 变更清单

| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 调整订单统一提交 | POST | `/v3/admin/order/{orderId}/adjustment/submit` | 修改接口 | 入参新增 `updates.people`，承载订单级紧急联系人与出行人增删改 |
| 2 | 调整记录变更项 | - | `items[].type` | 修改枚举 | 新增 `EMERGENCY_CONTACT`，用于表示订单级紧急联系人变更 |

## 3. 接口详情

### 3.1 调整订单统一提交

- **使用场景**: 管理后台调整订单弹窗点击提交时调用；本次主要服务出行人 tab。
- **认证**: 管理后台 JWT。
- **幂等性**: 非幂等；每次提交会按请求内容生成调整记录。
- **路径**: `POST /v3/admin/order/{orderId}/adjustment/submit`

## 4. 入参

### 4.1 路径参数

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `orderId` | Long/String | 是 | 订单 ID，雪花 ID 建议前端按字符串传递 |

### 4.2 请求体总结构

| 字段 | 类型 | 必填 | 说明 | 校验规则 |
|------|------|------|------|----------|
| `updates` | Object | 是 | 各子域改动容器 | 不能为 null，且至少包含一个有效子域 |
| `updates.people` | PeopleUpdate | 否 | 出行人 tab 新契约；推荐前端后续使用该字段提交出行人 tab | 本字段存在时会走 PEOPLE 编辑窗口校验 |
| `updates.travelers` | TravelerBatch | 否 | 旧版出行人增删改契约 | 保留兼容；当 `updates.people.travelers` 同时存在时，优先使用 `updates.people.travelers` |
| `updates.schedule` | Object | 否 | 改期子域 | 本次未变 |
| `updates.itinerary` | Object | 否 | 行程子域 | 本次未变 |
| `updates.hotelRequirement` | Object | 否 | 房需求子域 | 本次未变 |
| `updates.vehicleRequirement` | Object | 否 | 车需求子域 | 本次未变 |

### 4.3 PeopleUpdate 字段

| 字段 | 类型 | 必填 | 说明 | 校验规则 |
|------|------|------|------|----------|
| `emergencyContactName` | String | 否 | 订单级紧急联系人姓名；不传表示不修改姓名 | 传入时会 trim；trim 后不能为空；姓名格式不合法时返回姓名格式相关错误 |
| `emergencyContactPhone` | String | 否 | 订单级紧急联系人电话；不传表示不修改电话 | 传入时会 trim；trim 后不能为空；必须为 11 位数字 |
| `travelers` | TravelerBatch | 否 | 出行人增删改分组 | 与旧 `updates.travelers` 结构相同 |

说明：
- 只修改紧急联系人时，可以传 `travelers` 为空数组或不传 `travelers`。
- 只提交出行人增删改时，可以只传 `updates.people.travelers`。
- 同时传 `updates.people.travelers` 和旧 `updates.travelers` 时，本次以后服务端优先读取 `updates.people.travelers`。

### 4.4 TravelerBatch 字段

| 字段 | 类型 | 必填 | 说明 | 校验规则 |
|------|------|------|------|----------|
| `add` | Array<TravelerEdit> | 否 | 新增出行人列表 | 空数组表示本次不新增 |
| `update` | Array<TravelerEdit> | 否 | 更新出行人列表 | 每项必须带 `id` 才能定位已有出行人 |
| `remove` | Array<Long/String> | 否 | 删除出行人 ID 列表 | 空数组表示本次不删除 |

### 4.5 TravelerEdit 字段

| 字段 | 类型 | 必填 | 说明 | 校验规则 |
|------|------|------|------|----------|
| `id` | Long/String | 更新时必填 | 出行人记录 ID | 新增时可不传 |
| `name` | String | 否 | 出行人姓名 | 规则沿用既有出行人编辑逻辑 |
| `idType` | String | 否 | 证件类型 | 例如 `ID_CARD` |
| `idNo` | String | 否 | 证件号 | 规则沿用既有出行人编辑逻辑 |
| `phone` | String | 否 | 手机号 | 规则沿用既有出行人编辑逻辑 |
| `travelerType` | String | 否 | 出行人类型 | `ADULT` / `CHILD` 等既有取值 |
| `birthday` | String | 否 | 出生日期 | `yyyy-MM-dd` |
| `remark` | String | 否 | 备注 | 可为空 |

## 5. 出参

### 5.1 响应字段

| 字段 | 类型 | 说明 |
|------|------|------|
| `code` | Integer | 统一响应码，成功为 `200` |
| `message` | String | 响应消息 |
| `success` | Boolean | 统一响应派生字段；`code=200` 时为 `true` |
| `data.success` | Boolean | 调整订单提交是否成功 |

### 5.2 成功响应结构

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

## 6. 枚举 / 数据字典

### 6.1 调整记录变更项类型 `items[].type`

所属字段：`GET /v3/admin/order/{orderId}/adjustment-record` 响应里的 `items[].type`。

| 值 | 中文 | 说明 |
|----|------|------|
| `HEADCOUNT` | 出行人数变化 | 成人、儿童、幼童、婴儿数量变化 |
| `DEPART_DATE` | 出发日期调整 | 改期产生 |
| `TRIP_DAYS` | 行程天数变化 | 行程增减天产生 |
| `EDIT_NODE` | 编辑行程节点 | 行程节点价格或数量等变化 |
| `ADD_NODE` | 新增行程节点 | 行程新增节点产生 |
| `REMOVE_NODE` | 删除行程节点 | 行程删除节点产生 |
| `HOTEL_REQ` | 酒店需求调整 | 房需求调整产生 |
| `VEHICLE_REQ` | 车辆需求调整 | 车需求调整产生 |
| `TRAVELER_EDIT` | 出行人资料修改 | 已有出行人字段修改产生 |
| `EMERGENCY_CONTACT` | 订单级紧急联系人变更 | 本次新增；修改 `updates.people.emergencyContactName` 或 `updates.people.emergencyContactPhone` 后产生 |

### 6.2 证件类型 `TravelerEdit.idType`

| 值 | 中文 | 说明 |
|----|------|------|
| `ID_CARD` | 身份证 | 既有出行人证件类型 |

### 6.3 出行人类型 `TravelerEdit.travelerType`

| 值 | 中文 | 说明 |
|----|------|------|
| `ADULT` | 成人 | 既有出行人类型 |
| `CHILD` | 儿童 | 既有出行人类型 |

## 7. 错误码

| code | 含义 | 触发场景 |
|------|------|----------|
| `581109` | 紧急联系人姓名和电话必填 | 本次提交了 `emergencyContactName` 或 `emergencyContactPhone`，但对应字段 trim 后为空 |
| `581113` | 手机号格式非法（应为 11 位数字） | `updates.people.emergencyContactPhone` 不是 11 位数字 |
| `587002` | 订单已是终态，不可调整 | 订单已结算、已取消、已退款等终态时提交调整 |
| `587033` | 未检测到有效变更，无需提交 | `updates` 没有有效改动，或提交值与当前值一致 |
| `587034` | 已出行，出行人不可调整 | 订单流程已到出行中或之后，提交 `people` 或 `travelers` |

## 8. 示例

### 8.1 典型成功：只修改订单级紧急联系人

**请求**

```http
POST /v3/admin/order/2075415561948315650/adjustment/submit
Authorization: Bearer <token>
Content-Type: application/json
```

```json
{
  "updates": {
    "people": {
      "emergencyContactName": "张三",
      "emergencyContactPhone": "13800000000",
      "travelers": {
        "add": [],
        "update": [],
        "remove": []
      }
    }
  }
}
```

**响应**

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

### 8.2 典型成功：同时修改紧急联系人并新增出行人

**请求**

```http
POST /v3/admin/order/2075415561948315650/adjustment/submit
Authorization: Bearer <token>
Content-Type: application/json
```

```json
{
  "updates": {
    "people": {
      "emergencyContactName": "李四",
      "emergencyContactPhone": "13900000000",
      "travelers": {
        "add": [
          {
            "name": "王五",
            "idType": "ID_CARD",
            "idNo": "110101199001011234",
            "phone": "13600000000",
            "birthday": "1990-01-01",
            "remark": "新增同行人"
          }
        ],
        "update": [],
        "remove": []
      }
    }
  }
}
```

**响应**

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

### 8.3 边界：只使用新版 people.travelers，不修改紧急联系人

**请求**

```http
POST /v3/admin/order/2075415561948315650/adjustment/submit
Authorization: Bearer <token>
Content-Type: application/json
```

```json
{
  "updates": {
    "people": {
      "travelers": {
        "add": [],
        "update": [
          {
            "id": "70001001",
            "phone": "13700000000"
          }
        ],
        "remove": []
      }
    }
  }
}
```

**响应**

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

### 8.4 异常：紧急联系人电话格式非法

**请求**

```http
POST /v3/admin/order/2075415561948315650/adjustment/submit
Authorization: Bearer <token>
Content-Type: application/json
```

```json
{
  "updates": {
    "people": {
      "emergencyContactName": "张三",
      "emergencyContactPhone": "138"
    }
  }
}
```

**响应**

```json
{
  "code": 581113,
  "message": "手机号格式非法（应为 11 位数字）",
  "success": false,
  "data": null
}
```

## 9. 业务边界

- `updates.people.emergencyContactName` 和 `updates.people.emergencyContactPhone` 均为可选字段；不传表示不修改对应字段。
- 传入紧急联系人字段时，空字符串不表示清空，会被视为非法入参。
- 仅修改订单级紧急联系人时，不会产生人数差价，也不会触发配房或配车重新配置。
- `updates.people.travelers` 复用既有出行人增删改逻辑；新增、更新、删除出行人可能继续触发既有人数差价和后续调整逻辑。
- 订单流程已到出行中或之后时，`people` 和旧 `travelers` 均不可提交。

## 10. 修改前后对比

### 10.1 入参字段对比

| 字段 | 修改前 | 修改后 |
|------|--------|--------|
| `updates.people` | 不支持 | 新增，作为出行人 tab 推荐提交结构 |
| `updates.people.emergencyContactName` | 不支持 | 支持提交订单级紧急联系人姓名 |
| `updates.people.emergencyContactPhone` | 不支持 | 支持提交订单级紧急联系人电话 |
| `updates.people.travelers` | 不支持 | 支持提交出行人 `add/update/remove` |
| `updates.travelers` | 支持 | 继续兼容；当与 `updates.people.travelers` 同时存在时优先使用 `updates.people.travelers` |

### 10.2 调整记录对比

| 字段 | 修改前 | 修改后 |
|------|--------|--------|
| `items[].type` | 无法表达订单级紧急联系人变更 | 新增 `EMERGENCY_CONTACT` |
| `items[].label` | 无对应值 | 紧急联系人 |
| `items[].before` / `items[].after` | 无对应值 | 返回姓名和电话变更摘要，电话脱敏展示 |

## 11. 影响评估 / 回滚

### 11.1 影响评估

- **是否破坏向后兼容**: 否。旧 `updates.travelers` 仍可用。
- **前端是否必须同步上线**: 否。旧出行人增删改调用可继续工作；需要在出行人 tab 修改订单级紧急联系人时，前端改用 `updates.people`。
- **建议前端改造点**: 出行人 tab 提交时统一组装到 `updates.people`，把订单级紧急联系人放在 `emergencyContactName/emergencyContactPhone`，把出行人增删改放在 `travelers`。

### 11.2 回滚方案

- 如需回滚后端，前端可临时继续使用旧 `updates.travelers` 完成出行人增删改。
- 回滚后订单级紧急联系人不能再通过调整订单 submit 接口修改，需要前端隐藏或禁用出行人 tab 的紧急联系人提交入口。

## 12. 注意事项

- 新旧契约并存期间，不建议同一次请求同时提交 `updates.people.travelers` 和 `updates.travelers`，避免前端误以为两份都会合并执行。
- `updates.people.emergencyContactPhone` 必须传 11 位数字，不支持带空格、短横线或区号。
- 紧急联系人电话在调整记录中脱敏展示，不要用调整记录回填编辑表单；编辑表单仍应以 snapshot 返回的订单级紧急联系人字段为准。

## 13. 关联 / 联系人

### 13.1 链接

- **Issue**: [#4908](https://git.1814.love:8443/wx/HL/issues/4908)
- **PR**: [#4909](https://git.1814.love:8443/wx/HL/pulls/4909)
- **Merge commit**: [85969df64](https://git.1814.love:8443/wx/HL/commit/85969df64b7d534f5ff93fbe1c7c562f0d79c6e2)

### 13.2 联系人

- **后端负责人**: @yst
