# 打印行程单出参二次调整（去 printTime / 拆日期 / 补订单金额 / 餐食 meals 数组 / 节点服务标准）

**接口路径**：GET /v3/admin/order/{id}/print-itinerary
**服务**：hl-order-service-v3
**PR**：[#4692](https://git.1814.love:8443/wx/HL/pulls/4692) ｜ **Issue**：[#4691](https://git.1814.love:8443/wx/HL/issues/4691) ｜ **前序**：[#4683](https://git.1814.love:8443/wx/HL/pulls/4683)（第一轮增强）/ [#4650](https://git.1814.love:8443/wx/HL/pulls/4650)（首上线）｜ **合并至**：dev-v3
**变更类型**：修改接口（含破坏性变更）

---

## 1. 接口背景

打印行程单（出团行程单·Driver Copy）接口联调后按前端反馈做第二轮出参调整。**只改出参，入参不变，零 DDL，无新依赖。**

调整目标：
- 打印时间去后端化，改前端本地生成。
- 出团/返回日期拆开，让前端自行拼接展示。
- 补齐订单号 + 订单级金额（总额/应收总额/应收尾款）。
- 餐食含餐字段结构化（三个平铺布尔 → meals 数组，带中文标签）。
- 每个资源点位带上服务标准。

---

## 2. 变更清单

| 类型 | 字段路径 | 变更说明 |
|------|----------|----------|
| 删除字段 | `printTime` | 打印时间不再由后端返回，前端本地生成 |
| 删除字段 | `dateRange` | 出行日期范围字符串删除，拆为 departDate + returnDate |
| 新增字段 | `departDate` | 出团日期（LocalDate） |
| 新增字段 | `returnDate` | 返回日期（LocalDate） |
| 新增字段 | `orderNo` | 订单号 |
| 新增字段 | `orderAmount` | 订单总额（下单冻结原价） |
| 新增字段 | `payableTotal` | 订单应收总额 |
| 新增字段 | `outstandingBalance` | 应收尾款（待收） |
| 删除字段 | `days[].breakfast` / `lunch` / `dinner` | 原 Boolean 三字段删除 |
| 新增字段 | `days[].meals` | 数组，固定早/午/晚三项，each `{type,label,included}` |
| 新增字段 | `days[].nodes[].serviceStandard` | 资源服务标准（景点/活动/服务有值，餐厅无恒 null） |

**入参无变化**，**无 DDL**，**无新依赖**。

---

## 3. 接口详情

- 方法：GET
- 路径：`/v3/admin/order/{id}/print-itinerary`
- 鉴权：管理后台 JWT（公司隔离后端从 JWT 校验，前端不传）
- 响应：`Result<PrintItineraryRespVO>`

---

## 4. 入参

| 位置 | 字段 | 类型 | 必填 | 说明 |
|------|------|------|:---:|------|
| Path | `id` | String | 是 | 订单 ID |

本次入参无变化。

---

## 5. 出参

### 5.1 顶层（本次变化字段）

| 字段 | 类型 | 说明 | 变化 |
|------|------|------|------|
| `orderNo` | String | 订单号 | 新增 |
| `departDate` | LocalDate(String) | 出团日期 | 新增（原 dateRange 拆分） |
| `returnDate` | LocalDate(String) | 返回日期 | 新增 |
| `orderAmount` | BigDecimal(String) | 订单总额（冻结原价；本地数据恒在，不随 feeDetail 降级） | 新增 |
| `payableTotal` | BigDecimal(String) | 订单应收总额（取消单为 0） | 新增 |
| `outstandingBalance` | BigDecimal(String) | 应收尾款（待收） | 新增 |
| ~~`printTime`~~ | ~~String~~ | 打印时间 | 删除 |
| ~~`dateRange`~~ | ~~String~~ | 出行日期范围 | 删除 |

> 其余顶层字段（agencyName / teamNo / productName / paxSummary / driver·guide·leader Name/Phone / consultantName）不变。

### 5.2 days[] 每日行程（变化字段）

| 字段 | 类型 | 说明 | 变化 |
|------|------|------|------|
| `meals` | List\<MealVO\> | 餐食含餐列表，固定早/午/晚三项 | 新增（原 breakfast/lunch/dinner 三布尔删除） |
| ~~`breakfast` / `lunch` / `dinner`~~ | ~~Boolean~~ | 是否含餐 | 删除，并入 meals |

`MealVO`：

| 字段 | 类型 | 说明 |
|------|------|------|
| `type` | String | 餐次：BREAKFAST / LUNCH / DINNER |
| `label` | String | 餐次中文：早餐 / 午餐 / 晚餐 |
| `included` | Boolean | 是否含餐 |

### 5.3 days[].nodes[] 点位（新增字段）

| 字段 | 类型 | 说明 |
|------|------|------|
| `serviceStandard` | String | 资源服务标准；覆盖景点(SCENIC)/活动(ACTIVITY)/服务(SERVICE)，**餐厅(RESTAURANT)无此字段恒 null**；资源未维护/失败为 null |

> 节点既有字段（nodeName / nodeType / description / startTime / timePeriod / contactPerson / contactPhone / supplierPhone / remark）不变。

---

## 6. 枚举 / 数据字典

| 项 | 值 | 说明 |
|------|------|------|
| `meals[].type` | BREAKFAST / LUNCH / DINNER | 早 / 午 / 晚 |
| `meals[].included` | true | 含团餐 / 特色餐（底层 HOTEL / SPECIAL） |
| `meals[].included` | false | 不含 / 自理（底层 NONE / SELF / 空） |
| `serviceStandard` | 有值 | 仅景点 / 活动 / 服务类资源 |
| `serviceStandard` | null | 餐厅节点，或资源未维护服务标准 |

---

## 7. 错误码

本次无新增错误码。接口为纯查询聚合，Feign 依赖失败走降级（费用块整体 null、联系人/服务标准返空串/null），不抛业务错误。

---

## 8. 示例

### 8.1 典型成功（字段全填示范）

```json
{
  "code": 200,
  "message": "成功",
  "data": {
    "agencyName": "内蒙古呼籁国际旅行社有限公司",
    "orderNo": "HL20260701001",
    "teamNo": "26-0554",
    "productName": "游牧的森林-短途版",
    "departDate": "2026-07-01",
    "returnDate": "2026-07-04",
    "paxSummary": "2大2小",
    "orderAmount": "18000.00",
    "payableTotal": "12000.00",
    "outstandingBalance": "6000.00",
    "driverName": "扎西", "driverPhone": "13700137001",
    "guideName": "", "guidePhone": "", "leaderName": "", "leaderPhone": "",
    "consultantName": "王骁",
    "transports": [
      {"direction": "ARRIVAL", "transportType": "FLIGHT", "transportNo": "CA1234", "carrier": "中国国航", "departStation": "北京首都T2", "arriveStation": "海拉尔东山机场", "departTime": "2026-07-01 08:00:00", "arriveTime": "2026-07-01 10:30:00", "pickupRequired": true, "pickupRemark": "T2出口举牌", "remark": null}
    ],
    "customerOverview": {"customerName": "吕思远", "customerPhone": "138****0020", "adultCount": 2, "childCount": 1, "youngChildCount": 1, "babyCount": 1, "tripDays": 4, "customerType": null, "createSource": "CONSULTANT", "customerRemark": "忌海鲜"},
    "feeDetail": {"items": [{"name": "成人包价", "unitPrice": "3380.00", "qty": 2, "subtotal": "6760.00"}], "singleRoomSurcharge": "0", "grandTotal": "9540.00", "onsiteBalance": "3540.00"},
    "hotels": [
      {"dayNumber": 1, "stayDate": "2026-07-01", "hotelName": "海拉尔海棠酒店", "city": "呼伦贝尔市", "roomCategory": "标间", "roomCount": 4, "contactPerson": "海棠-李经理", "contactPhone": "0470-7777777", "settleType": "公司付款", "paymentMode": "月结", "checkInTime": "14:00", "checkOutTime": "12:00"}
    ],
    "emergencyContacts": [{"contactName": "admin", "contactPhone": "13000000001", "role": "房务"}],
    "days": [
      {
        "dayNumber": 1, "dayDate": "2026-07-01", "dayTitle": "海拉尔接机", "week": "周三",
        "description": "接机入住自由活动",
        "meals": [
          {"type": "BREAKFAST", "label": "早餐", "included": true},
          {"type": "LUNCH", "label": "午餐", "included": false},
          {"type": "DINNER", "label": "晚餐", "included": false}
        ],
        "diningRemark": null,
        "gatherPlace": "{\"name\":\"海拉尔东山机场\",\"cityName\":\"呼伦贝尔市\"}",
        "dismissalPlace": "{\"name\":\"海拉尔海棠酒店\"}",
        "dailyMileage": "200.00",
        "nodes": [
          {"nodeName": "黑山头", "nodeType": "SCENIC", "description": "以壮美日落闻名", "serviceStandard": "黑山头点位服务标准：1.带队提前30分钟到集合点清点人数；2.按行程完成本点位服务；3.如遇异常及时上报计调。", "startTime": "10:00", "timePeriod": null, "contactPerson": "黑山头-前台", "contactPhone": "0470-8800006", "supplierPhone": "", "remark": null},
          {"nodeName": "早餐", "nodeType": "RESTAURANT", "description": "含(酒店)", "serviceStandard": null, "startTime": null, "timePeriod": null, "contactPerson": "", "contactPhone": "", "supplierPhone": "", "remark": null}
        ]
      }
    ],
    "notices": [
      {"level": "FORBIDDEN", "title": "严禁事项 · 违者扣全部车费、永不录用", "color": "#DC2626", "icon": "🚫", "items": ["严禁向客人推荐自费项目、带客进购物店；违者扣除本行程全部车费，且永不录用"]},
      {"level": "WARNING", "title": "警示事项 · 风险由领队、师傅承担", "color": "#D97706", "icon": "⚠️", "items": ["送站时间不得早于出发时间前 2 小时"]},
      {"level": "STANDARD", "title": "流程标准 · 出团必做", "color": "#16A34A", "icon": "✅", "items": ["出发前须核实全程住宿安排"]}
    ],
    "refundNotes": [
      {"sourceName": "黑山头", "intro": "退费说明", "items": [{"title": "单项未骑马", "amount": "100", "unitLabel": "/人", "settleScope": "PER_PERSON", "settleScopeLabel": "按人", "remark": null, "effectiveFrom": null, "effectiveTo": null}]}
    ],
    "handoverChecklist": ["出行群已建立并拉入全部出行人"],
    "collectReceipt": {"collectAmount": "3540.00"},
    "remark": null
  },
  "success": true
}
```

### 8.2 边界（餐厅节点 serviceStandard 恒 null + 未配司机/大交通）

- 餐厅节点 `serviceStandard` 永远 null（resource 模型无此列）。
- 订单未配司机/大交通时 `driverName`/`driverPhone` 为空串、`transports` 为空数组。
- 无配房 → `hotels` 空数组；无固化行程 → `days` 空数组。
- 未录代收款 → `outstandingBalance` 仍按应收派生返回，`collectReceipt.collectAmount` 为 null。

### 8.3 异常（product-v2 报价 Feign 失败）

- `feeDetail` 整块返回 `null`（前端展示"暂无"）。
- 但顶层 `orderAmount`/`payableTotal`/`outstandingBalance` 仍正常返回（本地数据，不受 Feign 影响）。

---

## 9. 业务边界

- 顶层订单金额（orderAmount/payableTotal/outstandingBalance）取自订单本地数据，恒返回，不随 feeDetail 的 product-v2 报价 Feign 降级为 null。
- 服务标准与联系人/电话均为查询类软依赖，失败降级不阻断整单。
- 餐厅节点 serviceStandard 恒 null 属预期（resource restaurant 表无 service_standard 列）。

---

## 10. 修改前后对比

| 字段 | 修改前 | 修改后 |
|------|--------|--------|
| 打印时间 | `"printTime": "2026-07-01T10:00:00"` | 字段删除（前端本地生成） |
| 日期 | `"dateRange": "2026-07-01→2026-07-04"` | `"departDate": "2026-07-01", "returnDate": "2026-07-04"` |
| 订单金额 | 无 | 顶层新增 `orderNo` / `orderAmount` / `payableTotal` / `outstandingBalance` |
| 餐食 | `"breakfast": true, "lunch": false, "dinner": false` | `"meals": [{"type":"BREAKFAST","label":"早餐","included":true}, {"type":"LUNCH","label":"午餐","included":false}, {"type":"DINNER","label":"晚餐","included":false}]` |
| 节点服务标准 | 无 | `days[].nodes[].serviceStandard`（景点/活动/服务有值，餐厅 null） |

---

## 11. 影响评估 / 回滚

**破坏性变更**（前端必须同步）：
1. 删除 `printTime` → 前端改本地生成打印时间。
2. 删除 `dateRange` → 前端改用 `departDate` + `returnDate` 拼接。
3. 删除 `days[].breakfast/lunch/dinner` → 前端改遍历 `days[].meals` 数组（用 label 展示、included 判含餐）。

**非破坏（可选接入）**：顶层订单号/金额、节点 serviceStandard。

**回滚**：接口层回退到 PR #4683 版本（第一轮增强）。零 DDL，无数据迁移，回滚无副作用。

---

## 12. 注意事项

- meals 固定三项、顺序早→午→晚，前端可直接下标或按 type 匹配。
- serviceStandard 是长文本，前端展示注意折行/截断。
- 顶层金额为字符串（防 JS 精度丢失），前端按字符串处理或自行解析。

---

## 13. 关联 / 联系人

- Issue：[#4691](https://git.1814.love:8443/wx/HL/issues/4691)
- PR：[#4692](https://git.1814.love:8443/wx/HL/pulls/4692)
- 前序：[#4683](https://git.1814.love:8443/wx/HL/pulls/4683)（第一轮增强）、[#4650](https://git.1814.love:8443/wx/HL/pulls/4650)（首上线）
- 设计文档：API-SPEC §12.6（四件套 v6.2.2）
- 负责人：腰苏图（yst）
