library-picturebook-activity/docs/design/judge-portal/review-tasks.md

102 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 评委端:评审任务
> 所属端:评委端(`tenant_id` 对应评委租户,如 `code=judge`
> 菜单与定位见 [菜单配置说明](../menu-config.md) 中「评委端」章节:仅能查看**被分配**的活动与作品。
## 活动列表
**接口**`GET /contests/reviews/judge/contests`
**活动来源(并集)**
1. `t_biz_contest_judge``judge_id``valid_state=1` 的赛事(机构显式添加的评委);
2. `t_biz_contest_work_judge_assignment` 中该评委出现过的 `contest_id`(含仅通过作品分配参与的隐式场景)。
**响应字段(与前端 `activities/Review.vue` 对齐)**
| 字段 | 说明 |
|------|------|
| `contestId` | 活动 ID |
| `contestName` | 活动名称 |
| `contestState` / `status` | 活动状态 |
| `reviewStartTime` / `reviewEndTime` | 评审时间窗 |
| `totalAssigned` | 该评委在该活动下的分配记录总数 |
| `reviewed` | 其中 `status=completed` 的数量(已提交评分) |
| `pending` | `totalAssigned - reviewed`(待评审) |
## 活动下作品列表
**接口**`GET /contests/reviews/judge/contests/{contestId}/works`
**分配状态 `reviewStatus` 查询参数(与库表兼容)**
- 库中 `t_biz_contest_work_judge_assignment.status` 实际使用:`assigned`(已分配未评完)、`completed`(已评审)。
- 前端下拉「未评审」传 `pending` → 后端按 **`status != completed`** 筛选。
- 前端「已评审」传 `reviewed` → 后端按 **`status = completed`** 筛选。
**作品编号**`workNo` 为空时,前端可用作品 `workId` 展示兜底(如 `#123`)。
## 活动详情(含评审规则)
**接口**`GET /contests/reviews/judge/contests/{contestId}/detail`
**权限**:满足以下**任一**即可:
- 存在有效的 `t_biz_contest_judge` 关联;或
- 存在该 `contestId` + `judgeId` 的作品分配记录。
避免「列表能进、详情 403」与隐式评委场景不一致。
## 预设评语(跨活动同步)
与 [菜单配置说明](../menu-config.md) 中「预设评语」能力一致:评委维护常用评语模板,**不按活动筛选**;列表与评审弹窗「老师点评 → 选择评语」使用**同一查询**。
**列表**`GET /contests/preset-comments`
- 按当前登录用户的评委身份(`judge_id`)返回其全部有效预设评语。
- **不要**使用 query 参数 `contestId`(接口不提供按活动筛选)。
**创建**`POST /contests/preset-comments`
- 请求体中 `contestId` **可选**;不传或为 `null` 表示全局模板(库表 `t_biz_preset_comment.contest_id` 为空,所有活动评审可选用)。
- `content` 必填。
**其它**:详情/修改/删除/批量删除/增加使用次数等见 `PresetCommentController`Knife4j
## 标记作品违规(活动参赛作品)
**接口**`POST /contests/reviews/work/{workId}/violation`
**权限**`review:score`(与提交评分一致)
**请求体JSON**
| 字段 | 必填 | 说明 |
|------|------|------|
| `assignmentId` | 是 | 当前评委在该作品上的分配记录 ID`t_biz_contest_work_judge_assignment.id`),与打分接口一致 |
| `reason` | 否 | 违规说明,写入 `t_biz_contest_work.violation_reason` |
**行为**
-`t_biz_contest_work.status` 置为 `violation`,并写入 `violation_mark_time`、`violation_judge_id`(及可选 `violation_reason`)。
- 将该评委对应的分配记录 `status` 置为 `completed`,与「已处理该评审任务」一致,避免长期占用「待评审」。
- 若作品已是 `violation`,幂等返回成功。
**列表字段**`GET .../works` 响应中增加 `workStatus`(作品表 `status`),便于前端展示「违规」等状态;与分配维度上的 `status``assignment` 是否 completed区分。
**说明**:此为**活动赛事投稿作品**`t_biz_contest_work`)的违规标记,与 UGC 绘本广场超管审核(`/content-review/...`)不同。
**公众端**`GET /public/activities/{id}/my-registration` 返回最新参赛作品 `latestWorkStatus`、`violationReason` 等;若最新作品为 `violation`,参赛者在活动提交期内可重新从作品库提交(`submitRule=once` 时亦允许覆盖违规版本)。
---
## 与租户端「评审进度」的口径对齐
| 维度 | 租户机构端 `contests/reviews/progress`(活动列表行) | 评委端 `activities/review`(上表) |
|------|------------------------------------------------------|-------------------------------------|
| 数据来源 | `GET /contests` 列表项中的 `reviewedCount` / `totalWorksCount` | `GET /contests/reviews/judge/contests` |
| 含义 | `totalWorksCount`:该活动最新有效作品总数。`reviewedCount`**该活动下已分配评委且全部分配记录均为 `completed` 的作品数**(与分配表 `t_biz_contest_work_judge_assignment` 一致,与作品表 `accepted`/`awarded` 终态无关) | **评委维度**`reviewed`/`totalAssigned`/`pending` 为该评委在分配表上的任务数;与租户「整作品是否全部评委评完」为不同聚合粒度 |
| 作品列表/详情 | `GET /contests/works` 每条作品含 `reviewedCount`/`totalJudgesCount`(按该作品分配条数统计) | 评委在单活动下作品列表同样基于分配 `completed` |
说明:顶部「作品统计」卡片若仍按作品 `status` 汇总,可能与逐活动行「分配完成作品数」不完全同数,属汇总维度不同;列表/详情/评委任务以分配表为准。