12_feat resource icon_svg + node emojiIcon default copy (PR HL#2100)

这个提交包含在:
API Changelog Bot 2026-05-12 15:48:07 +08:00
父节点 f123422ecc
当前提交 6ca3467685

查看文件

@ -0,0 +1,109 @@
# 后端 feat 通知 — 资源 3 类加回 icon_svg, 节点选资源时默认带到 emojiIcon
**日期**: 2026-05-12
**类型**: 后端新增功能 (PR #2100)
**模块**: 资源服务 (景区/游玩项目/服务) + 产品行程节点
**通知**: @mmg
**前端是否需改动**: **需要** — 资源管理 3 个编辑弹窗加"上传 SVG 图标"入口
**严重性**: P2
---
## 背景
前端反馈 PR #2091 后, 资源管理弹窗里**没法维护"图标"**。之前删 iconSvg 时把资源端的也一起删了过头, 但资源端实际没有可复用的图标字段 (cover_material_id 是大封面图, 语义不同)。
本次给资源 3 表加回 `icon_svg TEXT` 字段, 用户在资源管理页能上传 SVG 图标。节点选资源时, 后端自动把资源 iconSvg 复制到节点 emojiIcon (与 PR #2096 highlights→description 同样的"默认值, 可改不回写"机制)。
---
## API 变化
### 资源 admin CRUD 接口 (3 类)
**景区** `/admin/scenic/spot` POST/PUT/GET, **游玩项目** `/admin/activity/...`, **服务** `/admin/service-item/...`:
**请求体新增字段** (可选):
```json
{
"iconSvg": "<svg viewBox=\"0 0 24 24\"><path d=\"...\"/></svg>"
}
```
**响应体新增字段**:
```json
{
"iconSvg": "<svg viewBox=\"0 0 24 24\"><path d=\"...\"/></svg>"
}
```
ListVO 也包含 iconSvg, 前端列表可以快速预览图标。
### 资源端内部 Feign
`GET /internal/mp/resource/batch-details` 返回 `ResourceDetailDTO` **新增 iconSvg 字段** (字段顺序: description → highlights → iconSvg → cover)。
### 产品节点保存接口
`PUT /admin/product/item/{id}/itinerary` 节点保存时:
- 节点不传 `emojiIcon` + 选了资源 (resourceId 非空) + 资源 iconSvg 非空 → **后端自动用资源 iconSvg 填到 node.emojiIcon**
- 节点显式传 emojiIcon → 不被覆盖
- 之后修改资源 iconSvg 不影响已存在的节点 (节点 emojiIcon 是独立快照, 不回写资源)
### 产品/MP 节点查询接口
`GET /admin/product/item/{id}` + 等 MP 接口: `node.emojiIcon` 字段结构不变, 但可能比之前更常有 SVG 字符串内容 (自动带的)。
---
## 前端 mmg 行动项
### 1. 资源管理 3 个编辑弹窗加图标上传 (景区/游玩项目/服务)
建议位置: 编辑弹窗的「媒体素材」tab 里, 紧挨"封面图"上传组件下方加一个"小图标"上传组件:
- 接受 .svg 文件或直接粘贴 SVG XML
- 后端字段名: `iconSvg`
- 限制: TEXT 列, 一般 SVG 大小都不超过 64KB 完全够
### 2. 节点 emojiIcon 渲染逻辑增强 (可选)
之前 emojiIcon 存的是 lucide 名 (如 "map-pin"), 现在可能是 SVG XML 字符串。前端渲染逻辑建议:
```js
if (emojiIcon?.startsWith("<svg")) {
// 直接渲染 SVG (注意 XSS, 用 v-html 时套 DOMPurify)
} else {
// lucide-icon 组件渲染
}
```
如果前端已经按这个分支处理, 那不用动。
### 3. 节点编辑页 emojiIcon 字段
节点编辑页若有 emojiIcon 输入框, 用户选完资源后**后端会自动填一个默认 SVG**。用户可以保留 (不动)、清空 (设为 null) 或换 lucide 名/其他 SVG。
---
## 测试服实测结果
部署版本: dev 最新 (PR #2100 已合并)
| 场景 | 期望 | 实测 |
|------|------|------|
| 资源 PUT 带 iconSvg | DB 存入, GET 返回 | ✅ PASS (景区 2029818530992472065 写入读出一致) |
| 节点不传 emojiIcon + 选有 iconSvg 的资源 | node.emojiIcon = 资源 iconSvg | ✅ PASS |
| Flyway V20260512_004 | 3 表都加上 icon_svg 列, success=1 | ✅ PASS |
测试数据已清理 (节点临时数据 + 资源 iconSvg 已置 NULL)。
---
## DB Schema 变化 (前端无关, 仅记录)
V20260512_004:
```sql
ALTER TABLE scenic_spot ADD COLUMN icon_svg TEXT NULL COMMENT 'SVG 图标源码';
ALTER TABLE activity ADD COLUMN icon_svg TEXT NULL COMMENT 'SVG 图标源码';
ALTER TABLE service_item ADD COLUMN icon_svg TEXT NULL COMMENT 'SVG 图标源码';
```
节点表 `product_itinerary_node` **不动** (继续用 emojiIcon TEXT, 不加新列)。