2026-03-27 22:20:25 +08:00
|
|
|
|
# 评审进度模块优化 — 设计方案
|
|
|
|
|
|
|
|
|
|
|
|
> 所属端:超管端
|
|
|
|
|
|
> 状态:已实现(待验收)
|
|
|
|
|
|
> 创建日期:2026-03-27
|
|
|
|
|
|
> 最后更新:2026-03-27
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 背景与问题
|
|
|
|
|
|
|
|
|
|
|
|
超管端"评审进度"菜单是两层结构,问题模式与报名数据、作品数据一致:第一层是活动列表精简版(冗余),第二层围绕管理操作设计(开始评审/结束评审/替换评委),不符合超管只读监管定位。
|
|
|
|
|
|
|
|
|
|
|
|
### 核心问题
|
|
|
|
|
|
|
|
|
|
|
|
| 问题 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| 第一层与全部活动列表重复 | 活动列表已有评审进度列(已评/总数),两个入口功能重叠 |
|
|
|
|
|
|
| 写操作未隔离 | "开始评审""结束评审""替换评委"均为机构管理端操作 |
|
|
|
|
|
|
| 评审状态筛选无效 | 第一层评审状态下拉选了不生效(前端计算但未传后端) |
|
|
|
|
|
|
| 缺少全局统计 | 没有全平台评审总进度概览 |
|
|
|
|
|
|
| 无跨活动维度 | 不能跨活动查看所有作品的评审状态 |
|
2026-04-16 16:21:25 +08:00
|
|
|
|
| ~~TODO~~ 部分已补 | 未提交作品列表仍为 TODO;**评委替换**已由 `POST /api/contests/reviews/replace-judge` 实现(分配 ID + 新评委用户 ID,未评分前可换) |
|
2026-03-27 22:20:25 +08:00
|
|
|
|
| 样式不一致 | 主色 `#1890ff` |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 现状分析
|
|
|
|
|
|
|
|
|
|
|
|
### 2.1 第一层:评审进度(reviews/Progress.vue)
|
|
|
|
|
|
|
|
|
|
|
|
- 个人参与/团队参与 Tab
|
|
|
|
|
|
- 数据来源:`contestsApi.getList()` 按活动类型过滤
|
|
|
|
|
|
- 搜索:活动名称 + 评审状态(无效)
|
|
|
|
|
|
- 表格列:序号/活动名称/主办机构/评审状态/已评审÷作品数/评审时间/操作
|
|
|
|
|
|
- 操作:查看详情 → 跳转 ProgressDetail
|
|
|
|
|
|
|
|
|
|
|
|
### 2.2 第二层:评审进度详情(reviews/ProgressDetail.vue)
|
|
|
|
|
|
|
|
|
|
|
|
- 数据来源:`worksApi.getList({ contestId })`
|
|
|
|
|
|
- 搜索:作品编号/报名账号/评审进度
|
|
|
|
|
|
- 表格列:序号/作品编号/报名账号/评委评分/评审进度/操作
|
|
|
|
|
|
- 操作按钮:开始评审、结束评审、未提交作品、导出
|
|
|
|
|
|
- 评审详情 Drawer:每个评委评分 + 替换评委
|
|
|
|
|
|
- 评委替换 Drawer:选择新评委
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 3. 设计方案
|
|
|
|
|
|
|
|
|
|
|
|
### 3.1 整体思路
|
|
|
|
|
|
|
|
|
|
|
|
与报名/作品模块一致:**超管端两层合一为扁平作品评审列表**,展示全平台所有作品的评审状态和评分情况。隐藏所有写操作,只保留查看能力。机构端保持不变。
|
|
|
|
|
|
|
|
|
|
|
|
### 3.2 页面结构
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
┌─ 标题卡片 ──────────────────────────────────────────────┐
|
|
|
|
|
|
│ 评审进度 │
|
|
|
|
|
|
└─────────────────────────────────────────────────────────┘
|
|
|
|
|
|
|
|
|
|
|
|
┌─ 统计卡片 ──────────────────────────────────────────────┐
|
|
|
|
|
|
│ [全部 120] [未评审 60] [评审中 40] [已完成 20] │
|
|
|
|
|
|
└─────────────────────────────────────────────────────────┘
|
|
|
|
|
|
|
|
|
|
|
|
┌─ 筛选栏 ────────────────────────────────────────────────┐
|
|
|
|
|
|
│ 所属活动:[下拉搜索] 作品/作者:[______] 评审进度:[下拉] │
|
|
|
|
|
|
│ [搜索] [重置] │
|
|
|
|
|
|
└─────────────────────────────────────────────────────────┘
|
|
|
|
|
|
|
|
|
|
|
|
┌─ 数据表格 ──────────────────────────────────────────────┐
|
|
|
|
|
|
│ 所属活动 | 作品编号 | 提交者 | 报名账号 | │
|
|
|
|
|
|
│ 评审进度 | 平均分 | 递交时间 | 操作 │
|
|
|
|
|
|
└─────────────────────────────────────────────────────────┘
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3.3 统计卡片
|
|
|
|
|
|
|
|
|
|
|
|
4 张卡片,可点击筛选:
|
|
|
|
|
|
|
|
|
|
|
|
| 卡片 | 数据 | 颜色 | 说明 |
|
|
|
|
|
|
|------|------|------|------|
|
|
|
|
|
|
| 全部 | 作品总数 | 主色 | validState=1 且 isLatest=true |
|
|
|
|
|
|
| 未评审 | 无评分记录的作品 | 灰色 | assignments 为空或 scores 为空 |
|
|
|
|
|
|
| 评审中 | 部分评委已评的作品 | 橙色 | 有评分但未全部评完 |
|
|
|
|
|
|
| 已完成 | 所有评委评完的作品 | 绿色 | reviewedCount >= totalJudgesCount |
|
|
|
|
|
|
|
|
|
|
|
|
复用作品 stats 接口数据即可(submitted≈未评审,reviewing≈评审中,reviewed≈已完成)。
|
|
|
|
|
|
|
|
|
|
|
|
### 3.4 筛选栏
|
|
|
|
|
|
|
|
|
|
|
|
| 筛选项 | 组件 | 说明 |
|
|
|
|
|
|
|--------|------|------|
|
|
|
|
|
|
| 所属活动 | Select(远程搜索) | 按活动名称搜索下拉 |
|
|
|
|
|
|
| 作品/作者 | Input | 搜索作品编号、提交者姓名 |
|
|
|
|
|
|
| 评审进度 | Select | 未评审 / 评审中 / 已完成 |
|
|
|
|
|
|
|
|
|
|
|
|
### 3.5 表格列
|
|
|
|
|
|
|
|
|
|
|
|
| 列 | 宽度 | 渲染方式 |
|
|
|
|
|
|
|----|------|----------|
|
|
|
|
|
|
| 所属活动 | 180 | 活动名称,可点击跳转活动详情 |
|
|
|
|
|
|
| 作品编号 | 130 | workNo,可点击查看作品详情 |
|
|
|
|
|
|
| 提交者 | 130 | 昵称 / 队伍名 |
|
|
|
|
|
|
| 报名账号 | 120 | username |
|
|
|
|
|
|
| 评审进度 | 100 | Tag:未评审(灰)/ 评审中 x/y(橙)/ 已完成(绿) |
|
|
|
|
|
|
| 平均分 | 80 | averageScore,已完成时显示分数,否则"-" |
|
|
|
|
|
|
| 递交时间 | 150 | YYYY-MM-DD HH:mm |
|
|
|
|
|
|
| 操作 | 100 | 查看详情 |
|
|
|
|
|
|
|
|
|
|
|
|
### 3.6 详情 Drawer
|
|
|
|
|
|
|
|
|
|
|
|
点击"查看详情"打开 Drawer,展示该作品的评审明细:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
作品信息
|
|
|
|
|
|
├── 所属活动 / 作品编号
|
|
|
|
|
|
├── 提交者 / 报名账号
|
|
|
|
|
|
├── 平均分 / 评审进度(x/y)
|
|
|
|
|
|
|
|
|
|
|
|
评委评分列表(表格)
|
|
|
|
|
|
├── 评委姓名 / 所属单位 / 评分 / 评分时间
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
不提供"替换评委"操作。
|
|
|
|
|
|
|
|
|
|
|
|
### 3.7 URL 参数支持
|
|
|
|
|
|
|
|
|
|
|
|
- `/super/contests/reviews/progress` — 全部作品评审进度
|
|
|
|
|
|
- `/super/contests/reviews/progress?contestId=3` — 从活动列表跳转,筛选某活动
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 4. 后端改动
|
|
|
|
|
|
|
2026-04-16 16:21:25 +08:00
|
|
|
|
- **评委替换**:`POST /api/contests/reviews/replace-judge`(权限 `review:assign`),请求体 `{ "assignmentId": long, "newJudgeId": long }`;该分配下若已有有效评分则不允许替换。
|
|
|
|
|
|
- 其余复用已有能力:
|
|
|
|
|
|
- 统计:复用 `GET /api/contests/works/stats`(已有 submitted/reviewing/reviewed)
|
|
|
|
|
|
- 列表:复用 `GET /api/contests/works`(已返回 reviewedCount/totalJudgesCount/averageScore/assignments)
|
|
|
|
|
|
- 评分详情:复用 `GET /api/contests/reviews/work/{workId}/scores`(已有)
|
2026-03-27 22:20:25 +08:00
|
|
|
|
|
|
|
|
|
|
### 4.1 评审进度前端过滤
|
|
|
|
|
|
|
|
|
|
|
|
"评审进度"筛选(未评审/评审中/已完成)基于返回数据的 `reviewedCount` 和 `totalJudgesCount` 在前端过滤,或后端 works 接口增加 `reviewProgress` 参数。
|
|
|
|
|
|
|
|
|
|
|
|
简化方案:前端直接利用作品 status 字段 + scores 数据判定,不改后端。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 5. 前端改动
|
|
|
|
|
|
|
|
|
|
|
|
| 文件 | 操作 | 说明 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| `frontend/src/views/contests/reviews/Progress.vue` | 修改 | 超管端改为扁平评审进度列表(统计卡片+筛选+表格+评分Drawer),机构端保持不变 |
|
|
|
|
|
|
|
|
|
|
|
|
后端无需改动,完全复用已有的 works 接口和 stats 接口。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 6. 实施记录
|
|
|
|
|
|
|
|
|
|
|
|
### 2026-03-27 — 首次实现
|
|
|
|
|
|
|
|
|
|
|
|
**后端改动:无**(完全复用 works 接口和 reviews/scores 接口)
|
|
|
|
|
|
|
|
|
|
|
|
**前端改动(1 个文件):**
|
|
|
|
|
|
- `frontend/src/views/contests/reviews/Progress.vue` — 完全重写:超管端为扁平评审进度列表(统计卡片复用 worksApi.getStats + 筛选栏 + 全平台作品表格含评审进度/平均分 + 评分详情 Drawer 含评委评分明细),机构端保持原有两层结构;评审进度筛选为前端过滤(基于 reviewedCount/totalJudgesCount);支持 URL 参数联动(?contestId=xx)
|