frontend-notice: 修订方向 — 评价举报融入「人工复审队列」tab(不新建独立页面)

用户截图反馈现有「内容安全」菜单 6 个二级,他的产品语义是
*在已有「人工复审队列」页面里就能处理举报*,而不是新加一个
评价举报处理独立菜单。

修订前: 新建二级菜单「评价举报处理」
修订后: 现有「人工复审队列」页面顶部 tab 加第 4 项「评价举报」
       (TRAVELER / USER_NICKNAME / USER_AVATAR / REVIEW)
       REVIEW tab 调用已就绪的 /admin/review/report-queue/* 5 个 API,
       操作按钮按 reportStatus 路由(隐藏/恢复/警告作者/忽略).

后端依然 0 改动,前端 ~1.5 天闭环。
这个提交包含在:
API Changelog Bot 2026-05-06 21:08:42 +08:00
父节点 c61b2b832f
当前提交 37494f4cc8

查看文件

@ -1,144 +1,182 @@
# frontend-notice: 评价举报处理页面 mmg 待接入(后端 #1668 已就绪 + #1755 BFF 已通)
# frontend-notice: 「人工复审队列」页面加 REVIEW tab(融合评价举报,后端 #1668 已就绪)
**通知对象**: @mmg
**关联**: [PR #1668](https://git.1814.love:8443/wx/HL/pulls/1668)(后端 admin API 5 个)+ [PR #1755](https://git.1814.love:8443/wx/HL/pulls/1755)mp BFF 透传)
**问题反馈**: 2026-05-06 用户反馈"客户举报成功了应该在人工复审队列中展示 现在没有"
**方向修正**: ⚠️ 此前同名 changelog 让你"新建独立页面"——方向改为 **在现有「人工复审队列」页面加 tab 融合**,以下为最终方案
---
## 背景
## 用户产品语义
测试服客户从小程序点举报 `POST /mp/review/report` 已经能成功落库到 `review_report` 表 + `order_review.report_status`,但管理后台「内容安全 → 人工复审队列」页面查不到——因为那个页面后端只查 `traveler/user.audit_status`,**评价举报数据走的是另一个独立的 admin 队列**,前端 hl-ui 当前**没有对应的页面对接**。
PR #1668Phase 2D, 已合 main 2026-05-05后端把 5 个 admin 操作 API 都准备好了,前端漏建。本次需要 mmg 在 admin 后台「内容安全」一级菜单下新增二级菜单 **「评价举报处理」**,对接以下 5 个接口。
后端 0 改动。
进「内容安全 → 人工复审队列」页面就能看到所有需要复审的内容(包括出行人姓名、用户昵称、头像,**也包括评价举报**)+ 在同页面就能处理(隐藏/恢复/忽略/警告)。**不要新建独立的"评价举报处理"二级菜单**。
---
## 推荐 UI 位置
## 现状
「内容安全」一级菜单下,与「人工复审队列」并列,新增二级菜单 **「评价举报处理」**。
理由:评价举报跟出行人姓名、用户昵称、用户头像同属"内容安全"分类,但数据源/操作语义不同(隐藏/恢复 vs 通过/驳回),独立成页比硬塞进现有人工复审队列更清晰。
---
## 接口清单
### 1. 分页查询
后台「内容安全 → 人工复审队列」页面当前调:
```
GET /admin/review/report-queue/page
GET /admin/wx-security/manual-review/page?bizType=TRAVELER
```
**Query 参数**`AdminReportQueuePageReqVO`:
- `page` (int, 默认 1)
- `pageSize` (int, 默认 20)
- `reportStatus` (String, 可选): `NORMAL` / `PENDING_REVIEW` / `HIDDEN`
- `keyword` (String, 可选): 评价内容/作者昵称模糊匹配
支持 `bizType` ∈ {TRAVELER, USER_NICKNAME, USER_AVATAR},三类的查询/通过/驳回操作 5 个 API。
**响应**: `Result<PageResult<AdminReportQueueItemRespVO>>`
`AdminReportQueueItemRespVO` 字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| `reviewId` | Long (JsonFormat.STRING) | 评价 ID |
| `content` | String | 评价正文 |
| `userNickname` | String | 评价作者昵称 |
| `userId` | Long (JsonFormat.STRING) | 评价作者 ID |
| `productName` | String | 关联产品名 |
| `status` | String | 评价本身状态PUBLISHED 等) |
| `reportCount` | Integer | 总举报数 |
| `reportStatus` | String | NORMAL / PENDING_REVIEW / HIDDEN |
| `hiddenAt` | LocalDateTime | 隐藏时间null 未隐藏) |
| `hiddenReason` | String | 隐藏原因 |
| `createTime` | LocalDateTime | 评价创建时间 |
| `reasonStats` | Map<String, Integer> | 各 reason 统计,e.g. `{"SPAM":3,"OFFENSIVE":1}` |
| `reporters` | List | 举报人列表,每个含 `reportId/reporterUserId(JsonString)/reporterOpenid(脱敏)/reason/detail/status/createTime` |
### 2. 隐藏评价
```
POST /admin/review/report-queue/{reviewId}/hide
Body: { "reason": "违规广告" }
```
后端动作: `review.report_status=HIDDEN` + 该评价所有 `review_report.status=HANDLED`
### 3. 恢复评价
举报评价数据走另一套独立 admin API(已就绪,后端 0 改动):
```
GET /admin/review/report-queue/page?reportStatus=PENDING_REVIEW
POST /admin/review/report-queue/{reviewId}/hide Body: { "reason": "..." }
POST /admin/review/report-queue/{reviewId}/restore
```
后端动作: `review.report_status=NORMAL` + `report_count=0` + 所有 `review_report.status=IGNORED`
### 4. 单条忽略举报
```
POST /admin/review/report-queue/report/{reportId}/ignore
```
后端动作: 仅改单条 `review_report.status=IGNORED`,不动评价本身。用于"举报不实/驳回单条举报"。
### 5. 警告作者
```
POST /admin/review/report-queue/{reviewId}/warn-author
```
后端动作: 当前仅落操作日志(站内信 SDK 未集成,后端 TODO。前端按钮可正常调用,文案"警告作者"即可。
---
## 前端融合方案
### 1. 页面顶部 tab 加第 4 项 "评价举报"
```
[出行人姓名] [用户昵称] [用户头像] [评价举报] ← 新增
```
对应 `bizType` 内部值: `TRAVELER` / `USER_NICKNAME` / `USER_AVATAR` / `REVIEW`
### 2. tab 路由不同 API
| 当前 tab | 列表接口 | 操作接口 |
|---|---|---|
| TRAVELER / USER_NICKNAME / USER_AVATAR | `GET /admin/wx-security/manual-review/page?bizType=X` | `/admin/wx-security/manual-review/{approve,reject}` |
| **REVIEW** | `GET /admin/review/report-queue/page` | `/admin/review/report-queue/{reviewId}/{hide,restore,warn-author}` + `report/{reportId}/ignore` |
### 3. tab=REVIEW 时表格列建议
| 列名 | 数据来源 |
|---|---|
| 评价内容 | `content` (≤ 100 字省略号) |
| 作者 | `userNickname`(超链接到用户详情用 `userId`) |
| 关联产品 | `productName` |
| 举报数 | `reportCount` |
| 状态 | `reportStatus` 中文化(详见下文枚举) |
| 举报原因统计 | `reasonStats`(图表或 `广告 3 / 辱骂 1` 格式),通过字典 `review_report_reason` 翻译 label |
| 隐藏时间 | `hiddenAt`(状态 = HIDDEN 时显示) |
| 创建时间 | `createTime` |
| 操作 | 按 `reportStatus` 显示不同按钮(下文) |
### 4. 操作按钮(按 reportStatus 路由)
| reportStatus | 中文 | 显示按钮 |
|---|---|---|
| `NORMAL` | 正常 | 警告作者 / 忽略全部 |
| `PENDING_REVIEW` | 待复审 | **隐藏评价**(主按钮) / 警告作者 / 忽略全部 |
| `HIDDEN` | 已隐藏 | **恢复评价**(主按钮) |
> "忽略全部" = 列表内每条 `reporters[]` 行循环调 `POST /admin/review/report-queue/report/{reportId}/ignore`(批处理)
> "警告作者" → `POST /admin/review/report-queue/{reviewId}/warn-author`(后端目前仅落日志,站内信 SDK 待集成)
> "隐藏评价" 弹框输入 reason → `POST /admin/review/report-queue/{reviewId}/hide` body `{reason}`
> "恢复评价" → `POST /admin/review/report-queue/{reviewId}/restore`
### 5. 展开行(可选,推荐)
点击行展开看 `reporters[]` 数组,每个举报人:
| openid(脱敏) | 举报原因 | 详细说明 | 状态 | 时间 | 操作 |
|---|---|---|---|---|---|
| `oABCD***1234` | 垃圾营销 | (用户填的 detail) | PENDING / IGNORED / HANDLED | createTime | [忽略本条] |
`[忽略本条]``POST /admin/review/report-queue/report/{reportId}/ignore`
---
## 字典
## 接口字段清单
`review_report_reason`(举报原因)已通过 V20260505_007 + V20260507_001 初始化:
### `AdminReportQueueItemRespVO`(列表项)
| 字段 | 类型 | 说明 |
|---|---|---|
| `reviewId` | Long (`@JsonFormat(shape=STRING)`) | 评价 ID |
| `content` | String | 评价正文 |
| `userNickname` | String | 评价作者昵称 |
| `userId` | Long (JsonString) | 评价作者 ID |
| `productName` | String | 关联产品名 |
| `status` | String | 评价本身状态(PUBLISHED 等) |
| `reportCount` | Integer | 总举报数 |
| `reportStatus` | String | NORMAL / PENDING_REVIEW / HIDDEN |
| `hiddenAt` | LocalDateTime | 隐藏时间(null 表示未隐藏) |
| `hiddenReason` | String | 隐藏原因(管理员填的) |
| `createTime` | LocalDateTime | 评价创建时间 |
| `reasonStats` | `Map<String, Integer>` | 各 reason 统计 e.g. `{"SPAM":3,"OFFENSIVE":1}` |
| `reporters` | List | 举报人列表(展开行用) |
`reporters[]` 每项: `reportId / reporterUserId(JsonString) / reporterOpenid(已脱敏) / reason / detail / status / createTime`
### `AdminReportQueuePageReqVO`(查询参数)
```
GET /admin/review/report-queue/page
?page=1
&pageSize=20
&reportStatus=PENDING_REVIEW (可选,前端 tab 内嵌"全部/待复审/已隐藏"子筛选时用)
&keyword=违规广告 (可选,模糊匹配评价内容/作者昵称)
```
### 字典 `review_report_reason`
通过 `GET /admin/system/dict-data/by-type?dictType=review_report_reason` 拿:
| value | label |
|---|---|
| `SPAM` | 垃圾营销 |
| `OFFENSIVE` | 不友善/辱骂 |
| `OFFENSIVE` | 不友善/辱骂(注: 后端实际入库 dictValue 也可能是 `INSULT` 见 V20260507_001) |
| `FRAUD` | 欺诈/虚假 |
| `OTHER` | 其他 |
前端展示 `reasonStats` 时,key 是 value(如 SPAM),需要通过字典查询接口 `/admin/system/dict-data/by-type?dictType=review_report_reason` 拿 label。
> 字典值后端权威以 `/admin/system/dict-data/by-type` 实际返回为准,前端动态渲染不要硬编码
---
## 操作按钮文案建议
## 列表排序与分页
针对 `reportStatus`:
- **NORMAL**: 显示"忽略全部" / "警告作者"(举报数 < 3,无需隐藏
- **PENDING_REVIEW**: 显示"隐藏评价" / "忽略全部" / "警告作者"(举报数 ≥ 3 或再机审命中)
- **HIDDEN**: 显示"恢复评价"(已隐藏)
每条 `reporters` 行内显示"忽略本条举报"按钮(接口 4
后端默认按 `reportCount DESC, create_time DESC` 排序,**前端不要重排**。
分页用标准 `page` / `pageSize`,响应 `total` / `records`
---
## 开发提示
## 兼容现有 3 类的 UX
- 5 个接口都已有 swagger 文档,启 hl-admin-service 后访问 `/swagger-ui/` 可在线试。
- `reviewId` / `userId` 都是 Long + `@JsonFormat(shape=STRING)`,前端用字符串接收防精度丢失。
- `reporterOpenid` 已脱敏(前 4 + `***` + 后 4
- 列表本身已按 `reportCount DESC, create_time DESC` 排序,前端不要重排。
---
## 不在本次范围(与前端无关)
- 站内信通知作者(`hide` / `warnAuthor` 后端 TODO— 需独立后端工单
- Phase 2D-B 跨服务统一复审队列 — 已评估优先级低,不做
切换 tab 时:
- TRAVELER/USER_NICKNAME/USER_AVATAR tab 保留现有页面的 列定义/操作按钮(approve/reject)不动。
- REVIEW tab 是**完全独立的列定义 + 操作按钮**(因为 VO 字段完全不同)。
- 顶部筛选区 "建议 / 场景 / 关键词" 在 REVIEW tab 时:
- "建议" 字段 → 复用为 `reportStatus` (NORMAL / PENDING_REVIEW / HIDDEN)
- "场景" 字段 → REVIEW tab 隐藏(评价举报无 scene 概念)
- "关键词" 字段 → 走后端 `keyword` 参数,模糊评价内容/作者昵称
---
## 验收
1. 「内容安全 → 评价举报处理」菜单可见,有权限控制
2. 列表能加载,各 status 切换正常
3. 隐藏/恢复/忽略/警告 4 个操作按钮调通,操作完列表自动刷新
4. `reasonStats` 字典 label 翻译正确
5. 测试服 `reviewId=2048001001001001005` 已经有 1 条 SPAM 举报数据,前端接入后能直接看到
1. 「内容安全 → 人工复审队列」页面顶部 tab 出现 "评价举报",权限正常
2. 默认 tab 仍为出行人姓名(不影响现有用户习惯)
3. 切到 "评价举报" tab,列表能加载,字段渲染对齐上方表格
4. `reasonStats` 字典 label 翻译正确,中文显示 "广告/营销" "辱骂/人身攻击" 等
5. 操作按钮按 `reportStatus` 显示且功能调通,操作完列表自动刷新
6. 展开行显示 `reporters[]`,每条"忽略本条"按钮调 `report/{reportId}/ignore`
7. 测试服 `reviewId=2048001001001001005` 已有 1 条 SPAM 举报数据,接入后能直接看到
---
## 不在本次范围
- 站内信通知作者(`warnAuthor` 后端 TODO)
- 后端跨服务统一聚合(Phase 2D-B,已评估优先级低)
- 评价举报独立的二级菜单(已废弃,统一走 tab)
---
## 工作量预估
前端 ~1.5 天(VO 适配 + tab 切换 + 操作按钮按状态路由 + 展开行 + 字典翻译)。**后端 0 改动**。