# 资源服务 + 产品行程节点: 新增「图标」「卖点简介」2 字段

> **服务**: hl-resource-service (端口 8082) + hl-product-service-v2 (端口 8083)
> **PR**: [#2076](https://git.1814.love:8443/wx/HL/pulls/2076) — 已合并 dev + 测试服部署
> **PR (hotfix admin VO 补字段)**: [#2081](https://git.1814.love:8443/wx/HL/pulls/2081) — 已合并 dev + 测试服部署
> **PR (hotfix Flyway pilot marker 解锁)**: [#2077](https://git.1814.love:8443/wx/HL/pulls/2077) — 与本功能间接相关
> **Issue**: [#2068](https://git.1814.love:8443/wx/HL/issues/2068)
> **日期**: 2026-05-12
> **影响范围**: 管理端「资源管理 → 景区/活动/服务」 + 「产品编辑 → 行程编排/产品卖点」 + 小程序「今日体验」
> **状态**: ✅ **测试服已验证** (api.test.1814.love:9443)

---

## ⚠️ 关键变化

**资源端 3 类资源**(景区 scenic-spot / 活动 activity / 服务 service-item) **+ 产品行程节点** product_itinerary_node,**各新增 2 个字段**:

- `iconMaterialId` — 图标素材 ID(指向素材库)
- `sellingPoint` — 卖点简介(VARCHAR 500)

业务联动:
- 资源端**有这两个字段就是默认值**
- 产品行程节点保存时,**前端如果不传**这两字段,后端**自动从资源端拷贝默认值**到节点快照
- 产品行程节点保存时,**前端如果显式传值**,以前端为准(产品端可改)
- 产品端改了节点的 icon/selling 也**不回写资源**(资源端永远是真相源)

---

## 一、测试服已验证 (硬性凭证)

```
hl-resource-service 测试服:
  POST/PUT/GET /admin/scenic/spot     iconMaterialId + sellingPoint 能存能取 ✓
  POST/PUT/GET /admin/activity/item   iconMaterialId + sellingPoint 能存能取 ✓
  POST/PUT/GET /admin/service/item    iconMaterialId + sellingPoint 能存能取 ✓
  GET .../page (列表)                  ListVO 含 iconMaterialId/iconUrl/sellingPoint ✓

hl-product-service-v2 测试服:
  POST /admin/product/item/.../itinerary  节点 SAVE 落库 ✓
  GET /admin/product/item/{id}             节点 VO 返回 iconMaterialId + sellingPoint ✓
  「资源默认值复制」: 前端不传 → 节点字段=资源端 iconMaterialId/sellingPoint ✓
  「前端覆盖优先」: 前端传值 → 节点字段=前端值 ✓
  「不回写资源」: 改节点后资源端字段不变 ✓
```

异常路径:
```
sellingPoint 传 501 字符 → HTTP 200 code=400 "卖点简介不能超过500个字符" ✓
```

---

## 二、变更接口清单

### 资源端

| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 景区 创建 | POST | `/admin/scenic/spot` | 请求体新增 2 字段 | iconMaterialId, sellingPoint |
| 2 | 景区 更新 | PUT | `/admin/scenic/spot` | 请求体新增 2 字段 | 同上 |
| 3 | 景区 详情 | GET | `/admin/scenic/spot/{id}` | 响应体新增 3 字段 | iconMaterialId, iconUrl, sellingPoint |
| 4 | 景区 列表 | GET | `/admin/scenic/spots` | 响应体新增 3 字段 | 列表项含 3 字段 |
| 5-8 | 活动 同上 | - | `/admin/activity/item*` | 同景区 4 接口 | - |
| 9-12 | 服务 同上 | - | `/admin/service/item*` | 同景区 4 接口 | - |

### 产品端

| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 13 | 行程保存 | PUT | `/admin/product/item/{id}/itinerary` | 节点 NodeItem 入参新增 2 字段 | iconMaterialId, sellingPoint(可选) |
| 14 | 产品详情 | GET | `/admin/product/item/{id}` | 节点 NodeRespVO 响应新增 3 字段 | iconMaterialId, iconUrl, sellingPoint |
| 15 | mp 详情 | GET | `/mp/product/{id}` | 节点 NodeInfo 响应新增 3 字段 | 同上,小程序「今日体验」用 |

---

## 三、前端字段约束

| 字段 | 类型 | 必填 | 约束 | 备注 |
|------|------|------|------|------|
| iconMaterialId | Long(产品节点) / String(资源端,String 表示的 BIGINT) | 否 | - | 指向素材库的素材 ID |
| iconUrl | String | 否(仅 Resp) | - | 后端解析素材后的 OSS URL,**前端只在响应中读,不传** |
| sellingPoint | String | 否 | 最多 500 字符 | 卖点简介文字 |

---

## 四、UI 层面建议(参考)

### 资源管理页

3 类资源(景区/活动/服务)的**新建/编辑表单**新增 2 个字段:
- **图标**: 素材库选择器(选小尺寸图,推荐 64x64),保存 materialId
- **卖点简介**: 多行文本框,提示"最多 500 字"

详情页/列表卡片可直接展示这两字段(用 iconUrl + sellingPoint)。

### 产品编辑页

**行程编排** 步骤(图1 的「活动安排」红框):
- 节点点击图标时弹出**素材选择器** → 选完保存到节点的 iconMaterialId
- 节点详情面板新增**卖点简介**输入框(多行,500 字)
- **新建节点时**,选完资源(景区/活动/服务) → 后端自动用资源端默认值预填,前端可改
- **修改节点的 icon/卖点 不会回写到资源**,只影响当前产品的这个节点

**产品卖点页**(图2 的「快速理解」红框):
- 这个页面和「行程编排」**共用同一份 product_itinerary_node 数据**
- 也就是说在「行程编排」改了节点的 icon/卖点,「产品卖点」页面会立刻看到更新

---

## 五、风险/兼容性

- **不破坏现有调用**: 只追加字段,旧请求不传 → null,旧响应消费方忽略新字段无影响
- **Bean Validation**: sellingPoint 后端用 @Size(max=500) 校验,前端最好也加前置校验避免 round-trip
- **不回写资源铁规**: 后端 ProductItineraryService.convertNode() 已硬保证,前端无需关心

---

## 六、需要前端做的事

1. ⏰ **3 类资源管理页** 加 2 个字段:图标素材选择器 + 卖点简介文本框(都不必填)
2. ⏰ **产品编辑 → 行程编排** 加节点的 icon/卖点编辑(都不必填,空就用资源默认)
3. ⏰ **产品编辑 → 产品卖点** 页面如果是独立路由,字段读取同 product_itinerary_node 节点
4. ⏰ 「今日体验」小程序节点前显示图标(iconUrl 字段) + 节点卖点(sellingPoint)
5. 如有疑问可直接对照 swagger: `https://api.test.1814.love:9443/hl-resource-service/v2/api-docs?group=资源服务` 以及 `https://api.test.1814.love:9443/hl-product-service-v2/v2/api-docs?group=产品服务`(账号 hulalv / HuLaLv@Doc2026)
