# mp-service: 订单/行程 5 个聚合接口调用时机梳理

> **服务**: hl-mp-service（端口 8085）→ 透传 hl-order-service-v2（端口 8094）
> **PR**: -（纯契约梳理，无代码变更）
> **Issue**: -
> **日期**: 2026-04-23
> **影响范围**: C 端「订单详情页」+「行程 Tab」的 5 个聚合接口

---

## ⚠️ 关键变化

**无接口变更**。本 changelog 是对现有 5 个聚合接口的调用时机/契约关系做一次性梳理，方便前端对照接入。调用顺序、入参、返回 VO 均未调整。

---

## 一、接口清单

| # | 接口 | 方法 | 路径 | 返回 VO | 缓存 TTL |
|---|------|------|------|---------|----------|
| 1 | 订单详情页聚合 | GET | `/mp/order/{orderId}/dashboard` | `MpOrderDashboardVO` | 30s |
| 2 | 行程 Tab 路由决策 | GET | `/mp/trip/tab-state` | `MpTripTabStateVO` | 15s |
| 3 | 行程前·出发准备页聚合 | GET | `/mp/trip/{orderId}/pre-trip-dashboard` | `MpPreTripDashboardVO` | 30s |
| 4 | 行程中·今日页聚合 | GET | `/mp/trip/today-dashboard` | `MpTodayDashboardVO` | 15s |
| 5 | 旅行回忆列表 | GET | `/mp/order/travel-memory` | `PageResult<MpTravelMemoryVO>` | 60s |

所有接口均需登录，`userId` 由 mp-service 从 token 取出后透传给 order-v2。

---

## 二、两条独立入口

### 入口 A：订单详情页（#1）

来源：我的订单列表点击、支付成功跳转、消息/通知链接。拿到 `orderId` 后直接调 `#1`，与行程 Tab 无关。

### 入口 B：行程 Tab（#2 → #3/#4/#5）

用户切到行程 Tab 时**必须先调 `#2 /mp/trip/tab-state`**，后端根据当前订单情况返回 `state` + `orderId`，前端按 `state` 分支调对应接口。

| `state` | 含义 | 下一步接口 | 是否需要前端传 orderId |
|---------|------|-----------|------------------------|
| `NEW` | 从未下过单 | 无（空态） | - |
| `BEFORE_START` | 有订单未出发 | `#3 /mp/trip/{orderId}/pre-trip-dashboard` | ✅ 用 #2 返回的 orderId |
| `IN_PROGRESS` | 行程进行中 | `#4 /mp/trip/today-dashboard` | ❌ 后端从 userId 反查 |
| `RETURNING` | 已完成过行程 | `#5 /mp/order/travel-memory` | ❌ 分页拉列表 |

未支付订单（`PENDING_PAY`）不计入 `tab-state` 判定。

---

## 三、接口定位与返回核心字段

### 1. `GET /mp/order/{orderId}/dashboard` — 订单管理视角

**场景**：用户查看某张订单的履约与售后信息。

**返回**：`MpOrderDashboardVO`

| 字段 | 类型 | 说明 |
|------|------|------|
| `order` | `MpOrderDetailVO` | 订单主体，含 `serviceItems`（服务包含列表）|
| `preTripChecklist` | `MpPreTripChecklistVO` | 出发准备清单（顶部待办徽章用；服务降级时 null）|
| `files` | `FilesVO` | 合同摘要 + 发票摘要 + 保单 PDF 路径 |
| `insurance` | `MpInsuranceDetailVO` | 保险详情（未投保时 null）|
| `refund` | `RefundVO` | 退款详情+进度（仅 CANCELLED/REFUNDING/REFUNDED/REFUND_REJECTED/APPEALING 状态有值，其余 null）|

内部并行调 6 个 Feign：order（主，失败 500）+ contract + invoice + insurance + refund-detail + refund-progress。contract/invoice/insurance 失败降级 null。

> **服务包含列表**位置：`MpOrderDashboardVO.order.serviceItems`（`List<MpServiceItemVO>`）
> 每项字段：`type`（HOTEL/MEAL/VEHICLE/GUIDE/PHOTOGRAPHER/TICKET/INSURANCE）、`title`、`summary`、`hasDetail`（运行态，是否有子详情页可看）

---

### 2. `GET /mp/trip/tab-state` — 行程 Tab 路由决策

**场景**：用户切到行程 Tab 时的第一个调用。

**返回**：`MpTripTabStateVO`

| 字段 | 类型 | 说明 |
|------|------|------|
| `state` | String | `IN_PROGRESS` / `BEFORE_START` / `RETURNING` / `NEW` |
| `stateLabel` | String | 状态中文标签 |
| `orderId` | Long | IN_PROGRESS / BEFORE_START 时有值 |
| `summary` | `Summary` | 产品名/档位/出发日期/距出发天数 等 |

---

### 3. `GET /mp/trip/{orderId}/pre-trip-dashboard` — 行程前·出发准备

**场景**：`tab-state` 返回 `BEFORE_START` 时调用，订单已确认尚未出发。

**返回**：`MpPreTripDashboardVO`，包含订单头 / 出发准备清单 / 带队团队（领队+摄影师）/ 行程概览 / 客服电话。

内部并行调 3 个 Feign：trip + guide + photographer。guide/photographer 失败降级为 null，不影响主清单。

---

### 4. `GET /mp/trip/today-dashboard` — 行程中·今日页

**场景**：`tab-state` 返回 `IN_PROGRESS` 时调用，用户正在行程中。

**返回**：`MpTodayDashboardVO`

| 字段 | 类型 | 说明 |
|------|------|------|
| `today` | `MpTodayVO` | 今日行程主体（无行程中订单时 null）|
| `leader` | `MpGuideInfoVO` | 联系领队卡 |
| `sosContact` | `SosContactVO` | SOS：领队电话 + 客服电话 + 保险客服电话 |
| `weather` | `List<MpWeatherDayVO>` | 今日 + 未来 N 天天气（失败降级 null）|
| `todayProgressPercent` | Integer | 今日进度 0-100（已游览景点 / 总景点）|
| `dayNav` | `List<MpTripDayNavVO>` | DAY 导航，每天标记 DONE/CURRENT/PENDING |
| `todayTimeline` | `MpTodayTimelineVO` | 按当前时间切成 completed/current/next 三段 |
| `todayHotel` | `MpTripHotelArrangementVO` | 今晚住宿（含是否与昨晚换酒店标记）|
| `tomorrow` | `MpTomorrowPreviewVO` | 明日预告（路线摘要+出发时间）|

**入参仅 userId**（无 orderId），后端自己从 userId 反查进行中订单。无行程中订单时接口正常返回，核心字段全部 null/空列表。

内部并行调 guide + weather，两者失败都降级为 null。

---

### 5. `GET /mp/order/travel-memory` — 回头客态

**场景**：`tab-state` 返回 `RETURNING` 时调用。

**返回**：`PageResult<MpTravelMemoryVO>` — 已完成（COMPLETED）订单分页列表，按出发日倒序。含 `reviewed` / `rating` / `reviewId`（评价服务降级时评分字段为 null）。

---

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

### ✅ 行程 Tab 入口

| 场景 | 正确调用序列 |
|------|--------------|
| 用户切行程 Tab | **先 `#2`** → 按 state 分支调 `#3` / `#4` / `#5` 之一 |
| state=BEFORE_START | `#2` 返回的 `orderId` 传给 `#3` |
| state=IN_PROGRESS | `#4` 不传 orderId，token 中的 userId 足够 |
| state=RETURNING | 调 `#5` 拉分页 |
| state=NEW | 不再调任何接口 |

### ❌ 错误调用

- 切行程 Tab 直接调 `#3` / `#4`（跳过 `#2`）—— 不要自行根据订单状态/时间判断该渲染哪页
- 并行调 `#3` 和 `#4` —— 同一时刻用户只可能在其中一个状态
- `#3` 用自己缓存的 orderId —— 必须用 `#2` 本次返回的 orderId（订单可能已切换）

### ✅ 订单详情入口（#1）独立

从任何订单链接进入都直接调 `#1`，不依赖 `#2`，也不影响行程 Tab 的调用。

---

## 五、不影响范围

- `#1 /mp/order/{orderId}/dashboard` 与 `#3 /mp/trip/{orderId}/pre-trip-dashboard` 字段独立，**不要互相替代**
  - `#1` 关注：合同 / 发票 / 保单 / 保险 / 退款（订单管理视角）
  - `#3` 关注：准备清单 / 领队+摄影师 / 行程概览（出行准备视角）
- `#3 pre-trip-dashboard` 与 `#4 today-dashboard` 返回 VO 完全不同，**不要通用一套渲染**
- 登录态统一从网关 token 解析，所有接口无需前端额外传 `userId`

---

## 六、相关文档

- `MpOrderController.java`、`MpTripController.java`（hl-mp-service）
- VO：`MpOrderDashboardVO` / `MpTripTabStateVO` / `MpPreTripDashboardVO` / `MpTodayDashboardVO` / `MpTravelMemoryVO`
- 关联历史 changelog：
  - `2026-04-22_mp-order-detail-service-items-has-detail.md`（#1234 hasDetail 字段）
  - `2026-04-23_mp-pre-trip-checklist-split-arrival-departure.md`（#1289 清单拆 ARRIVAL/DEPARTURE）
