chore: 合并为单仓库,统一部署流程

- 根目录加入 docker-compose、Caddyfile、文档等原本不在仓库里的文件
- 前后端两份 GitHub Actions 合并成根目录的一个 deploy workflow:
  构建前端上传到 build/,再在服务器上 git pull 并重建容器

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-10-26 16:02:12 +08:00
1 parent 70983a12a5
commit 47d4679984
40 files changed
+13723 -34

No files matched your search

@@ -0,0 +1,229 @@
# 作品广场管理页设计
## 背景
作品广场当前已有学生浏览页 `/showcase` 和详情页 `/showcase/:id`。奖项与获奖作品的数据模型已经存在:
- `Award`:奖项名称、简介、启用状态、奖项排序、作品排序方式。
- `SubmissionAward`:提交作品与奖项的关联、手动排序值、授奖时间。
目前日常管理只能通过 Django Admin 完成,不适合老师在前端工作流中维护作品广场。
## 目标
在现有 Dashboard 中新增“作品广场”管理页,让管理员可以完成作品广场的日常维护:
- 创建、编辑、启停、删除奖项。
- 配置奖项在广场中的顺序。
- 配置奖项内作品排序方式。
- 通过复制来的 `submission_id` 查找提交作品,并把作品加入指定奖项。
- 查看、移除、调整奖项内作品。
## 非目标
- 不做公开代码查看。学生侧仍只展示运行效果和创作过程。
- 不做拖拽排序,第一版使用数字排序值。
- 不做批量导入或批量授奖。
- 不改变现有学生广场接口返回结构,避免影响 `/showcase`。
## 权限
管理页只对 `admin` 和 `super` 可见。
后端管理 API 使用 `admin_required` 限制。普通学生访问管理 API 返回 403,未登录用户返回登录态错误。
学生浏览页保持现状:登录用户可访问 `/showcase` 和 `/showcase/:id`。
## 前端入口
在 `Dashboard.vue` 侧栏新增菜单:
- 标签:`作品广场`
- 路由:`/dashboard/showcase`
- 可见角色:`admin`、`super`
新增页面文件:
- `client/src/pages/ShowcaseManage.vue`
## 页面结构
页面采用左右分栏,延续现有 Dashboard 的工具型界面风格。
左侧为奖项列表:
- 新建奖项按钮。
- 奖项名称。
- 启用状态。
- 展示排序值。
- 作品排序方式。
- 当前作品数量。
右侧为选中奖项详情:
- 奖项编辑表单:名称、简介、排序值、是否启用、作品排序方式。
- 保存按钮。
- 删除奖项按钮。
- 已授奖作品表格:作者、任务、分数、浏览量、手动排序值、授奖时间。
- 每行支持修改手动排序值和移除作品。
- 添加作品按钮:打开添加作品弹窗,粘贴 `submission_id` 后查找对应提交,确认无误后加入当前奖项。
当没有选中奖项时,右侧显示空状态。创建第一个奖项后自动选中。
## 后端 API
新增管理接口,放在 `submission/api.py`,路径位于现有 `/submission/showcase/` 下。
### 奖项管理
`GET /api/submission/showcase/manage/awards`
返回所有奖项,包括未启用和空奖项。每个奖项包含:
- `id`
- `name`
- `description`
- `sort_order`
- `is_active`
- `item_ordering`
- `item_count`
`POST /api/submission/showcase/manage/awards`
创建奖项。请求字段:
- `name`
- `description`
- `sort_order`
- `is_active`
- `item_ordering`
`PUT /api/submission/showcase/manage/awards/{award_id}`
更新奖项。字段同创建接口。
`DELETE /api/submission/showcase/manage/awards/{award_id}`
删除奖项。级联删除该奖项下的 `SubmissionAward` 关联,不删除提交作品本身。
### 作品查找
`GET /api/submission/showcase/manage/submissions/{submission_id}`
按提交 ID 查找一条提交,用于添加作品前确认。该接口只返回管理页需要的摘要,不返回 HTML/CSS/JS 源码。返回字段:
- `submission_id`
- `username`
- `task_title`
- `task_display`
- `score`
- `view_count`
- `has_prompt_chain`
提交不存在时返回 404。普通用户不能访问该接口。
### 奖项作品管理
`GET /api/submission/showcase/manage/awards/{award_id}/items`
返回该奖项下所有获奖作品。每项包含:
- `id`:`SubmissionAward.id`
- `submission_id`
- `username`
- `task_title`
- `task_display`
- `score`
- `view_count`
- `sort_order`
- `awarded_at`
- `has_prompt_chain`
排序规则沿用奖项的 `item_ordering`:
- `manual`:按 `SubmissionAward.sort_order`。
- `awarded_at`:按授奖时间倒序。
- `score`:按提交评分倒序。
- `view_count`:按浏览量倒序。
`POST /api/submission/showcase/manage/awards/{award_id}/items`
把提交作品加入奖项。请求字段:
- `submission_id`
- `sort_order`
如果同一作品已在该奖项中,返回现有关联,不重复创建。
`PUT /api/submission/showcase/manage/items/{item_id}`
更新获奖作品关联,目前只更新 `sort_order`。
`DELETE /api/submission/showcase/manage/items/{item_id}`
移除获奖作品关联,不删除提交作品。
## 前端 API 客户端
在 `client/src/api.ts` 中扩展 `Showcase`:
- `listManageAwards()`
- `createAward(payload)`
- `updateAward(id, payload)`
- `deleteAward(id)`
- `listAwardItems(id)`
- `findSubmissionForAward(submissionId)`
- `addAwardItem(id, payload)`
- `updateAwardItem(itemId, payload)`
- `deleteAwardItem(itemId)`
在 `client/src/utils/type.ts` 中新增管理页使用的类型:
- `AwardManageOut`
- `AwardManageIn`
- `AwardItemManageOut`
- `AwardItemIn`
- `AwardItemUpdateIn`
## 数据流
1. 进入 `/dashboard/showcase` 后加载奖项列表。
2. 自动选中第一个奖项,并加载该奖项作品。
3. 保存奖项后刷新奖项列表,并保留当前选中项。
4. 点击“添加作品”后打开弹窗,粘贴 `submission_id` 并查找提交。
5. 找到提交后展示提交者、任务、分数、浏览量和提示词状态。
6. 确认添加后刷新当前奖项作品,同时刷新左侧作品数量。
7. 修改作品手动排序值后刷新当前奖项作品。
## 错误处理
- 奖项名称重复时后端返回 400,前端显示错误消息。
- 奖项、作品关联或待添加提交不存在时返回 404,前端显示错误消息。
- 普通用户访问管理 API 返回 403。
- 网络或未知错误沿用现有 Axios 拦截器,同时管理页局部停止 loading 状态。
## 测试
后端测试覆盖:
- 普通用户不能访问作品广场管理接口。
- 管理员可以创建、编辑、启停奖项。
- 管理员可以通过 `submission_id` 查找提交作品摘要。
- 管理员可以给提交作品授奖。
- 重复授奖不会创建重复关联。
- 移除授奖后,学生广场列表不再返回该作品。
- 奖项停用后,学生广场列表不返回该奖项。
前端验证覆盖:
- Dashboard 中管理员能看到“作品广场”菜单,普通学生看不到。
- 奖项列表、奖项编辑、作品列表能正常加载。
- 粘贴 `submission_id` 查找作品并加入奖项后,已授奖作品列表更新。
- 删除或停用奖项后,学生 `/showcase` 表现符合预期。
## 后续增强
- 拖拽排序。
- 批量授奖。
- 按班级、挑战、作者筛选广场。
- 在提交列表中提供“加入作品广场”快捷入口。