diff --git a/changelogs/2026-05/21_refactor_material_remove_review_feature.md b/changelogs/2026-05/21_refactor_material_remove_review_feature.md new file mode 100644 index 0000000..74e9132 --- /dev/null +++ b/changelogs/2026-05/21_refactor_material_remove_review_feature.md @@ -0,0 +1,131 @@ +# refactor(material): 拆除素材审核遗留功能(reviewStatus 字段 + 字典 + DTO 全删) + +> **仓库**: HL (后端 hl-resource-service + hl-user-service) +> **关联 PR/Issue**: PR #2795, Closes #2789 +> **日期**: 2026-05-21 +> **影响范围**: 管理后台「素材库」批量审核/批量驳回功能整体废弃 +> **接收方**: mmg (前端) +> **前端**: **需要改动 — 拆按钮 + 删 API** + +--- + +## 🚨 关键变化 + +「素材审核」功能业务上已不需要,本次全部拆除: + +- 后端 `Material.reviewStatus` 字段删除 +- DB `material.review_status` 列 DROP +- DB 字典 `material_review_status` DELETE +- `MaterialReviewRequest` DTO 删除 + +**正式环境之前批量审核接口 `PUT /admin/material/review` 触发的「参数类型错误: materialId='review'(需要 Long 类型)」报错根因就是这两条**:前端调了 `/admin/material/review` 但后端从未实现该接口,Spring 把 `review` 当成 `{materialId}` 路径变量去解析 Long,报错。 + +--- + +## 一、API 影响 + +### 不再存在的接口(后端从未实现) + +``` +PUT /admin/material/review ← 不再支持(前端有死调用) +PUT /admin/material/reject ← 不再支持(前端有死调用) +``` + +### 字段移除 + +| 接口 | 字段 | 改前 | 改后 | +|------|------|------|------| +| `GET /admin/material/list` | `reviewStatus` | 不返回(VO 本就没此字段) | 不返回(一致) | +| `GET /admin/material/{id}` | `reviewStatus` | 不返回(VO 本就没此字段) | 不返回(一致) | + +> 实际 VO 层本来就没有 `reviewStatus` 字段,只是 Entity 层和 DB 列还在,本次一并清理。响应字段对前端无任何观测变化。 + +--- + +## 🚨 前端需要做的事 + +### 1. 删除批量审核/批量驳回 API + +文件:`hl-ui/src/api/material.js` 第 335-353 行 + +```js +// 整段删掉 +// ========== 素材审核 ========== + +/** + * 批量审核通过 + */ +export function reviewMaterials(materialIds) { + return http.put('/material/review', { materialIds }) +} + +/** + * 批量驳回素材(删除) + */ +export function rejectMaterials(materialIds) { + return http.put('/material/reject', { materialIds }) +} +``` + +### 2. 拆 UI 按钮 + 弹窗 + +文件:`hl-ui/src/views/material/index.vue` + +- 删除「批量审核」按钮、「批量驳回」按钮 +- 删除「批量审核确认」弹窗及相关逻辑 +- 列表/详情若有 `reviewStatus` 列或字段显示,一并删(实际 API 本就不返回) + +### 3. 自查 + +请 mmg 全前端 grep 一遍: + +```bash +grep -rE "reviewMaterials|rejectMaterials|material.*review|批量审核|审核通过|审核状态" hl-ui/src +``` + +如有残留请一并清理。 + +--- + +## 二、DB 改动(Flyway 已自动跑) + +- `hl-resource-service` `V20260521_001__drop_material_review_status.sql` — `ALTER TABLE material DROP COLUMN review_status`(MySQL 8.0 兼容写法,列不存在时跳过) +- `hl-user-service` `V20260521_006__drop_material_review_status_dict.sql` — `DELETE` `sys_dict_type` + `sys_dict_data` 中 `material_review_status` 全部行 + +> dev 上的 user-service Flyway 文件名是 `V20260521_002`,dev-v3 上为避免 out-of-order 改名为 `V20260521_006`。两个分支文件名不同但 SQL 内容完全一致。 + +--- + +## 三、兼容性 / 风险 + +- ✅ VO 层本就无 `reviewStatus` 字段,前端列表/详情响应字段零变化 +- ✅ Flyway 用 `information_schema` 防御,多环境部署安全(本地无此列也能跑过) +- ✅ DB 历史 `review_status` 值(如 PENDING/REJECTED)随列 DROP 丢失语义,业务已确认不需要 +- ⚠️ 前端 `PUT /admin/material/review` `/admin/material/reject` 调用 100% 报错(路径变量 Long 解析失败),mmg 改前端前用户使用「批量审核」按钮会持续报错 + +--- + +## 四、测试服验证记录 + +部署到测试服 (`https://web.test.1814.love:9443`) 后已 round-trip 验证(2026-05-21 14:01): + +``` +✓ GET /admin/material/list?page=1&pageSize=1 + → 响应 item keys 中无 reviewStatus + +✓ GET /admin/dict/data/material_review_status + → code=200, data=[] (字典已清空) +``` + +Flyway 自动执行: +- hl-resource-service 启动时跑 `V20260521_001__drop_material_review_status.sql` → `material.review_status` 列已 DROP +- hl-user-service 启动时跑 `V20260521_006__drop_material_review_status_dict.sql` → 字典 `material_review_status` 已 DELETE + +--- + +## 五、联系人 + +后端:wx(呼籁旅行) +前端:mmg + +如有疑问可在 [#2789](https://git.1814.love:8443/wx/HL/issues/2789) 评论区留言。 diff --git a/changelogs/2026-05/21_refactor_team_role_picker_use_staff_type_dict.md b/changelogs/2026-05/21_refactor_team_role_picker_use_staff_type_dict.md new file mode 100644 index 0000000..22fede1 --- /dev/null +++ b/changelogs/2026-05/21_refactor_team_role_picker_use_staff_type_dict.md @@ -0,0 +1,160 @@ +# refactor(product): 「添加团队成员」角色弹窗改为 staff_type 字典动态获取 + +**日期**:2026-05-21 +**PR**:无(后端零改动,字典与字典查询接口均已就绪) +**工单**:[#2790](https://git.1814.love:8443/wx/HL/issues/2790)(同步关闭 hl-api-changelog [#7](https://git.1814.love:8443/wx/hl-api-changelog/issues/7)) +**影响端**:管理后台前端(hl-ui) + +--- + +## 背景 + +产品编辑页 → 「添加团队成员」弹窗(`hl-ui/src/views/product/edit/components/modals/StaffPickerModal.vue:23-28`)的「选择角色」区域当前是 4 个 **写死** 的标签: + +```js +const roleOptions = [ + { label: '主领队', value: 'LEADER', limit: 1 }, + { label: '副领队', value: 'DEPUTY_LEADER', limit: 3 }, // 后端字典无此值 + { label: '摄影师', value: 'PHOTOGRAPHER', limit: 2 }, + { label: '司机', value: 'DRIVER', limit: 5 }, // 业务上不属于服务人员 +] +``` + +**问题**: +1. 后端 `staff_type` 字典里**根本没有 DEPUTY_LEADER**,前端保存后字典翻译不出中文,是孤儿值。 +2. 业务确认:**服务人员不包括司机**,DRIVER 不应出现在团队成员候选里。 +3. 后端 `staff_type` 字典已扩展到 7 项(导游 / 导游助理 / 摄影师 / 领队 / 其他 / 研学老师 / 生活老师),前端写死 4 项导致「导游 / 导游助理 / 研学老师 / 生活老师」都选不到——hl-api-changelog#7 已反馈过同一问题。 + +--- + +## 业务决策(wx 已确认) + +- **角色列表来源**:直接复用 **服务人员管理页「人员类型」那列对应的 `staff_type` 字典**(不要再造新字典) +- **主/副领队合并为 LEADER**:同一团里可加多个 LEADER,不在角色层区分主副 +- **司机不出现在候选**:司机另由车辆/驾驶员模块管理 +- **后续可扩展**:业务再加 staff_type 字典值时前端零改动自动出现 + +--- + +## 字典数据(staff_type,测试服已落库) + +通过 `GET /admin/dict/data/staff_type` 拉取: + +| sortOrder | dictValue | dictLabel | 说明 | +|-----------|-----------|-----------|------| +| 1 | `GUIDE` | 导游 | | +| 2 | `GUIDE_ASSISTANT` | 导游助理 | | +| 3 | `PHOTOGRAPHER` | 摄影师 | | +| 4 | `LEADER` | 领队 | | +| 5 | `OTHER` | 其他 | | +| — | (业务追加) | 研学老师 / 生活老师 / ... | 字典动态扩展,前端零改动 | + +> 实际项数以接口返回为准(后续业务可能继续追加),不要在前端写死个数或枚举值。 + +--- + +## 🚨 前端需要做的事 + +### 1. 删除硬编码 + +文件:`hl-ui/src/views/product/edit/components/modals/StaffPickerModal.vue` + +把第 23-28 行的 `roleOptions` 硬编码删掉。 + +### 2. 改成调字典接口 + +调用:`GET /admin/dict/data/staff_type`(已存在的通用字典 API) + +**Header**:需要 admin token + +**响应结构**: + +```json +{ + "code": 200, + "message": "成功", + "data": [ + { "dictValue": "GUIDE", "dictLabel": "导游", "sortOrder": 1, "status": "ACTIVE" }, + { "dictValue": "GUIDE_ASSISTANT", "dictLabel": "导游助理", "sortOrder": 2, "status": "ACTIVE" }, + { "dictValue": "PHOTOGRAPHER", "dictLabel": "摄影师", "sortOrder": 3, "status": "ACTIVE" }, + { "dictValue": "LEADER", "dictLabel": "领队", "sortOrder": 4, "status": "ACTIVE" }, + { "dictValue": "OTHER", "dictLabel": "其他", "sortOrder": 5, "status": "ACTIVE" } + // 业务追加的值按字典实际数量返回 + ] +} +``` + +### 3. 下拉/标签组绑定动态数据 + +```js +// 推荐:直接复用全局 dictStore(如已有) +import { useDictStore } from '@/stores/dict' +const dictStore = useDictStore() +const roleOptions = computed(() => + dictStore.getDictData('staff_type').map(d => ({ + label: d.dictLabel, + value: d.dictValue, + })) +) +``` + +如果暂时没全局字典 store,组件级 `onMounted` 拉一次即可(字典后端有 5 分钟 Redis 缓存)。 + +### 4. 联动 `getStaffPage` + +弹窗下半段调 `getStaffPage({ staffType: selectedRole.value, ... })` 时,`staffType` 参数直接传字典 `dictValue`(无需做映射,前后端值一致)。 + +### 5. `limit`(人数上限) + +业务暂无强制需求,前端可: +- A. 不限制(推荐,简化逻辑) +- B. 前端约定一份固定 map(不影响后端) +- C. 后续如需在字典 `remark` 放 `{"limit":N}` JSON,后端可补,前端解析 + +--- + +## 关联清理(mmg 请一并自查) + +`hl-api-changelog#7` 还提到:"请扫描代码中是否有其他地方也硬编码了这套角色枚举(订单成员配置、薪酬结算、小程序"服务团队"展示等)"。 + +请 mmg 一并核查以下位置是否硬编码同一份枚举,如有请同步改造为字典化: +- 订单详情/列表的成员展示 +- 小程序「服务团队」展示 +- 团队成员编辑/批量编辑组件 +- 各页面 staff_type 标签颜色 map + +--- + +## 历史数据 + +后端有零代码改动,但需关注产品快照里是否已有 `DEPUTY_LEADER` / `DRIVER` 孤儿值: + +```sql +-- 测试服执行核查(hl_product_service_v2 数据库) +SELECT DISTINCT staff_role, COUNT(*) +FROM group_batch_staff +GROUP BY staff_role; +``` + +- 如有 `DEPUTY_LEADER`:评估迁移为 `LEADER` +- 如有 `DRIVER`:评估删除或归 `OTHER` +- 如查询结果都是 `LEADER` / `PHOTOGRAPHER` / `GUIDE` 等正常值:无需迁移 + +后端将由 wx 在 [#2790](https://git.1814.love:8443/wx/HL/issues/2790) 关单 comment 中给出实际数据扫描结果。 + +--- + +## 兼容性 + +- ✅ 后端零改动,无回归风险 +- ✅ 字典服务挂掉时前端可 fallback 到 staff_type 字典已有的固定 5 项 +- ✅ 字典本身有 Redis 5 分钟缓存,QPS 无压力 + +--- + +## 联系人 + +后端:wx(呼籁旅行) +前端:mmg + +如有疑问或字典接口路径需要确认,可在 [#2790](https://git.1814.love:8443/wx/HL/issues/2790) 评论区留言。