library-picturebook-activity/docs/design/super-admin/works-data-optimization.md
aid 418aa57ea8 Day4: 超管端设计优化 + UGC绘本创作社区P0实现
一、超管端设计优化
- 文档管理SOP体系建立,docs目录重组
- 统一用户管理:跨租户全局视角,合并用户管理+公众用户
- 活动监管全模块重构:全部活动(统计卡片+阶段筛选+SuperDetail详情页)、报名数据/作品数据/评审进度(两层合一扁平列表)、成果发布(去Tab+统计+隐藏写操作)
- 菜单精简:移除评委管理/评审规则/通知管理
- Bug修复:租户编辑丢失隐藏菜单、pageSize限制、主色统一

二、UGC绘本创作社区P0
- 数据库:10张新表(user_works/user_work_pages/work_tags等)
- 子女账号独立化:Child升级为独立User,家长切换+独立登录
- 用户作品库:CRUD+发布审核,8个API
- AI创作流程:提交→生成→保存到作品库,4个API
- 作品广场:首页改造为推荐流,标签+搜索+排序
- 内容审核(超管端):作品审核+作品管理+标签管理
- 活动联动:WorkSelector作品选择器
- 布局改造:底部5Tab(发现/创作/活动/作品库/我的)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 22:20:25 +08:00

188 lines
8.2 KiB
Markdown
Raw Permalink 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.

# 作品数据模块优化 — 设计方案
> 所属端:超管端
> 状态:已实现(待验收)
> 创建日期2026-03-27
> 最后更新2026-03-27
---
## 1. 背景与问题
超管端"作品数据"菜单目前是两层结构:第一层按活动维度展示活动列表(每行一个活动,显示作品提交数),点击"查看详情"进入第二层查看某活动的具体作品。问题模式与报名数据完全一致。
### 核心问题
| 问题 | 说明 |
|------|------|
| 第一层与全部活动列表重复 | Index.vue 是活动列表精简版,全部活动列表已有可点击的作品数列 |
| 超管写操作未隔离 | "分配评委"按钮、批量分配、分配抽屉均为机构管理端功能,超管不应有 |
| 缺少全局统计 | 没有作品总量、提交率等概览 |
| 无跨活动搜索 | 不能跨活动搜索某个作者的作品 |
| 第二层围绕"分配评委"设计 | 分配状态列、评委列、分配操作均为管理功能,超管只需查看 |
| 样式不一致 | 主色写死 `#1890ff` |
---
## 2. 现状分析
### 2.1 第一层作品管理works/Index.vue
- 个人参与/团队参与 Tab 切换
- 数据来源:`contestsApi.getList()` 按活动类型过滤
- 搜索:仅活动名称
- 表格列:序号/活动名称/主办机构/报名人数/已递交÷应递交/活动时间/操作
- 操作:查看详情(跳转 WorksDetail
### 2.2 第二层参赛作品works/WorksDetail.vue
- 数据来源:`worksApi.getList({ contestId })`
- 搜索:选手名/报名账号/作品编号/分配状态/递交时间/机构
- 表格列:序号/作品编号/报名账号/选手名/递交时间/分配状态/评委/操作
- 功能作品详情弹框WorkDetailModal、分配评委抽屉批量+单个)、行勾选
---
## 3. 设计方案
### 3.1 整体思路
与报名数据优化方案一致:**超管端将两层合并为一层**,扁平展示全平台所有作品记录,通过筛选条件切换活动。机构端保持原有两层结构不变。
超管端隐藏所有写操作(分配评委、批量分配),只保留查看能力。
### 3.2 页面结构
```
┌─ 标题卡片 ──────────────────────────────────────────────┐
│ 作品数据 │
└─────────────────────────────────────────────────────────┘
┌─ 统计卡片 ──────────────────────────────────────────────┐
│ [全部 120] [已提交 85] [评审中 30] [已评完 20] │
└─────────────────────────────────────────────────────────┘
┌─ 筛选栏 ────────────────────────────────────────────────┐
│ 所属活动:[下拉搜索] 作者/编号:[______] 作品状态:[下拉] │
│ 递交时间:[日期范围] [搜索] [重置] │
└─────────────────────────────────────────────────────────┘
┌─ 数据表格 ──────────────────────────────────────────────┐
│ 所属活动 | 作品编号 | 提交者 | 报名账号 | 主办机构 | │
│ | 作品状态 | 递交时间 | 操作 │
└─────────────────────────────────────────────────────────┘
```
### 3.3 统计卡片
4 张卡片,可点击切换筛选:
| 卡片 | 数据 | 颜色 | 说明 |
|------|------|------|------|
| 全部 | 作品总数 | 主色 | 全平台所有作品 |
| 已提交 | submitted 数量 | 蓝色 | 已提交待评审 |
| 评审中 | reviewing 数量 | 橙色 | 正在评审(已分配评委) |
| 已评完 | reviewed 数量 | 绿色 | 评审完成 |
数据来源:新增 `GET /api/contests/works/stats` 接口。
### 3.4 筛选栏
| 筛选项 | 组件 | 说明 |
|--------|------|------|
| 所属活动 | Select远程搜索 | 按活动名称搜索下拉,选择后按 contestId 过滤 |
| 作者/编号 | Input | 搜索作品编号、提交者姓名 |
| 作品状态 | Select | 已提交 / 评审中 / 已评完 |
| 递交时间 | RangePicker | 时间范围筛选 |
**联动逻辑**:从"全部活动"列表点击作品数字跳转时URL 带 `?contestId=xx`,页面初始化时自动设置"所属活动"筛选。
### 3.5 表格列
| 列 | 宽度 | 渲染方式 |
|----|------|----------|
| 所属活动 | 180 | 活动名称,可点击跳转活动详情 |
| 作品编号 | 130 | workNo可点击查看作品详情弹框 |
| 提交者 | 130 | 提交者昵称;团队参与时显示队伍名 |
| 报名账号 | 120 | username |
| 主办机构 | 120 | 提交者所属租户名 |
| 作品状态 | 90 | Tag已提交/ 评审中(橙)/ 已评完(绿) |
| 递交时间 | 150 | YYYY-MM-DD HH:mm |
| 操作 | 80 | 查看详情 |
超管操作列**只有"查看详情"**(打开 WorkDetailModal不提供分配评委。
### 3.6 详情交互
点击"查看详情"复用现有的 `WorkDetailModal` 组件,展示作品内容。
点击"作品编号"也打开同一个弹框(与现有行为一致)。
### 3.7 URL 参数支持
- `/super/contests/works` — 全部作品
- `/super/contests/works?contestId=3` — 筛选某活动的作品(从活动列表跳转)
---
## 4. 后端改动
### 4.1 新增 GET /api/contests/works/stats
超管调用时返回全平台作品统计:
```json
{
"total": 120,
"submitted": 85,
"reviewing": 30,
"reviewed": 20
}
```
支持可选的 `contestId` 参数。
判定逻辑:
- submittedstatus = 'submitted' 且无评分记录
- reviewingstatus = 'submitted' 或 'reviewing',且有评分记录但未全部评完
- reviewed所有分配的评委都已评分
简化方案:直接按数据库 status 字段统计submitted / reviewingreviewed 通过 `reviewedCount` 从活动列表接口已有的逻辑复用。
### 4.2 扩展 GET /api/contests/works
超管调用时:
- `contestId` 变为可选(不传时查全部活动的作品)
- 新增 `keyword` 参数:搜索作品编号、提交者姓名
- 新增 `status` 参数:按作品状态筛选
- 返回增加活动名称:`contest: { id, contestName }`
- 返回增加提交者租户:`registration.user.tenant.name`
普通租户调用时保持现有逻辑不变。
---
## 5. 前端改动
| 文件 | 操作 | 说明 |
|------|------|------|
| `frontend/src/api/contests.ts` | 修改 | 新增 WorksStats 类型和 works.getStats 接口,扩展 works 查询参数 |
| `frontend/src/views/contests/works/Index.vue` | 修改 | 超管端改为扁平作品列表(统计卡片+筛选+全平台表格+详情弹框),机构端保持不变 |
| `backend/src/contests/works/works.service.ts` | 修改 | 新增 getStats扩展 findAll 支持跨活动查询 |
| `backend/src/contests/works/works.controller.ts` | 修改 | 新增 stats 端点findAll 增加参数 |
---
## 6. 实施记录
### 2026-03-27 — 首次实现
**后端改动3 个文件):**
- `backend/src/contests/works/dto/query-work.dto.ts` — 新增 keyword 参数
- `backend/src/contests/works/works.service.ts` — 新增 getStats() 方法按状态统计findAll 增加 keyword 搜索(作品编号/提交者姓名/队伍名)
- `backend/src/contests/works/works.controller.ts` — 新增 GET /api/contests/works/stats 端点stats 在 :id 之前)
**前端改动2 个文件):**
- `frontend/src/api/contests.ts` — 扩展 QueryWorkParamskeyword新增 WorksStats 类型和 worksApi.getStats
- `frontend/src/views/contests/works/Index.vue` — 超管端改为扁平作品列表(统计卡片+筛选栏+全平台表格+WorkDetailModal机构端保持原有两层结构支持 URL 参数联动(?contestId=xx