Commit Graph
9 Commits
Author SHA1 Message Date
xuyueandClaude Opus 5.5 cccf7a37be feat(成就): 多了 9 个好拿的档和「挑战成功」一条线,比赛里做的题也算,这学期八成学生多拿到成就
- 补档:做对 20 道、第一道中等题、交满 30 次、5 天交过题、一次就对 5 道、错 3 次后做对、一天做对 5 道;
  新线「挑战成功」1 次 / 5 次
- 比赛里的提交也计入成就(比赛其实是单班测验,2612 班整班在比赛里做题,原来一个成就都没有);
  参加过几场比赛改成判题时就更新,以前只在后台重扫时刷新
- 奖杯收藏家从 15 个提到 20 个
- 0044 迁移:按新口径从提交记录重数指标,给达标的人补发(已经拿到的不收回)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 16:52:00 +08:00
xuyueandClaude Opus 5.5 1b703d13ae style(专题): 「题单」改名「专题」,顶栏、列表、详情、后台、成就说法统一
Deploy / deploy (push) Canceled after 0s
只改界面文字和注释:网址 /problemset、接口、表名、字段名都不动,老链接照常能打开。
设计稿页名「题单重设计」和已执行的迁移文件保留原样。
线上 3 个成就(题单收藏家 / 入门 / 通关)已同步改名。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 00:12:18 +08:00
xuyueandClaude Opus 5.5 195069450f style(格式化): 改成单引号、一行最长 160,全仓重新格式化
Deploy / deploy (push) Canceled after 0s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 13:52:24 +08:00
xuyueandClaude Opus 5.5 c33b084788 fix(后台成就): 成就指标的名字改成大白话(「AC 题目数」→「做对的题数」这类)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:32:33 +08:00
xuyueandClaude Opus 5.5 85108df9d8 feat(成就): 下架三个拿不到的成就、理顺稀有度和图标;接口多给本班几人有和「本班」卡片
- 0032:下架六边形战士(判题机只剩 3 种语言)、坚持三天/一周(按天算基本拿不到);
  不撞南墙改白银、屡败屡战改黄金;百发百中换 💯、屡败屡战换 💪,不再和别的撞图标;
  代码行数只算做对的、空行不算,并按新口径重算所有人;已经拿到的一个不收回
- 奖杯收藏家只数上架的成就(判题结算、补发重算、0032 存量一起改)
- GET /achievements:每个成就带全站几人有、本班几人有;看自己时带「本班」(最近拿到、成就最多前五、自己第几);
  隐藏成就同一串拿到一档就整串亮出来;连续几周给「现在连着几周」而不是历史最长
- 删掉只有旧成就页在用的 /achievements/summary

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:26:37 +08:00
xuyueandClaude Opus 5.5 71670e609b feat(成就): 新增「最长连续新通过周数」指标,按课表的节奏算连续;修掉比赛成就重扫因孤儿提交失败
Deploy / deploy (push) Canceled after 0s
按天的连续成就对这里的学生基本拿不到:2025 秋最长连续交题天数的中位数是 1 天,
连续 7 天的只有 3 人。按周算,连续 2/4/8 周分别有约 73%/49%/8% 的学生做到过。

- 新指标 max_ac_week_streak:连续几个自然周(周一起、东八区)每周都至少新通过一道题
  (不含比赛)。判题结算时增量累计(比按天那段多一道判断:重判更早的提交不会把连续清零);
  后台建成就触发重扫时,先从提交记录全量补算(refreshAcWeekStreakForAll),同 contest_joined
- 老的「坚持三天」「坚持一周」不动:下架的成就连已获得的人也看不到
- 修:库里 28 个已不存在的用户留下了 935 条提交(其中 11 人有比赛提交),全量补算往
  user_stat 写时撞外键,整次失败——比赛类成就的重扫因此一直是失败的;两处都改为只算
  还在的用户。本地修好后重扫「初入赛场」补发了 3 人
- 本地验证:连续 2/4/8 周补发 1086/618/123 人,与独立 SQL 一致

线上要在后台手动建成就(指标选「最长连续新通过周数」),建的时候自动补发。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 08:27:25 +08:00
xuyueandClaude Opus 5 ed56a209ea chore(格式): Prettier 统一到全仓,后端和契约一次性格式化
Deploy / deploy (push) Has been cancelled
原来只有 `apps/web` 在 Prettier 下(配置在 `apps/web/.prettierrc.toml`、脚本在
web 的 package.json),后端和契约从来没格式化过 —— 手写在 100 列上下,`db/schema.ts`
还是 drizzle-kit pull 留下的 tab 缩进。两套口径分叉久了,跨端改一处就得记着「这边
什么风格」。

- 配置搬到根目录 `.prettierrc.toml`,内容不变(`semi=false`,其余全默认,
  printWidth 80 —— 和前端已有的格式一致,不另立一套宽度);
- 脚本统一成根目录 `bun run fmt`,覆盖 `apps/*/src`、`apps/web/tests` 和两个构建
  配置;web 自己那份 `fmt` 和重复的 prettier 依赖删掉;
- `.prettierignore` 挡掉两类不该碰的:drizzle-kit 生成的 `src/db/meta/` 结构快照
  (它是 db:generate 的比对输入,只该由 drizzle-kit 写)、unplugin 每次 dev 都会
  重写的 `auto-imports.d.ts` / `components.d.ts`;
- 全量跑了一遍。纯格式,无行为改动:api typecheck / check:routes / check:ast、
  前端 type-check 全过,起 api 打了接口确认正常。前端这 39 个文件的小改动是
  prettier 版本漂移(类型断言的换行口径变了),不是新配置带来的。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 08:27:34 -06:00
xuyueandClaude Opus 5 79bfd28b07 chore: 删掉 369 行没有任何调用方的代码
Deploy / deploy (push) Has been cancelled
## utils/functions.ts 砍掉一半(622 → 291 行)

- trickOrTreat():317 行、八种页面恶搞效果(中文乱码、页面翻转、去掉鼠标……),
  **全仓零调用**,占这个共享工具文件的一半;
- 文件末尾注释掉的 getChromeVersion / isLowVersion / protocol 六行。

## 其余没有调用方的导出

- services/achievement-metrics.ts 的 RARITIES / OPERATORS —— 和契约的
  achievementRaritySchema / achievementOperatorSchema 取值逐字相同,是没人用的第二份;
- collab/state.ts 的 hasRequest;以及 resetCollabState,它的注释写着「仅供进程退出或
  测试用」,而本仓库不写测试(项目约定),进程退出那条路径也没调过;
- contract/language.ts 的 JUDGE_LANGUAGES,注释说「前端用它排语言 tab」——前端并没有,
  它排 tab 用的是 constants.ts 里以 ProblemLanguage 为键的 SOURCES / LANGUAGE_SHOW_VALUE
  (那组映射的完整性 tsc 已经在管);
- web 的 useSimplePagination(usePagination 的一层空壳包装)和 updateProblemSetProgress。

扫描口径:三个包全部 .ts / .vue 里逐个导出符号数出现次数,只在定义处出现的算无引用
(.vue 模板里的引用也计入)。剩下 56 个仍无引用的全部是契约里 `z.infer` 派生的一行
类型(46 个请求类型 + 10 个领域类型)—— 它们是在用的 schema 的类型另一半,成体系的
1:1 镜像,删一部分只会让那个文件变得随意,所以不动。

## 留给你定的一件事

`updateProblemSetProgress` 删掉之后,后端 `PUT /problem-set-progress`(routes/problemset.ts:249)
就没有任何调用方了。题单进度实际是判完之后由 services/problemset.ts 的 recordSolvedProblem
在服务端记账的(schema.ts 里那条注释写明了),这个端点是一条客户端自报进度的平行路径。
没顺手删:删端点是行为变化,而且不能排除有脚本在打它。

tsc、vue-tsc、vite build、单二进制编译、check:routes、check:ast 均通过。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012j1vgeDqay8wKCh8dPgPcH
2026-09-10 19:38:16 -06:00
xuyueandClaude Opus 5 7e1a782747 feat(阶段4): 用户管理 + 成就管理;补上 rescan 与 contest_joined
GET/POST/DELETE   admin/users            (DELETE 走 body 传 ids)
  GET/PUT           admin/users/:id
  POST              admin/users/:id/reset-password
  GET               admin/achievement-metrics
  GET/POST          admin/achievements
  GET/PUT/DELETE    admin/achievements/:id

顺带补了新后端缺失的两块(不补的话成就后台建出来的东西是坏的):

1. **rescanAchievement**:旧后端 `rescan_achievement` 的对应实现。判定平时只在判题
   结算时发生,后台新建成就或调低阈值不会自动补发,必须显式扫一遍。补发标记
   backfilled=true —— 前端据此只显示「已获得」不显示日期,否则一次补发会给几百人
   盖同一个时间戳,把「最近获得」板块冲垮。
   触发判据包含 metric 与 visible 的变化,不只看 operator/threshold:换维度、
   以及从下架改上架(草稿期已达标的人)这两种都会漏。
2. **contest_joined 指标整个漏掉了**。旧 METRIC_REGISTRY 有 18 个指标,新后端只算
   17 个,配在这个指标上的成就永远解锁不了。已补上计算,并把注册表抽成
   services/achievement-metrics.ts 作为单一事实源 —— 后台下拉框和参数校验都读它,
   避免「下拉框里选得到但没人算」这种组合。

用户管理的几处要点:

- className 解析位数不对**直接报错不猜**。猜错会把 class_name 存歪,而剥前缀显示
  姓名、班级下拉、统计页都依赖它准确。
- problem_permission 按 admin_type 归一(超管恒 All、普通用户恒 None),否则把超管
  降级成普通用户后他还留着 All。
- 改用户名要同步 submission.username 这个冗余列,否则历史提交查不到。
- openApi 已开着就不重置 appkey,否则每次保存用户都把对方的 key 换掉。
- **删除用户不复刻 Django 的应用层级联硬删**。用户是被引用最广的一张表,改成让
  数据库外键拦下来:撞外键说明还有历史数据,应当禁用而不是删除,返回 409 并说明。

实测:学生 403;导入 2 人 / 重复 409 / 班级号位数报错文案正确;改名+降权后
permission 归一为 None、重名 409;重置密码 6 位无 0;删自己 400;
成就指标 18 项、新建后补发 unlockCount=2、野指标与野稀有度均 400。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 07:27:36 -06:00