# 订单出行人证件验证: admin 端补接口 + 前端必须改 URL/method/参数

> **服务**: hl-order-service-v2 (端口 8084)
> **PR**: #1798 (已合并 dev, 待部署 prod)
> **Issue**: #1797
> **日期**: 2026-05-07
> **影响范围**: 管理后台 出行人证件验证弹窗（蒋雨莲所在订单页）
> **@ 前端**: mmg

---

## ⚠️ 关键变化（必须改前端）

prod 弹窗 "证件验证未通过 · 蒋雨莲：接口不存在: POST /admin/auth/cert/validate" 是因为 **`POST /admin/auth/cert/validate` 后端从未实现过**（五重证据：代码 0 命中 / git 全历史 0 命中 / changelog 0 命中 / 需求文档 0 命中 / AuthController 全部 13 个 mapping 无 cert）。

后端**新增**正确接口：

```
GET /admin/order/{orderId}/travelers/validate
```

前端必须把"逐个 traveler 调 cert/validate"的循环逻辑**整段删掉**，改为按 orderId 一次性校验：URL 变 / method 由 POST 改 GET / 参数由 traveler body 改 path orderId。

---

## 一、背景

弹窗触发动作（疑似锁单/支付/确认行程前置校验）应该一次性把订单内全部出行人验证一次，而不是循环逐人。后端早就有 `GET /internal/order/traveler/validate/{orderId}` 给 payment-service Feign 调，本次只是在 admin 端薄包装一层让前端可以直调。

---

## 二、变更接口清单

| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 校验订单出行人证件信息 | GET | `/admin/order/{orderId}/travelers/validate` | **新增** | 替换前端误调的 `POST /admin/auth/cert/validate` |

---

## 三、接口详情

### 1. 校验订单出行人证件信息 `GET /admin/order/{orderId}/travelers/validate`

**Service**: 复用已有 `OrderTravelerService.validateAndReturnVO(orderId)`（与 internal 接口完全对齐）
**VO**: `TravelerValidationVO`

#### 入参

| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| orderId | Path | Long | ✅ | 雪花 ID | 订单 ID |

#### 出参 `Result<TravelerValidationVO>`

| 字段 | 类型 | 说明 |
|------|------|------|
| valid | Boolean | 全部出行人证件信息是否合规 |
| travelerCount | Integer | 出行人数量 |
| errors | `List<String>` | 校验失败明细（中文消息），合规时为空数组 |

#### 请求示例

```
GET /admin/order/123456789/travelers/validate
Authorization: Bearer <admin_token>
```

#### 响应示例（合规）

```json
{
  "code": 200,
  "message": "成功",
  "data": {
    "valid": true,
    "travelerCount": 2,
    "errors": []
  },
  "success": true
}
```

#### 响应示例（不合规）

```json
{
  "code": 200,
  "message": "成功",
  "data": {
    "valid": false,
    "travelerCount": 2,
    "errors": [
      "蒋雨莲：身份证号格式错误",
      "张三：护照有效期已过"
    ]
  },
  "success": true
}
```

---

## 四、契约约束与正确调用方式

### ✅ 正确 / ❌ 错误 调用对照

| 场景 | 调用 |
|------|------|
| ✅ 一次性按订单校验全部出行人 | `GET /admin/order/{orderId}/travelers/validate` |
| ❌ 循环逐人调 cert/validate | `POST /admin/auth/cert/validate` × N（接口不存在 404） |

### 前端代码改动指引

**旧代码（删除）**：
```js
for (const t of travelers) {
  await http.post('/admin/auth/cert/validate', t)  // ❌ 接口不存在
}
```

**新代码**：
```js
const { data } = await http.get(`/admin/order/${orderId}/travelers/validate`)
if (!data.valid) {
  // 弹窗显示 data.errors 即可
  showCertValidationDialog(data.errors)
}
```

错误明细 `errors: List<String>` 已经包含中文姓名 + 错误原因，前端不需要再拼姓名前缀。

---

## 五、数据库行为

只读校验，**不写库**。

---

## 六、边界行为

- orderId 不存在 → 服务端 BusinessException → `Result.code != 200` + 中文 message
- 订单存在但 0 个出行人 → `valid=false, travelerCount=0, errors=["订单尚未添加出行人"]`
- 未登录 → 网关 401 拦截
- 下游服务降级 → 暂不需要 fallback，service 内部不依赖外部服务

---

## 七、不影响范围

- **仅影响**: 管理后台出行人证件验证弹窗（前端 hl-ui mmg 维护）
- **零影响**:
  - 小程序端出行人列表 / 添加 / 编辑
  - admin 端出行人增删改 (`/admin/order/{orderId}/travelers/**`)
  - payment-service 内部 Feign 调用的 `/internal/order/traveler/validate/{orderId}` 保持不变
  - 历史数据零变更

---

## 八、测试环境已验证

后端单测 3 用例全绿（mockMvc 真路径 dispatch）：
- `validate_orderComplete_returnsSuccessVO` ✓
- `validate_orderIncomplete_returnsIncompleteVO` ✓
- `validate_invalidOrderId_serviceThrows_exposedAsBusinessError` ✓

测试服 admin token round-trip：待 PR #1798 部署到测试服后 /@qa 角色验证（24h 内回贴 curl 输出）。

---

## 九、相关历史 PR

| PR | Issue | 说明 | 是否仍有效 |
|----|-------|------|------------|
| 无 | 无 | 后端从未约定 `POST /admin/auth/cert/validate` 接口 | -- |
| **本 PR #1798** | **#1797** | 新增 `GET /admin/order/{orderId}/travelers/validate` | ✅ 最新 |

---

## 十、相关文档

- 关联 Issue: [wx/HL#1797](https://git.1814.love:8443/wx/HL/issues/1797)
- 关联 PR: [wx/HL#1798](https://git.1814.love:8443/wx/HL/pulls/1798)
