diff --git a/changelogs/2026-04/2026-04-23_equipment-item-icon-color.md b/changelogs/2026-04/2026-04-23_equipment-item-icon-color.md new file mode 100644 index 0000000..f0b5c34 --- /dev/null +++ b/changelogs/2026-04/2026-04-23_equipment-item-icon-color.md @@ -0,0 +1,138 @@ +# 装备建议条目 EquipmentItem 补 icon + color 字段 + +**日期**: 2026-04-23 +**PR**: #1273 (Closes #1272) +**服务**: hl-product-service-v2 / hl-order-service-v2 / hl-mp-service +**类型**: feat(新增字段,向后兼容) + +--- + +## 背景 + +PR #1259 上线后前端实现装备建议条目 UI,发现需要后端结构化传图标标识和颜色,不希望纯靠前端按 text 关键词猜图标。本次补字段。 + +--- + +## 字段扩展 + +### EquipmentItem 结构 + +```typescript +interface EquipmentItem { + text: string; // 必填,1-50 字 + icon?: string; // 可选,图标 key,≤64 字 + color?: string; // 可选,颜色值,≤16 字(建议 #RRGGBB) +} +``` + +### 约束总表(JSR-303 现已生效) + +| 字段 | 必填 | 长度 | 错误消息 | +|------|------|------|----------| +| text | ✅ | 1-50 字 | `equipmentList[N].text: 装备文案不能为空` / `装备文案长度需在 1-50 字符之间` | +| icon | ❌ | ≤64 字 | `equipmentList[N].icon: 图标标识长度不能超过 64 字符` | +| color | ❌ | ≤16 字 | `equipmentList[N].color: 颜色值长度不能超过 16 字符` | + +**color 格式**:后端不硬校验 `#RRGGBB` 格式,前端可传任意 ≤16 字符串(如 `red` / `#FFA726` / `rgb(255,167,38)`)。推荐 `#RRGGBB` 以便 admin/mp 渲染一致。 + +--- + +## 影响接口(5 处响应 + 1 处请求) + +| 接口 | 变化 | +|------|------| +| `PUT /admin/product/item/{id}/supplement` | 请求 `equipmentList[].icon` / `[].color` 可选 | +| `GET /admin/product/item/{id}` | 响应 `supplement.equipmentList[].icon/color` 新增 | +| `GET /mp/product/{id}` | 响应 `equipmentList[].icon/color` 新增 | +| `GET /mp/order/{id}` | 响应 `equipmentList[].icon/color` 新增(订单快照固化) | +| `GET /mp/order/{orderId}/supplies-checklist` | 响应 `equipmentList[].icon/color` 新增 | + +--- + +## 示例 + +### 保存(带图标和颜色) + +```http +PUT /admin/product/item/123/supplement +{ + "equipmentList": [ + {"text": "防晒霜 SPF50+", "icon": "sunscreen", "color": "#FFA726"}, + {"text": "长袖防晒衣", "icon": "shirt"}, + {"text": "运动鞋"} + ] +} +→ 200 {"code":200, "success":true} +``` + +### MP 详情回显 + +```json +{ + "equipmentList": [ + {"text":"防晒霜 SPF50+", "icon":"sunscreen", "color":"#FFA726"}, + {"text":"长袖防晒衣", "icon":"shirt", "color":null}, + {"text":"运动鞋", "icon":null, "color":null} + ] +} +``` + +### 超限 400 + +```http +PUT .../supplement +{"equipmentList":[{"text":"x","icon":"aaaa...(65字)"}]} +→ 400 {"code":400, "message":"equipmentList[0].icon: 图标标识长度不能超过 64 字符"} +``` + +--- + +## 前端适配建议 + +### 1. icon 字段 +**推荐约定**:前后端商量一份 iconKey 表(如 `sunscreen/shirt/jacket/shoe/bug/hat/sunglasses/water-bottle/umbrella/camera/headlamp/...`),前端内置图标库按 iconKey 查表渲染。 + +**降级逻辑**: +- icon 有值 → 前端按 key 查图标库渲染 +- icon 为 null → 前端按 text 关键词硬匹配图标(PR #1259 方案) +- 都没匹配上 → 显示默认占位图标 + +### 2. color 字段 +- color 有值 → 应用到图标颜色/文字颜色/背景色等 +- color 为 null → 使用主题默认色 + +### 3. admin 编辑器 +- 图标选择:内置 iconKey 下拉选择器(下拉源是前端约定的图标库) +- 颜色选择:内置色板选择器(el-color-picker 等) +- 两字段都可留空(提交时对应字段不传或传 null) + +--- + +## 向后兼容 + +- 现有调用方不传 icon/color:后端接受,DB 存 JSON 不含这两个键 +- 老订单快照:JSON 内条目没有 icon/color 键 → 反序列化后 EquipmentItem.icon/color = null +- **前端可直接升级,旧数据 null 兼容性零风险** + +--- + +## 验证 + +测试服网关已 curl 6 场景全过: +- 混合保存(含 icon+color+只 text)→ 200 +- Admin 详情回显 → 3 条字段精确 +- MP 详情 icon/color 透传 → 正确 +- icon 超 64 字 → 400 +- color 超 16 字 → 400 +- 老数据 null → 自然降级,无回归 + +--- + +## 部署 + +测试服已部署完毕: +- product-v2 task `f7952e0c` success +- order-v2 task `e94c50cd` success +- mp-service task `5b005209` success + +**正式环境部署**:无需 DDL(equipment_list 列已在 PR #1259 DDL 时加,新字段存在同一 JSON 列内)。