Files
web/docs/plans/2026-03-09-score-system-design.md
T
xuyueandClaude Opus 5.5 47d4679984 chore: 合并为单仓库,统一部署流程
- 根目录加入 docker-compose、Caddyfile、文档等原本不在仓库里的文件
- 前后端两份 GitHub Actions 合并成根目录的一个 deploy workflow:
  构建前端上传到 build/,再在服务器上 git pull 并重建容器

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 16:02:12 +08:00

114 lines
2.8 KiB
Markdown
Raw 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-09
**状态**: 已审批
## 背景
`Submission.score` 已有加权平均评分逻辑,`Profile.total_score` 字段存在但从未激活。分数计算出来后无任何展示或用途,需要设计让分数真正发挥作用的功能。
## 目标
- 学生:看到自己各题得分和在全班的排名
- 老师:快速了解哪些学生表现好,可按条件导出成绩
- 为未来解锁机制预留接口
## 方案选择
采用**方案 A(积分展示中心)**,在 `Challenge` 模型预留 `pass_score` 字段供日后解锁功能使用。
---
## 数据层
### Profile.recalculate_total_score()
替换现有 `update_total_score()` 的累加逻辑,改为从数据库重算:
```python
def recalculate_total_score(self):
from submission.models import Submission
from django.db.models import Max, Sum
# 每道挑战取最高分,再求和
total = (
Submission.objects
.filter(user=self.user, task__task_type='challenge')
.values('task_id')
.annotate(best=Max('score'))
.aggregate(total=Sum('best'))['total']
) or 0.0
self.total_score = total
self.save(update_fields=['total_score'])
```
### Rating post_save 信号
在现有 `update_submission_score_on_save` 之后,追加调用:
```python
instance.submission.user.profile.recalculate_total_score()
```
### Challenge.pass_score 字段
```python
pass_score = models.FloatField(null=True, blank=True, verbose_name="通过分数线")
```
默认 null,不影响现有功能,为解锁机制预留。
### 用户最佳分数定义
同一用户同一挑战取 `score` 最高的提交作为该题成绩。
---
## API 层
### 1. 排行榜
```
GET /api/account/leaderboard/
```
- 无需登录
- 返回所有用户按 `total_score` 降序,含排名、用户名、总分
### 2. 我的各题得分
```
GET /api/submission/my-scores/
```
- 需登录
- 返回当前用户每道挑战的最高分提交(challenge display、title、score、提交时间)
### 3. 成绩导出
```
GET /api/submission/export/?task_id=&username=
```
- 仅限 admin/super 角色
- 复用现有 `SubmissionFilter` 参数
- 返回 CSV 文件流,每行:用户名、挑战题号、挑战标题、最高分、提交时间
---
## 前端
| 改动点 | 说明 |
|--------|------|
| 挑战列表卡片 | 显示该用户最高得分(灰色小标,未评分不显示) |
| 新页面 `/leaderboard` | 排名/用户名/总分表格,所有人可访问,放主页导航 |
| 新页面 `/my-scores` | 我的各题得分列表,登录后可见,放主页用户区域 |
| Submissions 页面 | 现有筛选栏旁加"导出 CSV"按钮,触发浏览器下载 |
---
## 不在本期范围内
- 解锁机制(`pass_score` 字段已预留,后续单独设计)
- 班级/分组维度的统计
- 实时分数推送(WebSocket)