# 补全出行信息聚合接口（管理后台）

> 端类型：**管理后台**（v3）｜变更类型：**新增接口**｜服务：hl-order-service-v3
> Issue #3539 ｜ PR #3547 ｜日期：2026-06-06

## 接口地址

`PUT /v3/admin/order/{id}/traveler-info`

## 接口介绍

订单详情「补全出行信息」弹窗专用接口。一次提交完成：出行人**全量同步**（增/改/删）+ 订单紧急联系人 + 客户备注更新，单事务原子。

替代原先"前端编排 batch-edit + 多次 delete + PUT 订单"的多接口方案。弹窗打开时先调 `GET /v3/admin/order/{id}/traveler/list` 回填，编辑（含前端本地删除）后整体提交本接口。

## 本次修改点

新增接口。配套新错误码 581108。不影响现有 `traveler/batch-edit` `traveler/add` `traveler/{tid}/delete` `PUT /v3/admin/order/{id}` 及小程序端接口。

## 入参

路径参数：`id`（Long，订单 ID，必填）

请求体 `TravelerInfoSaveReqVO`：

| 字段 | 类型 | 必填 | 含义 |
|---|---|---|---|
| travelers | List\<TravelerItem\> | 是 | 出行人**全集**（≤30），见下表。提交即该订单完整出行人列表 |
| emergencyContactName | String | 否 | 紧急联系人姓名（null=保留原值） |
| emergencyContactPhone | String | 否 | 紧急联系人电话（null=保留原值） |
| customerRemark | String | 否 | 客户备注（null=保留原值） |

`TravelerItem`（travelers 数组元素）：

| 字段 | 类型 | 必填 | 含义 |
|---|---|---|---|
| id | String | 否 | 出行人 ID。**有值=更新该人，null=新增**；DB 中存在但本次未提交的 → **删除** |
| name | String | 条件 | 姓名（新增时 name/idType/idNo 至少 1 个非空；不可含数字等非法字符） |
| gender | String | 否 | 性别 1=男 / 2=女 / 0=未知 |
| birthday | LocalDate | 否 | 出生日期 yyyy-MM-dd |
| idType | String | 否 | 证件类型 ID_CARD / PASSPORT / BIRTH_CERT |
| idNo | String | 否 | 证件号（明文传，DB 加密；与 birthday 需一致） |
| nationality | String | 否 | 国籍（默认中国） |
| race | String | 否 | 民族（默认汉族） |
| phone | String | 否 | 出行人手机（明文传，DB 加密） |
| emergencyContact | String | 否 | 该出行人紧急联系人姓名 |
| emergencyPhone | String | 否 | 该出行人紧急联系人电话 |
| roomGroupNo | Integer | 否 | 同住分组号 |
| travelerType | String | 条件 | ADULT / CHILD / YOUNG_CHILD / BABY（**新增时必填**，更新时 null 保留原值） |

**入参示例**
```json
{
  "travelers": [
    {"id": "2062826419733336066", "name": "张大人", "gender": "1", "birthday": "1990-03-07",
     "idType": "ID_CARD", "idNo": "110101199003078531", "phone": "13800138001", "travelerType": "ADULT"},
    {"id": null, "name": "张小孩", "gender": "2", "birthday": "2018-05-12",
     "idType": "ID_CARD", "idNo": "110101201805129524", "phone": "13800138002", "travelerType": "CHILD"}
  ],
  "emergencyContactName": "紧急王",
  "emergencyContactPhone": "13900139000",
  "customerRemark": "客户希望安排素食"
}
```

## 出参

`Result<TravelerInfoSaveRespVO>`

| 字段 | 类型 | 含义 |
|---|---|---|
| createdCount | Integer | 本次新增出行人数 |
| updatedCount | Integer | 本次更新出行人数 |
| deletedCount | Integer | 本次删除出行人数 |
| completedCount | Integer | 当前资料完整(COMPLETED)的出行人数 |
| pendingCount | Integer | 当前资料待完善(PENDING)的出行人数 |
| allCompleted | Boolean | 是否全部补全（人数=声明数 且 全部 COMPLETED） |

**出参示例**
```json
{
  "code": 200, "message": "成功", "success": true,
  "data": {
    "createdCount": 1, "updatedCount": 1, "deletedCount": 0,
    "completedCount": 2, "pendingCount": 0, "allCompleted": false
  }
}
```

## 状态规则（调用约束）

接口行为随订单状态变化，前端需按返回错误码处理：

| 订单状态 | 新增 | 删除/更新 | 副作用 |
|---|---|---|---|
| 待支付 | ❌ 581116 | ✅ | 无 |
| 定制中（待补全/资源准备/待确认） | ✅ | ✅ | 无 |
| 待出行 / 出行中 | ✅ | ✅ | 后端**自动**作废旧合同重签 + 退旧保单重投（前端无需额外调用） |
| 已完成 / 已取消 | ❌ 581108 | ❌ 581108 | 整单拒绝编辑 |

- 通用：订单至少保留 1 位成人，删除最后 1 位成人返回 581107。
- 紧急联系人/备注：传 null 保留原值；传值则更新。
- 出行人全部补全后，订单流程自动从「待补全信息」推进到「资源准备」。

## 枚举

| 枚举 | 取值 | 含义 |
|---|---|---|
| travelerType | ADULT / CHILD / YOUNG_CHILD / BABY | 成人 / 儿童 / 小童 / 婴儿 |
| idType | ID_CARD / PASSPORT / BIRTH_CERT | 身份证 / 护照 / 出生证 |
| gender | 1 / 2 / 0 | 男 / 女 / 未知 |

## 错误码

| code | message | 触发 |
|---|---|---|
| 581102 | 订单不存在，无法编辑出行人 | 订单 ID 不存在 |
| 581108 | 当前订单状态不允许编辑出行信息（已完成 / 已取消） | 订单已完成/已取消 |
| 581116 | 当前订单状态禁止新增出行人 | 待支付订单提交了新增项 |
| 581107 | 出行人是订单最后 1 位成人，禁止删除 | 删除后无任何成人 |
| 581110 | 出行人 ID 不属于该订单 | 更新项 id 不属于该订单 |
| 581111 | 证件号被已签合同冻结 | 已签合同订单尝试改证件号 |
| 581118 | 新增出行人缺少必填字段（id=null 时 name/idType/idNo 必填，且 travelerType 必填） | 新增项缺必填 |
| 581119 | 出行人证件号重复 | 同次提交出现重复证件号 |
| 581104 | 同住分组号超出订单家庭数上限 | roomGroupNo 超过订单家庭数 |
| 581112 / 581113 / 581114 | 证件号 / 手机 / 生日格式错误 | 字段格式校验不通过 |
| 100702 | 姓名含非法字符 | 姓名含数字等非法字符 |
| 400 | 出行人列表不能为空 | travelers 为空数组 |
| 401 | 缺少有效的 Authorization 头 | 未携带 token |

> 幂等：同一订单 3 秒内重复提交会被拒绝（防重复点击/网络重试），前端避免短时间重复提交。

## 关联

- Issue：https://git.1814.love:8443/wx/HL/issues/3539
- PR：https://git.1814.love:8443/wx/HL/pulls/3547
- 后端负责人：腰苏图（订单 v3）
