# 行程节点新增「时间说明」字段(字典 itinerary_time_period)

**日期**: 2026-04-23
**服务**: hl-product-service-v2 / hl-order-service-v2 / hl-mp-service
**影响**: 管理端产品编辑页 + 小程序产品详情/行程详情/今日时间线
**PR**: #1315 + #1317 (hot-fix: DictFeignClient 路径对齐)
**工单**: #1295 / #1316

---

## 背景

产品编辑后台「行程编排」Tab → DAY X → 「活动安排」列表的每个活动节点，新增一个「时间说明」字段（字典下拉）。5 个候选值：清晨 / 上午 / 下午 / 黄昏 / 午夜。

用途：在 start_time 精确时间之外，再提供一个语义化时间上下文标签；小程序端行程页展示更直观。

---

## 新字典 `itinerary_time_period`

```
dict_type_id = 10070
dict_type    = itinerary_time_period
```

| dict_data_id | dict_value     | dict_label |
|--------------|----------------|------------|
| 100701       | EARLY_MORNING  | 清晨       |
| 100702       | MORNING        | 上午       |
| 100703       | AFTERNOON      | 下午       |
| 100704       | DUSK           | 黄昏       |
| 100705       | MIDNIGHT       | 午夜       |

**存储**：`product_itinerary_node.time_period VARCHAR(32) NULL`（历史数据保留 null，不强制回填）

---

## 1. 管理端 `/admin/product/item/{id}/itinerary` 保存

`ItineraryDayItem.nodes[]` / `ProductItinerarySaveReqVO.NodeItem` 新增字段：

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `timePeriod` | `String` | 否 | 字典 `itinerary_time_period` 值：`EARLY_MORNING` / `MORNING` / `AFTERNOON` / `DUSK` / `MIDNIGHT`。可为 null。 |

**PUT 请求示例**：
```json
{
  "itinerary": [{
    "dayNumber": 1,
    "nodes": [
      { "nodeName": "ATV 越野", "startTime": "10:00", "timePeriod": "MORNING" },
      { "nodeName": "湿地日落",  "startTime": "18:00", "timePeriod": "DUSK" }
    ]
  }]
}
```

---

## 2. 管理端 `GET /admin/product/item/{id}` 回显

`ItineraryDayRespVO.NodeRespVO` 新增字段：

| 字段 | 类型 | 说明 |
|------|------|------|
| `timePeriod` | `String` | 字典值（管理端下拉回显） |

管理端前端：下拉框 `options` 请从 `GET /admin/dict/data?dictType=itinerary_time_period` 拉取，绑定 `value/label`。

---

## 3. 小程序产品详情 `GET /mp/product/{id}`

`MpProductDetailRespVO.DayInfo.nodes[]` (`NodeInfo`) 新增两字段：

| 字段 | 类型 | 说明 |
|------|------|------|
| `timePeriod` | `String` | 字典值（如 `EARLY_MORNING`） |
| `timePeriodLabel` | `String` | 字典中文标签（如 `清晨`），null 表示未设置 |

前端直接展示 `timePeriodLabel`，为 null 不显示该标签即可。

---

## 4. 小程序行程详情 `GET /mp/trip/{orderId}`

订单进行中/已完成的行程页面 `data.itineraryDays[].nodes[]` 和 `data.dailyItinerary[].nodes[]` 两条路径新增：

| 字段 | 类型 | 说明 |
|------|------|------|
| `timePeriod` | `String` | 字典值，来自订单快照 |
| `timePeriodLabel` | `String` | 字典中文标签 |

**老订单兼容**：下单时快照中若没有 `time_period` 字段，反序列化后 `timePeriod = null` / `timePeriodLabel = null`，接口 200 不会报错。

---

## 5. 小程序今日时间线 `GET /mp/today/timeline`

`MpTripItineraryNodeVO` 新增：`timePeriod` + `timePeriodLabel`（字段含义同上）。前端逻辑同产品详情。

---

## 前端对接要点

1. 管理端新增编辑行程节点表单：下拉组件调字典接口 `itinerary_time_period`，绑定到节点的 `timePeriod` 字段，保存到 `PUT /admin/product/item/{id}/itinerary`。
2. 管理端回显：读 `GET /admin/product/item/{id}` 的 `itinerary[].nodes[].timePeriod`，在下拉组件 `v-model` 上。
3. 小程序三处（产品详情 / 行程详情 / 今日时间线）：优先展示 `timePeriodLabel`，null 时不显示该标签；需要精确时间仍用 `startTime`（HH:mm）。
4. 前端无需单独调字典接口，后端已在响应里填好 `timePeriodLabel`。

---

## 关联说明（2026-04-23 部署时踩坑）

首次部署 #1315 后，`timePeriodLabel` 全部返回 null。排查发现是 **pre-existing bug**：

- `DictFeignClient`（hl-common-feign）声明路径 `GET /internal/dict/data-by-type`
- `hl-user-service` 实际仅实现 `GET /internal/dict/data`

路径 mismatch 导致所有下游（review / complaint / trip / mpProductDetail）的字典 Feign 调用长期走 fallback。已由 **#1317 热修**（Feign 路径对齐 `/data`）后所有下游字典翻译恢复。

---

## 部署顺序（仅对测试/正式运维提醒）

1. DDL: `ALTER TABLE product_itinerary_node ADD COLUMN time_period VARCHAR(32) NULL AFTER start_time`
2. 字典 INSERT 5 条（type 10070 / data 100701~100705）
3. 重新部署 hl-product-service-v2 / hl-order-service-v2 / hl-mp-service（依赖 hl-common-feign 新版 Feign 路径）
4. 清 Redis `cache:dict:data:*`（或等 TTL）防读到旧映射
