新增: 产品标签改单选 + 字典值替换为 热内/新品/限定/硬核/治愈(Issue #1001)

这个提交包含在:
wx 2026-04-20 17:22:24 +08:00
父节点 f0863e0267
当前提交 ddd7a53dbb

查看文件

@ -0,0 +1,101 @@
# 产品标签改单选 + 字典值整体替换
**日期**2026-04-20
**PR**:无代码变更(纯字典数据迁移)
**Issue**#1001
**影响**:管理端产品编辑页 Step1 基础信息「产品标签」
---
## 为什么变
产品侧简化标签心智:
1. 每个产品只配 **1 个标签**(原来多选 chip,现在单选
2. 字典 `product_tag` 整体换值:
- **旧**:亲子 / 城记 / 摄影 / 研学 / 露营
- **新**:热内 / 新品 / 限定 / 硬核 / 治愈
---
## 后端改动
**只改字典,不动接口、不动字段类型**
- `product_tag` 字典:删除 5 个老项,新增 5 个新项sortOrder 1→5
- `ProductDO.tags` 字段**仍然是 `List<String>`**JSON 数组,DB 列类型 JSON,不动
- `ProductBasicSaveReqVO.tags` **仍然是 `List<String>`**,**没加 `@Size(max=1)` 校验**
- 原因:老产品 tags 已有多值(图示摄影/露营/亲子),加硬校验会直接卡死这些产品的保存
- `MpProduct*RespVO.tags` **仍然是 `List<String>`**
- 没有 DDL 变更
### 接口签名不变
| Method | Path | 说明 |
|---|---|---|
| POST | `/admin/product/item/basic` | `tags: string[]` 字段类型完全不变 |
| GET | `/admin/product/item/detail` | 同上 |
| GET | `/mp/product/list` / `/mp/product/detail` | 同上 |
| GET | `/admin/dict/data/product_tag` | 现在返回 5 个新字典项 |
| GET | `/dict/all`(公开)| 其中 `product_tag` 类目返回 5 个新字典项 |
---
## 前端改造(要做)
### 产品编辑页 Step1 —— 产品标签输入控件
- 从**多选 chip** 改为**单选下拉** (Select / Radio Group / 单选 chip 二选一,UI 同学定)
- 选项数据源:`/admin/dict/all``dictType === 'product_tag'``dataList` 5 项
- **提交格式仍然是数组**
```js
// 保持兼容后端 List<String> 字段
saveReqVO.tags = selected ? [selected] : []
```
不要直接传字符串 —— 后端仍按数组接
- **后端没加 max=1 硬校验**,所以就算前端误传 ≥2 个也不会报错,但业务上就按单选出
### 老数据兼容(关键)
现有产品 tags 里可能存了老字典值(摄影/露营/亲子/研学/城记),编辑页打开时:
- **不要把 `tags` 里不在新字典 5 项里的值过滤掉** —— 这会悄悄丢数据
- **建议展示**:老 tag 值按字符串原样显示,加个灰色提示 "已下架标签,请重新选择"
- 用户保存时前端强制用户从 5 个新值中选一个(单选默认行为)
### `/dict/all``product_tag` 新响应
```jsonc
{
"dictType": "product_tag",
"dictName": "产品标签",
"dataList": [
{ "dictValue": "热内", "dictLabel": "热内", "icon": null, "sort": 1 },
{ "dictValue": "新品", "dictLabel": "新品", "icon": null, "sort": 2 },
{ "dictValue": "限定", "dictLabel": "限定", "icon": null, "sort": 3 },
{ "dictValue": "硬核", "dictLabel": "硬核", "icon": null, "sort": 4 },
{ "dictValue": "治愈", "dictLabel": "治愈", "icon": null, "sort": 5 }
]
}
```
- 注意 `dictValue``dictLabel` 都是中文(和老字典保持一致,不是英文 code
- `icon` 字段是昨天新加的(见 [2026-04-20_dict-icon-field.md](./2026-04-20_dict-icon-field.md)),暂时都是 null,产品侧后续可配图标
---
## 数据迁移
**不迁移**。
- 老产品 tags JSON 里存的老字典值字符串**保留**,编辑时按上面"老数据兼容"逻辑展示
- 用户在下次编辑该产品时,按单选从新 5 项里选一个,保存后老值就被覆盖了
- 小程序端列表/详情展示老 tag 时原样显示(即使字典里没这个值)
---
## 验证
- ✅ 测试环境 `/admin/dict/data/product_tag` 返回 5 项(热内/新品/限定/硬核/治愈)
- ✅ `/dict/all` 公开接口 `product_tag` 也是 5 项新值
- ✅ DB `sys_dict_data WHERE dict_type='product_tag'` 5 行无残留老值
- ⏳ 生产环境字典同步:由 wx 手动在正式库执行相同的删 5 加 5后端不出包,不走部署