# 【删除接口·管理后台】订单详情大交通 Tab 删除冗余接口 `GET /v3/admin/order/{id}/transport-plans`

> **服务**: hl-order-service-v3 | **端**: 管理后台
> **接口**: `GET /v3/admin/order/{id}/transport-plans`（已彻底删除，调用将 404）
> **替代接口**: `GET /v3/admin/order/{id}/transport-plan/list`（保留，功能一致）
> **Issue**: [#3535](https://git.1814.love:8443/wx/HL/issues/3535) | **PR**: [#3536](https://git.1814.love:8443/wx/HL/pulls/3536)
> **日期**: 2026-06-05
> **影响**: ⚠️ **破坏性**——旧接口已删除，前端必须切换 URL，其余代码零改动。

---

## 一、接口背景

订单详情大交通 Tab 此前存在两个返回同一份数据的接口：

| 接口 | 所属域 | 说明 |
|------|--------|------|
| `GET /v3/admin/order/{id}/transport-plans` | core 域 | 底层 delegate 到 traveler 域，纯代理，无自身逻辑 |
| `GET /v3/admin/order/{id}/transport-plan/list` | traveler 域 | 数据权威来源，直接查询大交通批次表 |

2026-05-18 推送的 changelog（`18_#2521_transport-plan-list-path.md`）已将 `/transport-plan/list` 标记为正式接口；但 core 域的 `/transport-plans` 未同步下线，导致前端联调时两个路径并存、容易误用。

本次将 core 域冗余接口彻底删除，大交通数据源收敛到 traveler 域唯一路径。

---

## 二、变更清单

| # | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|----------|------|
| 1 | GET | `/v3/admin/order/{id}/transport-plans` | ❌ **删除接口** | 接口已彻底移除，调用返回 404 |
| 2 | GET | `/v3/admin/order/{id}/transport-plan/list` | ✅ **保留（替代接口）** | 功能 100% 一致，返回结构完全相同 |

> **前端改动量**：只改 URL 一行，入参、出参、枚举、错误码均无变化。

---
## 三、接口详情

### 替代接口：`GET /v3/admin/order/{id}/transport-plan/list`

| 项目 | 说明 |
|------|------|
| 认证 | 需要管理后台 JWT（Header: `Authorization: Bearer <token>`） |
| 幂等性 | 查询接口，天然幂等 |
| 限流 | 无特殊限流 |

---

## 四、接口入参

### 4.1 路径参数

| 参数 | 类型 | 必填 | 说明 |
|------|------|:----:|------|
| `id` | Long | ✅ | 订单 ID（雪花 ID，需字符串传输防 JS 精度丢失） |

### 4.2 请求体

无请求体（GET 接口）。

---

## 五、出参字段

**响应类型**：`Result<List<TransportPlanVO>>`

外层结构：

| 字段 | 类型 | 说明 |
|------|------|------|
| `code` | Integer | `200` 表示成功 |
| `data` | Array | 大交通批次列表；订单无批次时返回 `[]`，不会返回 `null` |
| `msg` | String | 状态消息 |

**TransportPlanVO 字段**：

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | String | 批次 ID（雪花 ID，字符串格式） |
| `orderId` | String | 订单 ID（雪花 ID，字符串格式） |
| `direction` | String | 方向，枚举值见六 |
| `transportType` | String | 交通类型，枚举值见六 |
| `transportNo` | String | 航班号 / 车次号；SELF_DRIVE 时为 null |
| `carrier` | String | 航司 / 铁路公司；SELF_DRIVE 时为 null |
| `departStation` | String | 出发站 |
| `arriveStation` | String | 到达站 |
| `departTime` | String | 出发时间（yyyy-MM-dd HH:mm:ss）；SELF_DRIVE 时为 null |
| `arriveTime` | String | 到达时间（yyyy-MM-dd HH:mm:ss）；SELF_DRIVE 时为 null |
| `selfDrivePeriod` | String | 仅 SELF_DRIVE 有值：时段枚举，见六；其他类型为 null |
| `selfDriveEta` | String | 仅 SELF_DRIVE 有值：预计抵达时间（yyyy-MM-dd HH:mm:ss）；其他类型为 null |
| `travelers` | Array | 关联出行人列表，元素见下方；永远非空，至少含一条 |
| `remark` | String | 备注；无备注时为 null |

**travelers 元素结构**：

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | String | 出行人 ID（雪花 ID，字符串格式） |
| `name` | String | 出行人姓名 |

**排序规则**：`direction ASC, departTime ASC, id ASC`（先按进/出方向，再按出发时间早晚，再按 ID 顺序）

---

## 六、枚举 / 数据字典

### direction（方向）

| 枚举值 | 含义 |
|--------|------|
| `ARRIVAL` | 抵达（进程） |
| `DEPARTURE` | 离开（离程） |

### transportType（交通类型）

| 枚举值 | 含义 | 备注 |
|--------|------|------|
| `FLIGHT` | 飞机 | transportNo/carrier/departTime/arriveTime 有值；selfDrivePeriod/selfDriveEta 为 null |
| `TRAIN` | 火车 | 同上 |
| `SELF_DRIVE` | 自驾 | transportNo/carrier/departTime/arriveTime 为 null；selfDrivePeriod/selfDriveEta 有值 |

### selfDrivePeriod（自驾时段，仅 SELF_DRIVE 有值）

| 枚举值 | 含义 |
|--------|------|
| `MORNING` | 上午 |
| `AFTERNOON` | 下午 |
| `EVENING` | 晚上 |

---

## 七、错误码

| 错误码 | 含义 | 触发场景 |
|--------|------|----------|
| `200` | 成功 | 正常返回（含空列表） |
| `401` | 未授权 | JWT 缺失或过期，网关拦截 |
| `581100` | 订单不存在 | Path id 对应订单不存在 |

> 订单存在但无大交通批次时，返回 `code: 200, data: []`，不返回 581100。

---

## 八、示例

### 8.1 典型成功（机票 + 火车组合）

```
GET /v3/admin/order/1234567890123456/transport-plan/list
Authorization: Bearer <token>
```

```json
{
  "code": 200,
  "data": [
    {
      "id": "9876543210000001",
      "orderId": "1234567890123456",
      "direction": "ARRIVAL",
      "transportType": "FLIGHT",
      "transportNo": "CA8888",
      "carrier": "中国国际航空",
      "departStation": "北京首都国际机场",
      "arriveStation": "丽江三义国际机场",
      "departTime": "2026-08-01 07:30:00",
      "arriveTime": "2026-08-01 10:45:00",
      "selfDrivePeriod": null,
      "selfDriveEta": null,
      "travelers": [
        {"id": "1111111111111111", "name": "张三"},
        {"id": "2222222222222222", "name": "李四"}
      ],
      "remark": null
    },
    {
      "id": "9876543210000002",
      "orderId": "1234567890123456",
      "direction": "DEPARTURE",
      "transportType": "TRAIN",
      "transportNo": "G1234",
      "carrier": "中国铁路",
      "departStation": "丽江站",
      "arriveStation": "北京南站",
      "departTime": "2026-08-08 14:00:00",
      "arriveTime": "2026-08-09 06:30:00",
      "selfDrivePeriod": null,
      "selfDriveEta": null,
      "travelers": [
        {"id": "1111111111111111", "name": "张三"},
        {"id": "2222222222222222", "name": "李四"}
      ],
      "remark": "卧铺车厢 9 车"
    }
  ],
  "msg": "success"
}
```

### 8.2 边界情况（自驾进程 + 订单无出程批次）

```
GET /v3/admin/order/1234567890123457/transport-plan/list
Authorization: Bearer <token>
```

```json
{
  "code": 200,
  "data": [
    {
      "id": "9876543210000010",
      "orderId": "1234567890123457",
      "direction": "ARRIVAL",
      "transportType": "SELF_DRIVE",
      "transportNo": null,
      "carrier": null,
      "departStation": "北京",
      "arriveStation": "丽江",
      "departTime": null,
      "arriveTime": null,
      "selfDrivePeriod": "AFTERNOON",
      "selfDriveEta": "2026-08-01 18:00:00",
      "travelers": [
        {"id": "3333333333333333", "name": "王五"}
      ],
      "remark": null
    }
  ],
  "msg": "success"
}
```

> 订单无出程批次时，仅返回进程数据，data 数组长度为 1，不报错。

### 8.3 业务失败（订单不存在）

```
GET /v3/admin/order/9999999999999999/transport-plan/list
Authorization: Bearer <token>
```

```json
{
  "code": 581100,
  "data": null,
  "msg": "订单不存在"
}
```

---

## 九、业务边界

**适用场景**：
- 管理后台订单详情「行程安排 - 接送站」Tab 加载大交通批次列表
- 前端展示进程/离程分组时，按 `direction` 过滤本接口数据即可，无需分两次请求

**不适用场景**：
- 小程序端（小程序有独立接口，不走 `/v3/admin/*`）
- 批量查询多订单的大交通（本接口仅支持单订单）

**特殊边界**：
- 订单存在但大交通批次为空时，返回 `data: []`（非 null），前端直接判断数组长度即可
- `travelers` 字段永远非空（批次创建时必须关联至少一名出行人），前端不需要判空
- SELF_DRIVE 类型时，`transportNo`/`carrier`/`departTime`/`arriveTime` 必为 null，前端渲染需按 `transportType` 分支处理

---

## 十、修改前后对比（接口级）

### 接口路径对比

| 维度 | 旧（已删除） | 新（保留） |
|------|-------------|-----------|
| 路径 | `GET /v3/admin/order/{id}/transport-plans` | `GET /v3/admin/order/{id}/transport-plan/list` |
| 响应结构 | `Result<List<TransportPlanVO>>` | `Result<List<TransportPlanVO>>` |
| 出参字段 | 与新接口完全一致 | 与旧接口完全一致 |
| 入参 | Path `id`（Long） | Path `id`（Long） |
| 存活状态 | ❌ 已删除（调用 404） | ✅ 正常可用 |

> 路径差异：复数 `transport-plans` vs 单数 `transport-plan/list`，返回内容 100% 相同。

### 行为对比

| 行为 | 旧接口 | 新接口 |
|------|--------|--------|
| 实际数据来源 | delegate 到 /transport-plan/list | 直接查询大交通批次表 |
| 响应内容 | 与新接口一致 | 权威数据源 |
| 可用性 | ❌ 已删除 | ✅ 正常 |

---

## 十一、影响评估 / 回滚

**是否破坏向后兼容**：是。旧路径 `GET /v3/admin/order/{id}/transport-plans` 已不存在，调用返回 404。

**前端是否必须同步改动**：是。前端若仍调用旧路径将收到 404，功能完全不可用。改动量极小：仅需将 URL 字符串中 `transport-plans` 改为 `transport-plan/list`，入参/出参/错误码处理代码均无需变更。

**影响范围**：仅管理后台订单详情大交通 Tab 的列表查询调用点。

**回滚方案**：如需回滚，在后端恢复 core 域的 `/transport-plans` 接口即可，前端无需改动。回滚不影响数据（数据始终在 traveler 域，两接口只是入口不同）。

---

## 十二、注意事项

1. **URL 拼写区分**：`transport-plans`（复数，旧的，已删）vs `transport-plan/list`（单数+list，新的，保留）。容易看漏，建议全局搜索替换。
2. **历史 changelog 矛盾已修正**：2026-05-18 的 `18_#2521_transport-plan-list-path.md` 曾将 `/transport-plan/list` 标记为正式接口，但 `/transport-plans` 当时未实际下线导致两者并存。本次 PR #3536 已彻底删除旧路径，以本文档为准。
3. **不影响其他大交通接口**：新增（`/transport-plan/add`）、编辑（`/transport-plan/{planId}/edit`）、删除（`/transport-plan/{planId}/delete`）均不受影响，只有查询列表接口有此变更。

---

## 十三、关联 / 联系人

- **Issue**: [#3535](https://git.1814.love:8443/wx/HL/issues/3535)
- **PR**: [#3536](https://git.1814.love:8443/wx/HL/pulls/3536)
- **历史关联 changelog**: `changelogs-v2/2026-05/18_#2521_transport-plan-list-path.md`（大交通列表路径迁移，本次与其收尾呼应）
- **后端负责人**: yst
