# resource + product-v2: 节点封面/轮播图/视频按产品线 seasons[0] 季节回落 (基础设施 + MP 消费侧接通)

> **服务**: hl-resource-service (端口 8082) + hl-product-service-v2 (端口 8083)
> **PR**: #2263 (基础设施) + #2271 (MP 消费侧接通)
> **Issue**: #2256 + #2268
> **日期**: 2026-05-14
> **影响范围**: 小程序 C 端 产品详情节点封面/轮播图按当前产品线季节自动切换

---

## ⚠️ 关键变化

紧接 #2243/#2250 节点 description 季节回落。把同款规则推广到节点的 3 个媒体字段:

> 「产品中也要显示对应季节的封面图轮播图视频啥的, 季节没有才显示景区/游玩项目自己的」 — wx 2026-05-14

**取数链路 (回落顺序, 字段独立)**:

```
节点 cover           = scenic_season.cover_material_id  WHERE seasons[0] || scenic_spot.cover_material_id  || null
节点 images (banner) = scenic_season.banner_material_ids WHERE seasons[0] || scenic_spot.banner_material_ids || []
节点 videos (ID 列表) = scenic_season.video_material_ids WHERE seasons[0] || scenic_spot.video_material_ids || []
```

ACTIVITY 节点同款 (activity_season → activity)。产品线 seasons 为 null/空 → 走旧行为(本体), 向前兼容。

季节匹配规则: 取**产品对应产品线** `productLine.seasons[0]` (首个季节), 与封面切换 #2229/#2234 行为一致。

---

## 实现方案 (选 B: 详情装配动态计算, 不写节点表)

`ProductItineraryNodeDO` 本来就没 cover_material_id / banner_material_ids / video_material_ids 列, 加列代价大且与现有资源层季节子表设计正交。

改在 ResourceBatchDetailService 装配 ResourceDetailDTO 时, SCENIC/ACTIVITY 节点的 cover 优先用季节素材 URL → 回落本体, images 优先用季节轮播列表 → 回落本体。下游消费方 (product-v2 toNodeItem) **零改动**自动拿到季节切换值。

PR #2263 改基础设施 + DTO; PR #2271 改 product-v2 MP Assembler 接通 season 参数 (实时路径取 productLine.seasons[0], 快照路径取 snapshot.seasons[0] 符合冻结语义)。

---

## 接口字段变化

### Internal: ResourceDetailDTO 新增 4 字段 (PR #2263)

| 字段 | 类型 | 说明 |
|------|------|------|
| seasonCoverMaterialId | Long | 季节封面素材 ID (按入参 season 命中) |
| seasonBannerMaterialIds | List<Long> | 季节轮播图素材 ID 列表 |
| seasonVideoMaterialIds | List<Long> | 季节视频素材 ID 列表 |
| videoMaterialIds | List<Long> | 视频素材 ID 列表(本体, 补全字段) |

调用方 `GET /internal/resource/batch-details` 加 `season` 入参, 命中时填新字段, 本体 cover/images 同步替换为季节素材 URL。

### MP 端节点透明改善

调用方/前端**无字段变化**, MP `/mp/product/{id}` 返回的节点 `resourceCover` / `resourceImages` 已是季节素材 URL (前端无任何改动)。

---

## 测试服真测 (PASS)

样本产品 `2047216096724873217` 「呼伦贝尔周边摄影季」, productLine `2047215799055118338` 「快乐摄影季」 `seasons=['summer']`, Day 2 SCENIC 节点引用 scenicId=3001000000000000019 (中俄边境公路):

```json
{
  "nodeType": "SCENIC",
  "resourceId": "3001000000000000019",
  "resourceName": "中俄边境公路（卡线）",
  "resourceCover": "https://images.unsplash.com/photo-1472214103451-9374bd1c798e?w=800&q=80",
  "resourceImages": [
    "https://images.unsplash.com/photo-1472214103451-9374bd1c798e?w=800&q=80",
    "https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=800&q=80"
  ]
}
```

- `resourceCover` / `resourceImages` 注入了 summer 季节图 (与产品线 seasons[0]='summer' 匹配, 非本体 OSS 图)
- PR #2229 测试数据脚本配的 summer unsplash URL 命中 ✓

---

## 边界

| 场景 | 节点 cover/images 实际值 |
|------|--------------------------|
| productLine.seasons=`["spring"]` + 景区有 spring scenic_season cover | scenic_season(spring).cover_material_id URL |
| productLine.seasons=`["winter"]` + 景区无 winter season | 回落 scenic_spot.cover 本体 |
| productLine.seasons null/空 | 回落本体 (向前兼容) |
| ACTIVITY 节点 | 同款 (activity_season → activity) |
| Snapshot (订单已下单) | 取 snapshot.seasons[0] (锁定下单时刻, 不实时查产品线 — 快照语义) |
| 节点 description 字段 | 仍走 PR #2250 独立快照(保存时为空才回填), 非空保护用户手填 |

---

## 兼容性

- ResourceDetailDTO `@AllArgsConstructor` 参数顺序变了, 已 grep 全仓库无位置参数 new 调用, 全用 builder 模式
- 老服务消费 DTO 时 Jackson 默认 ignore unknown, 新字段不影响老版本反序列化
- 节点级 images: List<String> 由前端控制保留 (独立快照), 资源/季节级媒体通过 DTO 动态切换, 解耦清晰

---

## 不影响范围

- **仅影响**: 节点详情媒体字段 (cover/images/videoMaterialIds) 装配来源
- **零影响**: 节点 description (走 #2250 链路) / 节点 emojiIcon / 订单创建 / 算价 / 历史已生成的 snapshot (snapshot.seasons 不存在时走 null 兼容)

---

## 相关历史 PR

| PR | Issue | 说明 |
|----|-------|------|
| #2229 | #2227 | 景区列表/封面 season 切换 + scenic_season 表 |
| #2234 | #2232 | 游玩项目同款 + activity_season 表 |
| #2250 | #2243 | 节点 description 按季节回落 highlights |
| **#2263** | **#2256** | 节点媒体基础设施 (ResourceDetailDTO + ResourceBatchDetailService) |
| **#2271** | **#2268** | **MP Assembler 消费侧接通 season 参数** |

---

## 相关文档

- Issue #2256: [wx/HL#2256](https://git.1814.love:8443/wx/HL/issues/2256)
- Issue #2268: [wx/HL#2268](https://git.1814.love:8443/wx/HL/issues/2268)
- PR #2263: [wx/HL#2263](https://git.1814.love:8443/wx/HL/pulls/2263)
- PR #2271: [wx/HL#2271](https://git.1814.love:8443/wx/HL/pulls/2271)
