# 大交通批次列表: 接口路径破坏性迁移 (transport-plans → transport-plan/list)

> **存放目录**: 二期(v3,`order-v3` 标签)→ `changelogs-v2/2026-05/`
>
> **服务**: hl-order-v3 (端口 8084)
> **PR**: #2544 (squash 后 commit `be3badaca`)
> **Issue**: #2521
> **日期**: 2026-05-18
> **影响范围**: 管理后台「行程安排 - 接送站」区块 - 大交通批次列表

---

## ⚠️ 关键变化(破坏性 - 前端必同步)

一行红字说清:
- **本次变了什么**: 大交通批次列表接口路径从 `/transport-plans` 改为 `/transport-plan/list`
- **前端以前以为的是什么**: `GET /v3/admin/order/{id}/transport-plans` (旧式复数资源风格)
- **实际现在是什么**: `GET /v3/admin/order/{id}/transport-plan/list` (统一 list/add/edit/delete 动词风格)

**配套破坏性**: §2.6 大交通批次模块 4 个接口路径风格 + 动词 + Method 全部统一迁移,见 #2522/#2523/#2524 changelog。前端需要 4 个接口一并改。

---

## 一、背景

V5.48 §2.6 大交通批次模块 4 个接口(list/add/edit/delete)统一为 `/transport-plan/{动词}` 子路径风格,与订单模块其他子资源(出行人 traveler/list、配房 hotel-requirement 等)保持一致:

| 风格 | 旧 (V5.47 之前) | 新 (V5.48) |
|------|-----------------|------------|
| 列表 | `GET /transport-plans` | `GET /transport-plan/list` |
| 新增 | `POST /transport-plans` | `POST /transport-plan/add` |
| 编辑 | `PUT /transport-plans/{planId}` | `POST /transport-plan/{planId}/edit` |
| 软删 | `DELETE /transport-plans/{planId}` | `POST /transport-plan/{planId}/delete` |

统一动词路径后,网关路由 / 权限 RBAC / 操作审计的资源前缀一致,便于配置和扫描。

---

## 二、变更接口清单

| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 大交通批次列表 | GET | `/v3/admin/order/{id}/transport-plan/list` | 路径迁移 | 旧路径 `/transport-plans` 已下线 |

---

## 三、接口详情

### 1. 大交通批次列表 `GET /v3/admin/order/{id}/transport-plan/list`

**VO**: `TransportPlanVO`

#### 入参

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

#### 出参 `Result<List<TransportPlanVO>>`

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | String | 批次 ID(雪花) |
| `orderId` | String | 订单 ID |
| `direction` | String | 方向 `ARRIVAL` / `DEPARTURE` |
| `transportType` | String | 类型 `FLIGHT` / `TRAIN` / `SELF_DRIVE` |
| `transportNo` | String | 航班号 / 车次号(SELF_DRIVE 时为 null) |
| `carrier` | String | 航司 / 铁路公司 |
| `departStation` | String | 出发站 |
| `arriveStation` | String | 到达站 |
| `departTime` | LocalDateTime | 出发时间(SELF_DRIVE 时为 null) |
| `arriveTime` | LocalDateTime | 到达时间(SELF_DRIVE 时为 null) |
| `selfDrivePeriod` | String | 仅 SELF_DRIVE: `MORNING` / `AFTERNOON` / `EVENING` |
| `selfDriveEta` | LocalDateTime | 仅 SELF_DRIVE: 预计抵达时间 |
| `travelers` | List<Map> | 桥接表关联出行人,元素 `{id, name}` |
| `remark` | String | 备注 |

#### 请求示例

```
GET /v3/admin/order/60123456789012/transport-plan/list
```

#### 响应示例

```json
{
  "code": 200,
  "data": [
    {
      "id": "80012345",
      "orderId": "60123456789012",
      "direction": "ARRIVAL",
      "transportType": "FLIGHT",
      "transportNo": "CA1234",
      "carrier": "中国国际航空",
      "departStation": "北京首都T3",
      "arriveStation": "长春龙嘉",
      "departTime": "2026-06-01T08:30:00",
      "arriveTime": "2026-06-01T10:15:00",
      "selfDrivePeriod": null,
      "selfDriveEta": null,
      "travelers": [
        {"id": "70123456789012", "name": "张三"},
        {"id": "70123456789013", "name": "王小明"}
      ],
      "remark": "需要接机举牌"
    },
    {
      "id": "80012346",
      "orderId": "60123456789012",
      "direction": "DEPARTURE",
      "transportType": "SELF_DRIVE",
      "transportNo": null,
      "carrier": null,
      "departStation": null,
      "arriveStation": null,
      "departTime": null,
      "arriveTime": null,
      "selfDrivePeriod": "AFTERNOON",
      "selfDriveEta": "2026-06-05T15:00:00",
      "travelers": [
        {"id": "70123456789012", "name": "张三"}
      ],
      "remark": null
    }
  ],
  "msg": "success"
}
```

#### 空数据响应

订单尚未登记任何大交通批次时:

```json
{ "code": 200, "data": [], "msg": "success" }
```

#### 错误响应

订单不存在:

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

---

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

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

| 场景 | 请求 |
|------|------|
| ✅ 新路径 | `GET /v3/admin/order/60123456789012/transport-plan/list` |
| ❌ 旧路径(已下线 404) | `GET /v3/admin/order/60123456789012/transport-plans` |

### 字段语义约束

- `direction` 取值固定两值: `ARRIVAL`(到达) / `DEPARTURE`(离开)
- `transportType` 三值: `FLIGHT` / `TRAIN` / `SELF_DRIVE`
- `SELF_DRIVE` 类型行: `transportNo` / `departTime` / `arriveTime` 必为 null;`selfDrivePeriod` 必有值
- `FLIGHT` / `TRAIN` 类型行: `transportNo` / `departTime` / `arriveTime` 必有值;`selfDrivePeriod` / `selfDriveEta` 必为 null
- `travelers` 数组永远非空(后端保证),元素至少 1 个

---

## 五、数据库行为

**只读查询**,无写动作。

| 查询步骤 | 表 | 说明 |
|----------|-----|------|
| 1 | `order_transport_plan` | `WHERE order_id = ? AND deleted = 0`,主表批次记录 |
| 2 | LEFT JOIN `order_transport_plan_traveler` | `WHERE deleted = 0`,桥接表关联出行人 ID |
| 3 | JOIN `order_traveler` | `WHERE deleted = 0`,出行人姓名补全 |
| 4 | 内存装配 | 同一 plan 多 traveler 聚合为 `travelers: [{id, name}]` 数组 |

排序: `ORDER BY direction ASC, depart_time ASC, id ASC` (ARRIVAL 先于 DEPARTURE,同方向按时间升序)。

---

## 六、边界行为

- 未登录 → 401(网关拦截)
- 订单不存在 → `581100`
- 订单存在但无任何批次 → 200 + `data: []`(不报错)
- 批次存在但桥接表全软删 → `travelers: []`(理论上不应出现,后端保证)
- 老数据(v2 历史 plan 无 `mode` 字段)→ 字段为 null,不异常

---

## 七、不影响范围(显式声明,帮前端 / QA 缩小排查面)

- **仅影响**: 管理后台 F21 行程安排 Tab 「接送站」区块 - 大交通批次列表渲染
- **零影响**:
  - C 端订单详情 mp 接口(不查 plan 表,只查 arrival_plan)
  - 订单创建 / 支付 / 退款主流程
  - 出行人模块(travelers list 仍走 `/admin/order/{id}/traveler/list`)
  - Feign 内部接口 `GET /internal/order/orders/{orderId}/travelers`(回传 `transportPlanIds`,使用的是同表数据但聚合方向相反,不受路径变化影响)

---

## 八、测试环境已验证

测试服 9443 网关 + 真 admin token round-trip 验证:

```
GET https://web.test.1814.love:9443/v3/admin/order/{orderId}/transport-plan/list
  → 200 + data 数组 ✓
  → travelers 嵌套字段返回正确 (id+name) ✓
  → ARRIVAL/DEPARTURE 排序正确 ✓
  → 空订单返 data: [] ✓
```

(commit `15e2c7eeb` 含 hotfix #2550 修复 conflict markers,4 接口一并 9443 真测过)

---

## 九、相关历史 PR

| PR | Issue | 说明 | 是否仍有效 |
|----|-------|------|------------|
| **本 PR #2544** | **#2521** | 路径破坏性迁移 `/transport-plans` → `/transport-plan/list` | ✅ 最新 |

---

## 十、相关文档

- 关联 Issue: [wx/HL#2521](https://git.1814.love:8443/wx/HL/issues/2521)
- 关联 PR: [wx/HL#2544](https://git.1814.love:8443/wx/HL/pulls/2544)
- API 文档: `docs/order-v3/api/API-SPEC-V5.48.html` §2.6.1
- 配套破坏性: 见 `18_#2522_transport-plan-add.md` / `18_#2523_transport-plan-edit.md` / `18_#2524_transport-plan-delete.md`
