- 根目录加入 docker-compose、Caddyfile、文档等原本不在仓库里的文件 - 前后端两份 GitHub Actions 合并成根目录的一个 deploy workflow: 构建前端上传到 build/,再在服务器上 git pull 并重建容器 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
317 lines
8.0 KiB
Markdown
317 lines
8.0 KiB
Markdown
# 作品广场功能设计
|
|
|
|
**日期**: 2026-04-29
|
|
**状态**: 待审阅
|
|
|
|
## 背景
|
|
|
|
WebPreview 目前已有挑战、提交、评分、分区、人气统计和 AI 对话生成代码能力。现有机制偏向提交管理和评分结果展示,还缺少一个面向学生的优秀作品展示入口。作品广场用于把老师选出的优秀提交集中展示,让学生通过最终效果和创作提示词链学习同伴作品。
|
|
|
|
## 目标
|
|
|
|
- 学生登录后可以进入全站统一的作品广场,浏览获奖作品效果。
|
|
- 老师可以在后台维护奖项,并把提交作品授予一个或多个奖项。
|
|
- 每个奖项可以配置自己的作品排序方式。
|
|
- 作品广场只展示运行效果,不开放代码查看。
|
|
- 如果获奖作品有关联 AI 提示词链,所有登录学生都可以查看创作过程。
|
|
|
|
## 不在本期范围
|
|
|
|
- 学生提名、投票、评论、收藏。
|
|
- 对外公开展示。
|
|
- 作品代码公开。
|
|
- 复杂拖拽排序界面。初版用后台排序字段实现手动排序。
|
|
- 为奖项做单独的前端管理页。初版通过 Django 后台维护奖项和授奖关系。
|
|
|
|
## 核心规则
|
|
|
|
### 访问权限
|
|
|
|
- `/showcase` 需要登录。
|
|
- 普通学生只能浏览作品广场。
|
|
- 管理员和超级管理员可以通过 Django 后台维护奖项和授奖关系。
|
|
|
|
### 奖项
|
|
|
|
奖项由后台配置,不写死在前端。每个奖项包含:
|
|
|
|
- 名称,例如“最佳游戏”“最佳设计”。
|
|
- 简介,用于解释该专区的评选标准。
|
|
- 排序值,用于控制奖项专区在作品广场中的顺序。
|
|
- 是否启用。停用后不在前台展示。
|
|
- 作品排序方式。
|
|
|
|
作品排序方式初版支持:
|
|
|
|
- `manual`: 手动排序,按授奖关系上的排序值升序。
|
|
- `awarded_at`: 按授奖时间倒序。
|
|
- `score`: 按提交评分倒序。
|
|
- `view_count`: 按浏览量倒序。
|
|
|
|
默认排序方式为 `manual`。
|
|
|
|
### 授奖
|
|
|
|
- 一个提交作品可以获得多个奖项。
|
|
- 一个奖项可以包含多个提交作品。
|
|
- 同一个提交和同一个奖项只能建立一条授奖关系。
|
|
- 授奖关系包含手动排序值和授奖时间。
|
|
|
|
### 作品展示
|
|
|
|
作品广场按奖项分区展示,全站统一混合所有挑战作品,不按单个挑战拆分。
|
|
|
|
每个作品卡片展示:
|
|
|
|
- 作品运行效果。
|
|
- 作者用户名。
|
|
- 挑战标题。
|
|
- 奖项标签。
|
|
- 评分。
|
|
- 浏览量。
|
|
|
|
点击作品进入详情页,只展示运行效果和作品信息,不提供查看代码入口。
|
|
|
|
### 提示词链展示
|
|
|
|
如果提交作品关联到 `prompt.Message.submission`,作品详情展示“创作过程”区域。
|
|
|
|
展示内容:
|
|
|
|
- 每一轮学生提示词。
|
|
- 提示词来源:对话或手动。
|
|
- L1-L6 提示词层级,如果已分类。
|
|
- 每一轮 assistant 消息提取出的网页效果。
|
|
|
|
不展示内容:
|
|
|
|
- 系统提示词。
|
|
- 模型配置。
|
|
- API 信息。
|
|
- 代码文本。
|
|
|
|
创作过程默认折叠,学生点击后展开。
|
|
|
|
## 数据模型
|
|
|
|
### Award
|
|
|
|
建议放在 `submission/models.py`,因为奖项直接服务于提交作品展示。
|
|
|
|
字段:
|
|
|
|
- `name`: 奖项名称,唯一。
|
|
- `description`: 奖项简介,可为空。
|
|
- `sort_order`: 奖项排序值,默认 0。
|
|
- `is_active`: 是否启用,默认 true。
|
|
- `item_ordering`: 作品排序方式,默认 `manual`。
|
|
- `created` / `modified`: 复用 `TimeStampedModel`。
|
|
|
|
### SubmissionAward
|
|
|
|
授奖关系表。
|
|
|
|
字段:
|
|
|
|
- `submission`: 外键到 `Submission`。
|
|
- `award`: 外键到 `Award`。
|
|
- `sort_order`: 手动排序值,默认 0。
|
|
- `awarded_at`: 授奖时间。
|
|
- `created` / `modified`: 复用 `TimeStampedModel`。
|
|
|
|
约束:
|
|
|
|
- `(submission, award)` 唯一。
|
|
|
|
查询优化:
|
|
|
|
- `award`, `submission`, `sort_order`, `awarded_at` 建索引或通过外键索引满足主要查询。
|
|
- API 查询时 `select_related("submission", "submission__user", "submission__task", "award")`。
|
|
|
|
## 后端接口
|
|
|
|
### 作品广场列表
|
|
|
|
```
|
|
GET /api/submission/showcase/
|
|
```
|
|
|
|
登录后可访问。
|
|
|
|
返回启用奖项及其作品列表。无获奖作品的奖项默认不返回,避免前台出现空专区。
|
|
|
|
响应结构建议:
|
|
|
|
```json
|
|
[
|
|
{
|
|
"id": 1,
|
|
"name": "最佳设计",
|
|
"description": "视觉完成度高、布局清晰的作品",
|
|
"item_ordering": "manual",
|
|
"items": [
|
|
{
|
|
"submission_id": "uuid",
|
|
"username": "student01",
|
|
"task_title": "挑战标题",
|
|
"task_display": 3,
|
|
"score": 4.6,
|
|
"view_count": 28,
|
|
"html": "...",
|
|
"css": "...",
|
|
"js": "...",
|
|
"has_prompt_chain": true
|
|
}
|
|
]
|
|
}
|
|
]
|
|
```
|
|
|
|
### 作品详情
|
|
|
|
```
|
|
GET /api/submission/showcase/{submission_id}/
|
|
```
|
|
|
|
登录后可访问。仅允许访问已授奖的提交作品。
|
|
|
|
返回:
|
|
|
|
- 提交作品运行所需的 `html/css/js`。
|
|
- 作者、挑战、评分、浏览量。
|
|
- 当前作品获得的奖项列表。
|
|
- 是否存在提示词链。
|
|
|
|
### 作品提示词链
|
|
|
|
```
|
|
GET /api/submission/showcase/{submission_id}/prompt-chain/
|
|
```
|
|
|
|
登录后可访问。仅允许访问已授奖且有关联提示词链的提交作品。
|
|
|
|
后端通过 `Submission.source_message` 找到关联 assistant 消息,再回到同一 `Conversation`,按时间顺序构造用户提示词和 assistant 生成效果的轮次。
|
|
|
|
返回结构可复用 `ChainModal.vue` 当前使用的数据概念,但需要针对作品广场隐藏代码文本,只返回提示词内容、层级、来源和可预览的生成结果。
|
|
|
|
如果提交没有关联提示词链,作品详情接口返回 `has_prompt_chain: false`,该接口返回 404。
|
|
|
|
## 后台管理
|
|
|
|
在 Django admin 注册:
|
|
|
|
- `Award`
|
|
- `SubmissionAward`
|
|
|
|
`SubmissionAward` 后台字段:
|
|
|
|
- submission
|
|
- award
|
|
- sort_order
|
|
- awarded_at
|
|
|
|
列表页显示:
|
|
|
|
- 奖项名称
|
|
- 提交作者
|
|
- 挑战标题
|
|
- 评分
|
|
- 浏览量
|
|
- 手动排序值
|
|
- 授奖时间
|
|
|
|
筛选:
|
|
|
|
- award
|
|
- submission.task
|
|
- submission.user.classname
|
|
|
|
搜索:
|
|
|
|
- award.name
|
|
- submission.user.username
|
|
- submission.task.title
|
|
|
|
## 前端页面
|
|
|
|
### 路由
|
|
|
|
新增:
|
|
|
|
```
|
|
/showcase
|
|
```
|
|
|
|
路由 `meta.auth = true`。
|
|
|
|
### 入口
|
|
|
|
在主页/任务面板中新增“作品广场”入口,学生登录后可见。
|
|
|
|
### 作品广场页面
|
|
|
|
布局:
|
|
|
|
- 顶部标题和简短说明。
|
|
- 奖项专区纵向排列。
|
|
- 每个专区展示奖项名称、简介和作品网格。
|
|
- 每个作品卡片内嵌预览效果,显示作者、挑战、分数、浏览量。
|
|
|
|
空状态:
|
|
|
|
- 如果没有任何获奖作品,显示“暂无展示作品”。
|
|
|
|
### 作品详情页
|
|
|
|
新增或复用现有提交详情页,但需要隐藏代码查看能力。
|
|
|
|
内容:
|
|
|
|
- 作品运行效果。
|
|
- 作者、挑战、奖项、评分、浏览量。
|
|
- “创作过程”折叠区域。
|
|
|
|
创作过程:
|
|
|
|
- 有提示词链才显示入口。
|
|
- 默认折叠。
|
|
- 展开后显示提示词轮次和每轮生成效果。
|
|
|
|
## 安全与隐私
|
|
|
|
- 作品广场需要登录。
|
|
- 仅展示被授奖的提交。
|
|
- 不展示代码文本。
|
|
- 提示词链公开范围限定为登录用户。
|
|
- 提示词链只取用户消息和 assistant 生成效果,不展示系统提示词或接口配置。
|
|
|
|
## 测试计划
|
|
|
|
后端:
|
|
|
|
- 普通未登录用户访问作品广场接口返回 401/403。
|
|
- 登录用户可以查看已授奖作品。
|
|
- 未授奖提交不能通过详情接口访问。
|
|
- 一个提交可以获得多个奖项。
|
|
- 同一提交同一奖项不能重复授奖。
|
|
- 奖项停用后不在广场接口返回。
|
|
- 不同排序方式返回顺序正确。
|
|
- 有 `source_message` 的提交可以返回提示词链。
|
|
- 无 `source_message` 的提交在详情中返回 `has_prompt_chain: false`,请求提示词链接口返回 404。
|
|
|
|
前端:
|
|
|
|
- 未登录访问 `/showcase` 触发登录逻辑。
|
|
- 登录后能看到作品广场入口。
|
|
- 作品卡片只展示效果和元信息,不出现查看代码入口。
|
|
- 详情页能展示作品效果。
|
|
- 有提示词链时显示创作过程入口,无提示词链时隐藏。
|
|
|
|
## 后续扩展
|
|
|
|
- 学生点赞、收藏、评论。
|
|
- 奖项专题封面图。
|
|
- 老师在提交列表中直接授奖。
|
|
- 作品广场按班级、挑战、作者筛选。
|
|
- “本周精选”或“最近上榜”专区。
|