Commit Graph
154 Commits
Author SHA1 Message Date
xuyueandClaude Opus 5.5 adea781b8e fix(一言): 句子下面多挂了个「· 游戏」「· 动画」的分类,看着啰嗦——不显示分类;本机不用再配 env 就能读到一言数据集
Deploy / deploy (push) Canceled after 0s
- 出处只写「—— 谁《出处》」。接口里的分类还在,只用来判断出处要不要加书名号
- HITOKOTO_DIRECTORY 默认值改成仓库旁边的 ../sentences-bundle,.env.example 里那几行撤掉。
  线上不受影响:镜像里 Dockerfile 写死了 /data/hitokoto

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 15:14:03 +08:00
xuyueandClaude Opus 5.5 c7a8e05385 feat(一言): 一言挤在角落里,出处被截成「来自 Structure and Interpretatio…」、不知道点一下能换——改成引号 + 句子 + 「—— 谁《出处》· 分类」+ 换一句按钮
设计稿「一言重设计」A 版:
- 句子一行,长句(数据集 p90 44 字、最长 255 字)截断,点句子弹出全文
- 出处写成「雷电将军《原神》· 游戏」:接口多下发 fromWho 和分类名,「佚名」「网络」这类充数的出处不写
- 「换一句」是个看得见的圆按钮,换的时候转一圈
- 契约 quoteSchema 从 string | Record 收成定形对象
- .env.example 说明本机怎么把 HITOKOTO_DIRECTORY 指到 sentences-bundle(不指就一直是内置的三句)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:19:55 +08:00
xuyueandClaude Opus 5.5 e852bf4498 fix(题目列表): 排序里多了个用不上的「按题号」,原来的最早创建、最多 / 最少提交、通过都没了——换回原来那一套
Deploy / deploy (push) Canceled after 0s
最新创建 / 最早创建 / 最多人做过 / 最少人做过 / 最多人做对 / 最少人做对。排序值和原来一样,
旧链接照样能用;「最多 / 最少」改成按人数,和最后一列「做对 / 做过」对得上。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 12:58:26 +08:00
xuyueandClaude Opus 5.5 97426f0895 fix(题目列表): 选了知识点后题目改成按题号排,和平时看惯的「最新的在前」不一样——默认一律按最新创建
排序下拉固定三项:最新创建(默认)/ 按题号 / 最多人做对。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 12:57:14 +08:00
xuyueandClaude Opus 5.5 ed7752afbb feat(题目列表): 学生自己挑题时只看得到一堆标签和提交数,不知道自己练到哪了——改成左栏知识点进度、顶上先说做到了什么
Deploy / deploy (push) Canceled after 0s
- 左栏是知识点(可切到主题)和自己的进度:做了一部分写 37/96 加进度条,全做对写「通关」,
  一道没做对过的只写题数,不再是一整列 0/108
- 顶上一行:做对几道 · 这周 +n(或连续几周都有做对)· 离哪个成就最近 ·「有 n 道差一点」
  (点开才列出来);新生引去「输出入门」;一言照旧在右边
- 每题最后一列是做对 / 做过的人数,代替提交数和按提交算的通过率(和题目页统计同一个口径)
- 「画流程图 / 语法要求 / 有参考图」挂在题目名后面,「全部类型」下拉单独筛这三类,
  不再混在排序里;题目页的「代码要求」统一叫「语法要求」
- 「只看没做完」开关(默认关)、「随便来一道」(当前知识点里先挑没做对的简单 / 中等题)
- 画流程图的题,流程图评到 A / S 在状态列也打勾,和题单、课堂条一个口径
- 老师看不到状态列和个人进度;出题者筛选保留

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 12:31:49 +08:00
xuyueandClaude Opus 5.5 af2ca31de5 fix(学生管理员): 260 班看板 23 人、数据统计只有 22 人,学生管理员还能看同学的作业代码——学生管理员一律按学生算
Deploy / deploy (push) Canceled after 0s
- 统计、题目页各班表、流程图统计的班级名单原来只认普通用户,改成和看板、排行榜一样的
  STUDENT_ROLES,学生管理员进名单、进分母
- 看别人的提交代码和流程图只给老师、超管和出题人;题单防抄对学生管理员也生效。
  原来「比赛进行中学生管理员不能看」那条特例随之去掉
- 题单的「用户进度」原来只给题单创建者,其余老师点开报「题单不存在」;改成所有老师都能看,
  和看板、统计对所有班开放一致。后台能改能删的接口仍只给创建者

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:00:11 +08:00
xuyueandClaude Opus 5.5 30f34f0e36 fix(老师权限): 老师在自己比赛里点题目「可见」没反应、看不到学生的智能分析入口等一批权限错位
- 比赛题的可见开关按题目作者判归属,从题库加进比赛的题作者是别人,老师点了 404 且无提示;
  改成和编辑、删除一样按比赛创建者判(canEdit)
- 学生主页「智能分析」和「查看指定用户」只给超管,后端本来就允许老师;改成老师可见
- 排名页班级详情的「AI 分析」学生也看得到,点了权限不足;只给老师显示
- 班级 PK 页解构 store 丢了响应性,资料晚到时老师看不到「AI 分析」
- 学生管理员能给任何人的流程图重新评分且不限流;别人的提交只有老师能重评,免限流也只给老师
- 超管没退登就过期的机房电脑上,下一个登录的老师继承演示模式、看不到后台和看板且关不掉;
  演示模式只对超管生效
- 老师的出题权限能设成「无权限」,设了比赛题目页全是权限不足;后端兜成「仅自己」,
  编辑框里老师不再给这个选项

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:00:04 +08:00
xuyue bde387e8bc fix
Deploy / deploy (push) Canceled after 0s
2026-10-08 12:29:35 +08:00
xuyueandClaude Opus 5.5 a8918b41b1 fix(题目统计): 「答案错误几乎都卡在第 1 个测试点」几乎每道题都弹,说了等于没说——答案错误最多时不再给提示
Deploy / deploy (push) Canceled after 0s
七成多的题错得最多的都是答案错误(快照 349 / 484),卡在第 1 个测试点过六成的也有 185 / 320 道,
两句提示对哪道题都一样。具体错在哪,每次提交的结果里已经有「题目里的例子 N 就错了」和三栏对照。
运行时错误、编译失败排第一时的提示保留。后端那条扫 info JSONB 数第 1 个点的查询一起删掉。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:21:00 +08:00
xuyueandClaude Opus 5.5 923f3efeca feat(统计): 没填班级的学生也能和班级一样看——班级下拉多一项「没填班级」,一起上的课能切出来、点进去看小方块;零散提交也能点了
- 班级筛选多一个取值 NO_CLASS("none"),统计、方块串、流程图、提交列表都认;只圈普通学生,
  老师管理员的号本来就不填班级,不挡的话试题的提交会算进去
- 切课时没填班级的号合在一起当一个班切(原来 class_name is null 直接排除,7 月 4 日那两节课看不到)
- 没填班级不是真班:不列「还没交」,课上只写几人不写几人之几
- 「另有零散提交」每一项可点,进那个班那一整天

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:18:06 +08:00
xuyueandClaude Opus 5.5 c2ef55b10b fix(提交): C 代码编译不过时,提交前的自动格式化把出错的几行并成一行,学生认不出自己的代码
Deploy / deploy (push) Canceled after 0s
clang-format 不认中文分号、缺了分号的语句,会把它和下一行并起来(int n; 和 scanf 成了
一行),报错的行号也对不上学生记得的位置。现在 C / C++ 格式化之前先套上题目模板、在
判题机上编一次,编不过就原样返回、不格式化,代码照常提交、照常判成编译错误。

api 容器里没有 gcc,判题机的编译器和参数本来就是判的标准,所以借它编。这一下不进判题
队列、不建提交记录;判题机连不上时照旧格式化。代价是每次交 C 多一次编译,零点几秒。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:29:37 +08:00
xuyueandClaude Opus 5.5 a18e129f4c feat(课堂): 布置这节课的题时可以选用什么语言做,学生用别的语言交对不算这份作业做完
class_lesson 加一列 language(0024,可空:以前布置的、按提交推断出来的课都不限语言)。
布置时有题不支持选的语言就整个拒掉并点名是哪几道;看板的格子、学生首页的做完状态、
提交列表「这节课」都只认这个语言的代码提交,流程图照旧算。看板多给 lastLanguage 当默认值。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 09:54:21 +08:00
xuyueandClaude Opus 5.5 921990285c feat(统计): 统计能按「一节课」列了——哪天哪个班几点到几点、来了几人、错得最多的题,选什么时间段都有
原来这些只有「今日统计」里有、而且只看今天;老师那一版并进统计之后,今日统计接口只留学生版。
课按「隔 30 分钟切开、一段里有一道题 5 人以上做过」切,26计算机0班 9 月 29 日是 14:04–15:38,
不再被课后两次零星提交拖成 14:04–18:42。统计接口多给一份结果分布,数字行画结果条用。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 09:23:53 +08:00
xuyueandClaude Opus 5.5 13051926cf fix(统计): 按班级列的时候零星一两个人补做的班排在最前,改成交过的人多的在前
Deploy / deploy (push) Canceled after 0s
题目页「各班做得怎样」和数据统计「按班级汇总」一起改,两边顺序一致。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:59:41 +08:00
xuyueandClaude Opus 5.5 50d8e072ac fix(题目页): 统计页签的各班表和数据统计「按班级汇总」对不上,改成同一个口径
原来题目页写 13/26(做对/交过)、数据统计写 13/58(做完/班级人数),列的班也不一样,
老师点过去看到的数「变了」。现在两边都是:只算学生,做完/班级人数、交了没对、没交、
正确率、最近一次,按最近一次排。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:56:35 +08:00
xuyueandClaude Opus 5.5 db493cebe4 fix(题目页): 统计页签的老师版回到讲这道题本身,各班只列一张表,不选班、不列人名
Deploy / deploy (push) Canceled after 0s
按人看谁没做对是提交页「数据统计」的活;表里点一个班就去那边看。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:50:01 +08:00
xuyueandClaude Opus 5.5 2fddf4a011 feat(提交列表): 今日统计重做——老师看今天哪几个班上了课、几点到几点、错得最多的题;学生版从简
- 老师:各班上课时段画在一条 7–20 点的时间轴上(点班级名去数据统计),有班正在上课时引去课堂看板
- 错得最多的题带班级、没过的原因、做对 x/y 人;底部一根全站结果条,语言只有一种时缩成一句
- 学生:你今天交了几次做对几道 + 今天大家都在做(按人数,带去做 / 接着做)
- 标题栏写「截至几点」、判题中几条;打开时把按钮上的数一起更新(原来只在进页面时拉一次)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:47:51 +08:00
xuyueandClaude Opus 5.5 99319fdcc5 feat(题目页): 「统计」页签重做——学生看难不难、几次做对、常错在哪,老师按班看谁没做对
- 全部按人算:原来的「通过数」是 AC 条数、「通过率」按提交算;击败用户、饼图、历年 AC 率去掉
- 错得最多的那种给一句该怎么办(都指向「运行例子」),自己交了 3 次以上还没对再多一张卡
- 老师选一个班:做对 / 交了没对(次数、最后结果)/ 没交;班里错得和全站不一样时点出来
- 题库入口工具栏的「课堂统计」并进这里(题单没有页签,按钮留着)
- 新接口 /problems/:id/stats(按内部题号,比赛题不再查到同号公开题),删掉 beat-count、yearly-ac

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:39:57 +08:00
xuyueandClaude Opus 5.5 91d9c9c6d7 feat(首页): 登录后不再弹「登录速报」,上次来做了什么、哪道还没做对放进首页,带「接着做」
Deploy / deploy (push) Canceled after 0s
- 新接口 /me/last-visit:上次登录到这次登录之间的题库提交,不调 AI(原来要同步等模型最长 60 秒弹框才出来)
- 班里今天在做时让位给班里卡,只在卡底留一句;班里那天就是上次来那天时两张卡合成一张
- 第一次登录说「欢迎来到判题狗」,隔了 30 天以上说「好久不见」
- 删掉弹框、store 和 /ai/login-summary

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:28:14 +08:00
xuyueandClaude Opus 5.5 5f9743efe0 feat(提交列表): 右栏名字旁多一个「只看这个班」,不在班级列表里的老班也能筛出来
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:00:38 +08:00
xuyueandClaude Opus 5.5 e37ad982c0 revert(提交列表): 撤掉班级下拉里补「近半年有提交的班」那一版,下拉回到只用系统设定的班级列表
改成在右栏名字旁加「只看这个班」过滤按钮(下一条)。
This reverts commit 61ec7d7.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:00:38 +08:00
xuyueandClaude Opus 5.5 61ec7d7f8e fix(提交列表): 不在班级列表里的班(毕业、换届摘掉的老班)在班级下拉里选不到,筛不出它的提交
Deploy / deploy (push) Canceled after 0s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:31:50 +08:00
xuyueandClaude Opus 5.5 923516ad36 fix(课堂看板): 这节课整班在画流程图时,点格子、点名字进到的是一片空的代码提交列表
Deploy / deploy (push) Canceled after 0s
看板格子的次数原来是代码和流程图加在一起的,链接却总是去代码那边;名字链接看的「今天交过」
还把比赛提交算了进去。现在格子分开给代码 / 流程图次数、学生分开给今天交过代码 / 画过流程图,
只画了流程图的跳到提交列表的「流程图」那边。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 19:02:33 +08:00
xuyueandClaude Opus 5.5 52bf2d6111 feat(提交列表): 题号填错一道时顶上提示「没有这道题」;← → 也能翻上一条下一条
Deploy / deploy (push) Canceled after 0s
- 列表接口回带查不到的题号(公开列表只认公开题,比赛列表只认本场的题),
  一次填好几道时打错的那道原来被悄悄忽略
- 方向键恢复成四个都能翻(9 月加的时候就是这样,老师已经用惯了)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 18:58:31 +08:00
xuyueandClaude Opus 5.5 26c8d65e89 fix(判题/统计): 老师重判一次题目提交数就多一;统计选 231 班会把 2311、2312 班也算进来
- 重判带上原来的结果,落库只做差量:提交数不变、旧结果那一格减一新结果加一,
  通过数按新旧结果调整(原来重判当新提交记账,连点三次就多三)。重判时一起清掉 info,
  判题中那几秒不再按旧结果显示「通过 2/3」
- 三个统计接口加 className,按 class_name 精确匹配(原来拼 ks231 做包含匹配)
- 流程图统计查几道题时要每道都拿到 A/S 才算完成;「每人最好的一次」截断时有标记,
  题号上限 20 道和代码统计一致;流程图列表支持按整名匹配用户
- 删掉统计弹框走后没人用的展开行明细接口,以及每次都白算的「语法未过题数」「最近一次错在哪」

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 18:52:58 +08:00
xuyueandClaude Opus 5.5 f09da88ff7 feat(统计): 统计接口补上每人每道题的每一次提交、流程图每人最好的一次,流程图也能一次查几道题
- 新增 GET /submissions/statistics/grid:范围内每个学生的每次提交(只含普通学生,最多 5000 条),
  没选班级时附带各班花名册人数,统计页按「人 × 题」画方块串、按班级汇总
- /flowcharts/statistics 题号可以一次填几道,多返回 people(每人分数最高的那张)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 18:28:27 +08:00
xuyueandClaude Opus 5.5 ea480d5e0c feat(提交列表): 老师也能重新判题;列表能按班级、一次按几道题筛,还带「通过几个测试点」
- 重新判题从只放超管改成老师及以上:前端一直给老师亮着按钮,点了只会「权限不足」
- /submissions、/flowcharts 加 className(user.class_name 精确匹配),题号可以一次填几道
- 列表每行带 caseSummary,口径和详情一致,在库里数完只回两个数
- 新增 GET /classroom/lesson:提交列表「这节课」按钮用,班级和题的取法同课堂看板

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 11:08:49 +08:00
xuyueandClaude Opus 5.5 eb32676de4 feat(题目): 「运行例子」「自己输入」改用和提交同一台判题机——例子上跑出什么样,提交在这几个例子上就是什么样
Deploy / deploy (push) Canceled after 0s
原来试运行走另一台 Judge0:C 是 GCC 9、编译参数也不一样,Python 的语法错误回来的是运行错误,
没有题目的时间内存限制和代码模板,例子上的结果常和提交对不上。现在走本站判题机
(POST /trial-runs),同一套编译命令、这道题的限制和模板,对不对也由判题机比。

- 不落库、不算提交、不进判题队列:api 进程里自己排队,全站同时 TRIAL_CONCURRENCY 批
  (服务器 2、机房 4),每人最多两批,排满或等超过 30 秒就请学生过一会儿再点
- 死循环不停打印时判题机回包会很大,超过 16MB 就掐断,告诉学生输出太多、停不下来
- Python 语法错误用和提交一样的说明:第几行、中文标点标红、一键换成英文
- 运行时错误和提交用同一个解析,说清楚第几行、为什么(下标越界、int() 转换失败、段错误……);
  比赛里照旧只给按结果码的那一句
- 语法没过、服务没跑成时,标题不再说「N 个例子没对上」
- 后台「生成测试点」一并迁过来,编译警告不会再写进 .out;Judge0 的地址和调用全部删掉

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 08:09:44 +08:00
xuyueandClaude Opus 5.5 e7b95d211d fix(题目): 修掉题目页重构审查查出的问题——提交途中换题会把结果算到新题上、运行例子把对的菱形判错、点评完「下一题」不跳等
题目页重构之后按「功能对照 / 状态 / 结果页 / 布局与后端」四路审查了一遍,查出的问题一起修:

提交与换题
- 提交、画流程图途中换题:A 题格式化好的代码会盖掉 B 的草稿,A 判对了把 B 标成已解决、
  弹 B 的点评、题单里跳回题单。现在每个请求回来先核对题目,轮询和推送回来的也核对提交编号
- 画着流程图换到不能画的题,语言退到题目的第一门、还被记成偏好;现在回到学生习惯的那门
- 强制点评评完点「继续 / 下一题」,学生之前在看「题目」页签的话会停在原题
- 离开题目页之后判题、流程图的 WebSocket 一直连着,现在闲 15 分钟断开

运行例子
- 输出开头的空格被削掉,打印菱形这类题对的代码也显示「没对上」
- C 的编译警告拼进了「你的输出」(后台生成测试点也会写进 .out)
- Python 的语法错误(中文标点)被说成「下标有没有越界、除数是不是 0」
- 比赛里仍然把空格画成「·」、把不同的地方标红

入口与协作
- 比赛里不给「课堂统计」、不绑协作:房间和统计都按题号找,比赛题号和公开题撞号
- 「看他交过什么」按整名匹配,不再混进学号相近的同学
- 协作中点上下文条、相似题、下一题开新标签,协作不断
- 题单入口给管理员的「⋯」里留「本题提交」

结果与题面
- 「去自己输入拿 51 这些数试试」取到了题面 HTML 里的颜色值;「题目原话」露出 &quot;
- 流程图 A 级的学生标题下还写着「还没交过」
- 「我的提交」上方补回「答案错误 × 3」这样的计数
- 流程图历次评分能点开看那一版的图;读分数失败不再说「还没交过流程图」;手机上能看流程图点评
- 「结果」页签有新结果没看时加粗上色,看过就恢复
- 空画布拖进第一个节点画布会跳一下;画布底下空着一条
- 比赛没开始写成「已结束」、倒计时超过一个月算错;分隔条拖到头工具栏被挤坏;题单里的题目页有备案页脚
- 流程图历次分数只读需要的几列(一个学生一道题 23 次提交:96 kB → 2 kB)
- 比赛密码、比赛没开始等几条学生看得到的英文报错换成中文

设计文档照实际做法更新了第 5.5、5.6、6、8、9、10、11 节。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 00:07:16 +08:00
xuyueandClaude Opus 5.5 ee66cef367 feat(课堂): 只画了流程图的学生也算来上过课、做完了题——推断这节课的题、班上几人做完、最近来了几次都认流程图
原来课堂那边只有「我的状态」和看板格子认流程图 A/S,其余统计只数代码提交:
全班画流程图的那节课推断不出题,课堂条和看板都是空的;只画了图的学生在看板上
「最近来了 0 次」。现在代码提交和流程图提交合成一张表来数,口径统一:
流程图 A/S 算做完,交过流程图(含评分中、评失败)算做过。

- 推断这节课的题、「班上 M 人做完」、最近几节课是哪几天
- 看板「最近来了几次」、最后提交时间、各题尝试次数
- 看板没选班时猜正在上课的班
- 班级对比、个人资料的通过数不在这次范围,仍然只数代码

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 00:06:54 +08:00
xuyueandClaude Opus 5.5 83b6b7a81a fix(题目): 修掉代码审查查出的几处问题——流程图拿到的徽章不弹、点评弹窗读失败时关不掉等
- 流程图画到 A / S 拿到的题单徽章、成就原来不弹:流程图那条 WebSocket 只认评分完成 / 失败,
  成就消息被丢掉了,要等下次换路由拉 pending 才出来
- 强制点评弹窗读不出点评、或者一直交不上时,「下一题 / 继续」按钮也给出来:原来弹窗关不掉,
  只能按浏览器后退;拦下换题时就记上「继续」,按钮文字不会写错
- 「放回编辑器」走正常的换语言路子(画流程图时切回代码编辑器、读那门语言的草稿);
  这道题已经不收的语言(0020 摘掉的 Java / JS / Go)置灰,只能复制
- 举着手时刚交对、1.5 秒内点下一题:原来「确定要换题吗」要问两遍(点评完再问一次),
  现在同意过的那个地址不再问
- 课堂看板上评分中、评失败的流程图不再算「尝试过」,和学生的课堂条一个口径;
  新加的流程图查询和其他查询并行,不再多等一轮数据库
- 课堂条的数据只认最后发出的那次请求:进页面那次后到的话会把刚做完的那道盖回「没做」
- 「A / S 算做完」收进契约,前后端只留一份;协作中老师的判断统一用 useTeacherCollab;
  几处放错位置、说法过时的注释

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 19:35:07 +08:00
xuyueandClaude Opus 5.5 b4afcbd47f chore(流程图): 注明 flowchart/current、history 两个接口为什么还留着、什么时候可以删
Deploy / deploy (push) Canceled after 0s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 18:50:05 +08:00
xuyueandClaude Opus 5.5 b5d2f1589e feat(课堂看板): 流程图画到 A / S 在老师的看板上也算做完,只画了图的学生不再显示「没开始」
和学生首页的课堂条同一个口径:格子的状态、做对的时间、尝试次数都把流程图提交算进去;
「最后一次提交」也算上今天画的图。有的题这节课整个班都在画流程图,原来看板上是满屏「没开始」

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 18:42:53 +08:00
xuyueandClaude Opus 5.5 0c2ff68e9b feat(协作): 老师协作时右栏顶上一条协作条,结果页签先摆学生最近一次交的,抽屉变成「他的提交」
- 协作条:「正在帮 谁 · 语言 · 看他交过什么 ↗ · 结束协作」,从工具栏里挪出来,一眼看得出
  编辑器里是学生的代码。「看他交过什么」带上学生用户名、开新标签(原来只带题号,还得再筛一遍)
- 老师接单后「结果」页签原来是空的:现在摆学生在这道题上最近一次交的结果,可刷新;
  不给 AI 提示(那是按登录的人自己的失败次数解锁的)
- 抽屉「我的提交」在协作中变成「他的提交」,列的是学生的提交,只能复制、不能放回编辑器
  (放回去会经协作通道直接盖掉学生正在写的代码),也不显示老师自己的排名
- 学生排队求助中、或者老师正在帮他时换题:先确认一句。换题会断开协作 / 撤掉举手,
  原来一点「下一题」就把正在帮他的老师踢出去了
- 求助按钮文案:「举手求助」→「已举手 · 前面 2 人」→「某某 老师在帮你」
- 提交列表加 exactUsername=1:用户名精确匹配。原来只有「包含」,ks24a1 会把 ks24a10 的提交
  也捞进来

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 18:28:53 +08:00
xuyueandClaude Opus 5.5 3fe3caa944 feat(流程图): 流程图画到 A / S 算这道题做完——题单进度、课堂条都认;加入题单之前画的图先藏起来
Deploy / deploy (push) Canceled after 0s
- 流程图评到 A 或 S,记进所有已加入、且包含这道题的题单(和判题那一路同一个口径,不看从哪个
  入口交的),徽章和题单类成就照样推送。原来题单进度只在判代码时记,流程图作业在题单里永远是
  「没做」。流程图提交的 id 进不了 problemset_submission(外键指向代码提交表),所以只写
  progress_detail —— 解锁旧提交的那道闸看的也是它
- 课堂条(/me/class-activity)的 myStatus:流程图 A / S 也算 accepted,评完的非 A/S 算 tried
- 题单防抄闸门补到流程图上:加入题单之前画的图,对本人藏起来(列表 showLink、详情 404、
  current / history 不数它),规则和代码提交同一份(problemSetJoinTimes 挪进 services/problemset)。
  原来加入之前画到 A 的那张图点一下就能载回画布、交上去就是 A
- 新增 GET /problems/:id/flowchart/scores:一次给出自己评完的每一次的分数和等级,外加被藏起来
  的次数(原来 history 一次只给一条,看分数走势得一页一页翻)
- 「A/S 算过关」和按分数定等级收进 flowchart/grade.ts;判题那边的记账 + 通知抽成
  recordSolvedAndNotify,两条路共用

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 17:56:35 +08:00
xuyueandClaude Opus 5.5 a7f6ebaf49 feat(激励): 知识点地图——每个知识点做对几道、在哪一档、再做几道升级,首页一句话提示本周进步
Deploy / deploy (push) Canceled after 0s
现有 38 个成就全是累计量(通过几题、提交几次、连续几天),起步的人人都有、往上的够不着,
而且没有一个在说「你学会了什么」。连续打卡在这里结构上做不到:2025 秋学生最长连续交题
天数的中位数是 1 天,连续 7 天的只有 3 人。

- GET /me/knowledge:题数 ≥10 的知识点标签(10 个),每个给做对几道、档位、周一时的档位、
  下一档门槛;四档 入门 1 / 会了 3 / 熟练 题数 40%(≤10)/ 精通 75%(≤20)。
  回测 2025 秋:中位数学生一学期升 5 档;「入门」一档是给只做对一两道的 71 人加的
- 同班 ≥30% 点亮过的知识点才会出现在「还没碰过」里,免得 Python 班看到「C 语言」
- 个人主页加「我的知识点」,只在看自己时显示;首页一句话:本周升级 > 离下一档最近的 >
  去点亮一个班里在学的,点了去按知识点筛的题目列表

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 23:17:43 +08:00
xuyueandClaude Opus 5.5 a6bf845e06 feat(课堂看板): 标出最近几节课经常没交的学生,求助的学生置顶,点一下打开求助列表
Deploy / deploy (push) Canceled after 0s
2025 秋至少上过 5 节课的学生里,12.5% 七成以上的课一道都没交,37% 的学生贡献了
一半以上的「没交」;当堂那份「今天还没交过」把偶尔没来的和一直不动手的排在同一行。

- 看板接口给每个学生加 recentAttended:最近几节课(最多 5 节、不含今天、45 天内;
  一节课 = 同班同日 ≥5 人做同一题)里交过几节,另给 recentLessons
- 「今天还没交过」拆成「经常没交」(≥3 节可比且最多交过 1 节)和其他;表格加一列
  「最近 N 节」;只给老师看,投影模式不出现
- 求助读老师端常驻 WebSocket 的 collabStore.requests(不改后端):求助的学生置顶,
  状态显示「举手了 / 老师在帮」,点一下打开求助列表;求助提示不论布没布置题都显示

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 22:47:24 +08:00
xuyueandClaude Opus 5.5 80106eaa04 feat(课堂): 老师的课堂看板——布置这节课的题、看全班谁还没开始谁卡住了,布置的题直接出现在学生首页
2025 秋平均每节课有 14 个平时在用的学生一道都没交(三分之一),交了 3 次以上还没过的
平均不到 1 个;而老师原来只能一道题一道题打开统计弹窗看。

- 新表 class_lesson(迁移 0023,仅建表):一个班一天一行,存老师布置的 problem.id 与顺序;
  day 存东八区日历日文本,created_by CASCADE
- GET /classroom/board:这个班今天的题 × 全班学生(通过与否不限今天、今天交了几次、
  最后提交时间);不给班级时猜最近两小时提交人数最多的班,不记老师上次选的
- PUT /classroom/lesson:按展示题号布置,对不上的题号点名拒绝,空数组 = 清掉
- /me/class-activity 优先返回老师布置的题(source = teacher),否则照旧推断
- 前端 /classroom:没交过的名单置顶,按 没交过 → 卡住 → 在做 → 做完 排序,15 秒刷新;
  投影模式只显示每题完成人数、不出名字;用户菜单给老师加入口
- 学生首页:老师布置的标题写「今天老师布置的题」,没人交时不显示 0/0

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 22:37:59 +08:00
xuyueandClaude Opus 5.5 2a4405d2ea feat(题目): Python 语法错误改成中文说明,在编辑器里标出位置,中文标点可以一键换成英文
Deploy / deploy (push) Canceled after 0s
中职学生看不懂英文报错。原来提交前用浏览器里的 Skulpt 拦语法错误,只弹一句
「第 N 行存在语法错误」——Skulpt 九成报的是 bad input / bad token,没有列号。

- 提交前的语法检查挪到服务端:/code/format 先用 CPython 编译一遍(只编译不执行),
  api 镜像加 python3-minimal(3.13,与判题机同版本,+17MB),前端删掉 Skulpt
- 报错按规则表翻成中文(pythonError.ts),生产库 2695 条 Python 编译错误覆盖 99.7%;
  提交前拦下的和判题回来的编译错误共用同一张卡片
- 编辑器里标红出错行和 ^ 指的位置
- 中文标点(历史编译错误的 22%)一键换成英文,跳过字符串和注释、处理 f 字符串花括号;
  594 条里修好 593 条,经 tokenize 核对没有改到字符串内容;走编辑器事务,可 Ctrl+Z

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 21:47:01 +08:00
xuyueandClaude Opus 5.5 039992dc86 feat(前台): 顶栏可以输入题号直达;首页列出班里最近一次课一起做的题和自己的完成情况
Deploy / deploy (push) Canceled after 0s
课上老师报题号、全班去找,是 2025 秋七成非比赛提交的来路,界面上原本没有它的入口。

- 顶栏(桌面端)加题号框,首页「找题」同一套逻辑:题号对上直接进题,否则去列表搜
- 新接口 GET /me/class-activity:同班同一天 ≥5 人做过的题,取最近 7 天里最近的一天,
  附带我自己的状态与班里通过人数;首页据此显示「今天班里在做」卡片,没有就不占位

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 20:58:15 +08:00
xuyueandClaude Opus 5.5 d07459928d feat(标签): 题目列表的标签分成「知识点」「主题」两组,新建的标签在后台标出待归类
Deploy / deploy (push) Canceled after 0s
- 迁移 0022:problem_tag 加 category(knowledge / theme)和 category_confirmed;
  存量 25 个题材、题集类标签归主题,其余归知识点,全部记为已确认
- 前台题目列表按两组显示标签,组内按题目数从多到少
- 后台标签管理:每行切换分类;出题时新建的标签默认知识点、标「待归类」并排在最前,
  页头提示待归类数量,可点「确认」保留默认;加分类筛选
- 新接口 PUT /admin/problem-tags/:id/category,设置分类即视为确认

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 20:38:43 +08:00
xuyue d25b5dbe6d update
Deploy / deploy (push) Canceled after 0s
2026-09-27 19:36:28 +08:00
xuyueandClaude Opus 5.5 23844ae301 fix(班级筛选): 输入 ks251 会把 2511 班的学生也算进来
Deploy / deploy (push) Canceled after 0s
班级号 3~4 位并存,按用户名前缀/包含匹配时 ks251 会捞到 ks2510~ks2519。
新增 classPrefixCondition:ks + 3 位以上数字按具体班级匹配(后面不能再跟数字),
1~2 位仍是年级前缀。后台首页的用户排名、随机抽签,以及题单的学生进度筛选
(只填数字时补上 ks)都改用它。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 19:34:28 +08:00
xuyueandClaude Opus 5.5 9412ba3cf6 refactor(契约): 展示题号统一叫 problemDisplayId,题单 id 统一叫 problemSetId
Deploy / deploy (push) Canceled after 0s
前后端同时改,部署前开着的旧页面要刷新一次(题号列会是空的、提交筛选会失效)。

- 挂在非题目对象上的展示题号,原来叫 problem(字符串)或 displayId,统一成
  problemDisplayId:提交列表、流程图列表、统计的 lastFailure / items /
  今日最热题、站内信里的提交、后台题单的题目列表。别处的 problem 都是对象
  或数字 id,这几处是字符串,最容易看错
- 列表筛选的 query 参数 ?problemId= 实际传的是展示题号,改成
  ?problemDisplayId=(提交列表、流程图列表、三个统计接口)
- 契约里 problemsetId / problemSetId、problemset / problemSet 两种拼法并存,
  统一成 problemSetId / problemSet,和 ProblemSet* 类型名、problem-sets
  路径、前端路由参数一致。drizzle 的列键跟表名走,没动
- aiDetail.user(用户名字符串,而契约里别的 user 都是对象)→ username。
  ai_analysis.data 里存的历史快照仍是 user,没有代码读回它
- 后台题单题目表的列是按字符串键 'displayId' 取的,类型检查抓不到,一并改

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 16:08:31 +08:00
xuyueandClaude Opus 5.5 5ae830a7f9 refactor: 一批名不副实的命名改掉(只动一端,不碰契约)
后端:
- getUserByToken → authenticateToken:它会删会话、续 TTL、记在线,不是纯读
- todayStart → dayStart(instant):本来就接受任意时刻,不只是「今天」
- objectValue → asRecord,删掉 4 份一模一样的私有拷贝和 `as toObject` 别名
- 报错文案 "does not exists" / "Already be a public problem" 改通顺

前端:
- utils/types 里 Contest / User / Problem 三个别名删掉:Contest 原来指后台
  比赛、契约里同名的却是学生侧。现在 Contest = 学生侧、AdminContest = 后台,
  后台用户表单叫 AdminUserForm,题目详情直接用 ProblemDetail
- SubmissionInfo → ContestSubmissionInfo,免得和 submission.info 撞名
- utoa / atou → compressToBase64 / decompressFromBase64(实际是 zlib + base64),
  encode / decode → base64EncodeUtf8 / base64DecodeUtf8
- filterResult → toProblemRow、toProblemListItem → toAdminProblemRow,
  行字段 submission / rate → submissionCount / acRate
- 组件:Modal → AddFromLibraryModal、Form → EditorToolbar、
  ContestEditor → BasicEditor(题单也在用它)、rank 的 Index → RankMedal、
  Name → UserNameCell、Password → PasswordCell、ContestType → ContestAccessTag

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 16:08:21 +08:00
xuyueandClaude Opus 5.5 f8b04af4ea chore: 加 oxlint,现存 19 条 warning 清零
Deploy / deploy (push) Canceled after 0s
原来只有 Prettier,没有任何 lint。根目录加 `bun run lint`(oxlint,覆盖后端、前端、
契约,--deny-warnings:有一条就算失败),CLAUDE.md 常用检查里加上。

现存 19 条顺手清掉:
- 11 处未使用的 import / catch 参数 / 回调参数
- oj/store/problem.ts:`...problem.value?.languages` 展开可能是 undefined
  (外层 if 已经保证非空,去掉 ?.)
- admin/problem/detail.vue:`contestId = contestId` 自赋值,删掉
- judge/sql/engine.ts:注释里的 `/*x*/` 示例原来靠零宽空格防止提前闭合注释,
  改成 `*\/`
- 其余:多余的 !!、new Array(n)、展开里多余的 `|| {}`

两边类型检查、前端构建、后端单二进制编译都过。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 15:25:27 +08:00
xuyueandClaude Opus 5.5 e17da63fc6 fix(上传): 头像和题面插图按文件头认格式,不信扩展名
原来只看扩展名:改个后缀什么都能落盘,再由 /public/* 按扩展名配 content-type
发出去。线上 Caddy 有 nosniff 兜着,但不该把非图片存到盘上。

- services/image.ts:按 PNG / JPEG / GIF / BMP 的文件头识别,返回落盘用的扩展名 ——
  以内容为准,改名成 .png 的 JPEG 存成 .jpg,content-type 才对得上
- 头像上传、后台插图上传都走它;插图那边扩展名白名单保留当第一道快速筛
- serveUpload 自己也带 x-content-type-options: nosniff,不只靠 Caddy

实跑核过:真 PNG / GIF 正常;改名成 .png 的 JPEG 存成 .jpg;改名成 .png 的 HTML
两个入口都拒;/public/upload 回 image/png + nosniff。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 15:15:36 +08:00
xuyueandClaude Opus 5.5 6406794971 refactor(AI): 学情统计查询从 routes/ai.ts 挪到 services/learning-stats.ts
routes/ai.ts 1149 行里约六成是 buildSolved / buildDetail / buildDuration 这些查询
构造器,它们不碰 Context,只是查询。挪出去之后 route 文件剩 585 行,只管
「鉴权 → 取参 → 调统计 → 回包」和 AI 调用本身;targetUser / throttleAi 依赖
Context,留在 route 里。

纯搬移,函数体一行没改。实跑核过:同一个用户的 /ai/detail、/ai/duration(按月、
按周)、/ai/solved、/ai/heatmap 五个响应,改前改后逐字节一致。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 15:09:21 +08:00
xuyueandClaude Opus 5.5 925cecb389 refactor(题目): 新建 / 复制题目收成 validateProblem、insertProblem、copyProblem
admin/problem.ts 里四处 insert(schema.problem) 其实是两对重复:

- 新建公开题 / 新建比赛题:公共校验 + SQL 展示数据 + 插入 + 写标签,逐行一样,
  只差 contestId。编辑题目那条也抄了同一段校验。收成 validateProblem(校验 +
  展示数据)和 insertProblem(插入 + 标签,一个事务)。比赛题当初就是抄漏了
  sqlDisplay,现在三条路径只有一份
- 比赛题转公开 / 从公开题库拉进比赛:复制整行 + 统计清零 + 复制标签,收成 copyProblem

顺带 db/index.ts 加 DbOrTx 类型,四处 `tx as unknown as typeof db` 去掉。

唯一的行为差异:编辑题目时 SQL 展示数据的生成挪到了题号查重之前(和新建一致),
两项同时出错时报的是前一个。

实跑核过:新建公开题、编辑、重复题号 409、新建比赛题、比赛题转公开(不可见、
标签跟过去)、从公开题库拉进比赛(可见、标签跟过去),SQL 题测试点缺失时照样拦下。
测试数据已删。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 15:07:13 +08:00
xuyueandClaude Opus 5.5 f2ca34fd4b refactor(api): 请求体解析收成 readJson / parseBody
54 处 handler 都手写同一段:
  const parsed = X.safeParse(await c.req.json().catch(() => null))
  if (!parsed.success) return failure(c, 400, "invalid-request", ...)
漏写 .catch 就是一个畸形请求打出 500。

- http.ts 加 readJson(读 + 校验)和 parseBody(再加上 400)。parseBody 不给
  message 时回 zod 的第一条 issue —— 后台表单原来就是这么写的,fallback 文案
  「Invalid payload」/「参数错误」只在 issues 为空时才用得上,实际走不到
- 51 处换成 parseBody;另 3 处失败时带别的错误码或和路径参数一起判,换成 readJson
- 错误码、状态码、文案、判断顺序都不变

实跑核过:非 JSON 请求体回原来的固定文案,公告标题为空回 zod issue。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 15:04:19 +08:00