# 作品广场功能设计 **日期**: 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` 触发登录逻辑。 - 登录后能看到作品广场入口。 - 作品卡片只展示效果和元信息,不出现查看代码入口。 - 详情页能展示作品效果。 - 有提示词链时显示创作过程入口,无提示词链时隐藏。 ## 后续扩展 - 学生点赞、收藏、评论。 - 奖项专题封面图。 - 老师在提交列表中直接授奖。 - 作品广场按班级、挑战、作者筛选。 - “本周精选”或“最近上榜”专区。