Commit Graph
112 Commits
Author SHA1 Message Date
xuyueandClaude Opus 5.5 c17f88cdbb feat(题单): 题单页重做——布置中的放最上面,详情顶上一条进度和奖章阶梯,没加入看得见题点不进;老师看全班、后台一屏编辑
Deploy / deploy (push) Canceled after 0s
- 列表:布置中的大卡片(做对几道、布置到哪天、再做对几道拿哪个奖章),其余小卡片,加入过的在前
- 详情:进度 + 奖章阶梯(下一个金圈「再做对 n 道」),题目两列写几点做对 / 交过几次;
  以前做对过的标「旧代码先藏着」;做完整条变绿,烟花只在做完那一刻放
- 老师多一个「全班情况」页签;题目页从链接直接进来没加入时,条上给「加入题单」
- 后台一屏编辑:布置一周 / 两周 / 四周 / 选日期,公开开关,粘贴多个题号一次加,拖动排序,奖章只剩两种条件
- 旧代码藏着的地方都说清楚是哪个题单、哪天之后能看
- 修掉列表卡片把选做题数说成「新加了 N 题」

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 22:01:39 +08:00
xuyueandClaude Opus 5.5 ba5b9ada0e feat(后台): 编程题出题页重做——左边写,右边是学生看到的样子;例子和测试数据的输出都由标准答案跑出来,改老题能直接看、改测试数据
- 例子就是测试数据里勾了「当例子」的几组,不再手抄输出;老题的例子不在测试数据里的补到最后
- 改了答案,输出变了的那组标黄、写清原来存的是什么;答案在某组上报错就挡住保存
- 没存标准答案的老题输出手写;太大的测试数据(>100 组或单文件 >32KB)只能导入 / 下载 zip
- 预制代码只写学生看得到的那段,前后藏起来的代码收进折叠;语法要求先拿标准答案自测
- 流程图两个互斥开关改成三选一;时间 / 内存限制能改了;草稿只给新建页
- 后端:读回测试点原文、语法要求自测、AI 想测试输入三个接口

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 20:07:34 +08:00
xuyueandClaude Opus 5.5 50660abf11 fix(题目列表): 切了几个知识点再按后退,地址回到了全部题目、页面还停在上一个知识点
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 16:49:09 +08:00
xuyueandClaude Opus 5.5 b121c2d0ee style(一言): 短句也要点一下弹出一模一样的全文——只有两行放不下的才弹,而且是鼠标移上去就弹
Deploy / deploy (push) Canceled after 0s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 15:27:27 +08:00
xuyueandClaude Opus 5.5 43ca3c34f1 style(一言): 句子只有一行,稍长一点就被截掉——改成最多两行,出处跟在第二行末尾靠右
Deploy / deploy (push) Canceled after 0s
短句一行时出处就在这一行右边;超过两行截断的是句子,出处始终露在外面。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 15:21:42 +08:00
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 1ba8928d41 feat(课堂看板): 「请假隐藏」不会用——改成班级旁一个「请假」按钮勾名单,请假的人变灰排到最后、今天有效
Deploy / deploy (push) Canceled after 0s
原来要先打开开关、名字变成带 × 的标签再点 ×,× 像删除;标完人从页面上消失,
恢复只能全部恢复。现在:

- 班级下拉旁「请假」按钮,标了人之后按钮直接写「请假 2 人:陈言、黄依露 · 修改」
- 弹框只列今天还没交过的人(请假的人一定在里面,刚上课时就是全班),勾上点确定
- 请假的人在表格里变灰排到最后,不算进进度和「还没交过」
- 交了题或举手就算来了,自动取消标记
- 有效期从两小时改成今天(请假一般是一整天),仍然只记在这台电脑上

顺带修掉:被标过的学生后来交了题,会从表格里整个消失、也不算进进度。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:38:25 +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
xuyueandClaude Opus 5.5 e3be3cd62c feat(统计): 「今日统计」「数据统计」合成一个「统计」,打开是一行一节课,这节课在最上面
Deploy / deploy (push) Canceled after 0s
老师的提交列表上只剩一个「统计」按钮;什么都没筛时按课列(选「今天」就是原来今日统计看的),
点一行进那节课(班、题、时段都带好),左上「← 全部」回来;只填题号时仍按班级汇总,和题目页
统计页签对得上。数字行加结果条,统计里的「课堂看板」按钮去掉,改成有班正在上课时才引过去。
学生仍是「今日统计」。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 09:23:54 +08:00
xuyueandClaude Opus 5.5 b19fc3c1d9 style(顶栏): 「课堂看板」夹在两个框中间像是没对齐,改成和「今日统计」一样的按钮
Deploy / deploy (push) Canceled after 0s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 01:20:01 +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 9b4c4a73f1 style(页脚): 版权和备案信息只在首页显示,其他页面不再占地方
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:31:17 +08:00
xuyueandClaude Opus 5.5 0bcc981e6f fix(提交列表/统计): 按方向键会顺手切掉「代码/流程图」、重判后右栏还是旧内容、没人交时统计说「全都做完了」
提交列表:
- 焦点在单选框、下拉框上时方向键不再一边切控件一边换条;跨页没回来前不再连跳一整页
- 重判、重新评分之后右栏重新拉,不再命中旧缓存;同一条新旧请求不再互相覆盖
- 从「我的提交」点顶栏「提交」、浏览器后退时,地址里没有的筛选回到默认
- 找回点用户名开个人主页;「只看他 / 只看这题」学生也能用;重判不用等代码拉下来
- 手机上老师也能重判、能按语言筛,流程图行有手机排版;学生界面带着的班级筛选显示成能点掉的标签
- mermaid 画不出来时先说中文、原始报错折起来

统计页:
- 没人交时说「这段时间没有人交」,不再说「全都做完了」;没填题号时各处统一叫「做对过题」
- 班级按 class_name 单独传;查询失败清掉旧数据并说清原因;标签跟着查出来的那一份走
- 「语法未过」的格子单独标「语」;正确率不算还在判的;截断提示说清哪些数字受影响
- 看板的请假隐藏只藏还没交过、没在举手的人,「恢复」只恢复这个班的
- 手机上筛选折行、上下排,不再挤出屏幕

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 8d1521f3b6 fix(统计): 统计弹框里几处数字对不上——完成度圆环把交了没对的也算成完成、请假隐藏的人还算在班级人数里
- 代码统计「班级完成度」圆环的已完成改成做完的人数,和上面「完成人数」一致
- 流程图统计「班级人数」减掉请假隐藏的,和完成度的分母一致
- 流程图统计打开就查、开着自动刷新(一天以内的时间段,30 秒一次),按钮带转圈
- 两个面板统计失败时在按钮旁说一句,不再无声无息停在旧数字上
- 没完成的人全被隐藏时不再显示「全都完成了」
- 流程图统计的「未完成」页签在全班做完后不再整个消失

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 11:14:34 +08:00
xuyueandClaude Opus 5.5 b76a35b5f2 feat(顶栏): 「提交」回到顶栏,顺序改为自学、题目、提交、题单、比赛、排名;公告只留在首页
Deploy / deploy (push) Canceled after 0s
「更多」下拉里只剩公告一项,一起去掉。公告基本是版本更新,一年五六条,
首页公告卡片有「全部」入口;手机菜单末尾仍留一项「公告」。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 10:05:33 +08:00
xuyueandClaude Opus 5.5 56ef4a999c feat(顶栏): 顶栏重排——点题号框就能看到这节课的题,老师的「N 人举手」挪上顶栏、不再一条条弹提示
Deploy / deploy (push) Canceled after 0s
- 导航改成 题目 / 题单 / 比赛 / 排名 / 自学 / 更多,当前页浅绿底块;提交、公告收进「更多」
- 题号框点开先列出这节课的题(做对没有、下一道),输入时按题号或标题筛,回车照旧直达;
  只在今天有课、不在题目页时出现
- 后台入口、暗色开关收进个人菜单;老师顶栏只留课堂看板
- 「N 人举手」前台、后台顶栏都有,放最末尾:没人等不显示,人数变多时闪一下;
  新求助的 toast 删掉(一节课能弹十几次,投屏时还弹在全班面前)
- 1280 以下题号框变窄、课堂看板只留图标、名字最宽 120;1024 以下允许折行

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:24:02 +08:00
xuyueandClaude Opus 5.5 5b43015be4 feat(统计): 提交统计里鼠标停在提交方块上就能看到这次交的代码,不用再点开新页面
Deploy / deploy (push) Canceled after 0s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 08:42:57 +08:00
xuyueandClaude Opus 5.5 22459cc212 feat(统计): 提交记录和流程图的统计弹框记住上次查的班级、题号、时间段,一小时内再打开自动带上
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 08:36:16 +08:00
xuyueandClaude Opus 5.5 ad2e4a34a2 style(顶栏): 机房 1280 宽的屏上顶栏不再折成两行——菜单改成纯文字,「后台」挪到右边
Deploy / deploy (push) Canceled after 0s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 08:26:43 +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 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 972dac3776 feat(题目): 答错时说清楚「输出了什么、应该是什么」,交对后给相似题,零碎几处对齐设计
Deploy / deploy (push) Canceled after 0s
- 答案错误里「格式和内容都不一样」那一类(样例上错的 44%):原来只说「对照一下,找找
  从哪里开始不一样」,现在是「你的程序输出了「E」,正确的是「D」。拿例子 2 的输入「60」,
  一行一行走一遍你的程序,看它走进了哪个分支」;多行的说第几行开始不一样
- 不在这节课里的题交对之后,结果页签里给「再练几道相似的」(原来只在题面最底下)
- 提交前自动排版改了代码的,结果上面提一句「编辑器里的代码也跟着变了,按 Ctrl+Z 能撤回」
- 交对之后「提交」降成描边按钮,「下一题」是唯一的主按钮
- 「重置代码」先确认(原来点一下就把代码和本地草稿一起清掉了)
- AI 提示的档位写「第 1 档 · 反问」,不写「L0 反问」
- 成就弹窗从右下角挪到右上角,别和结果、点评弹窗叠在一起

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 18:39:05 +08:00
xuyueandClaude Opus 5.5 11368813cc feat(流程图): 「写代码 / 画流程图」变成工具栏上的切换,AI 的评分和历次分数挪进结果页签,题单里也能画
- 流程图题的工具栏最左边是「写代码 / 画流程图」。原来流程图藏在语言下拉里,叫一个名叫
  Flowchart 的「语言」;画完一道题之后它还被记成语言偏好,下一道能画的题一打开就是画布
- 「交给 AI 点评」交完切到「结果」页签:评的时候写着「AI 正在看你的图」、画布照样能改;
  评完是分数、评语、改进建议、四项得分,顶上一排历次分数,点哪次看哪次。
  原来是提交按钮旁一个 1000px 的弹框,盖住画布,翻历次评分要一页一页点
- 画到 A / S:给「照着它写代码 →」,题单里 1.5 秒后回题单(和代码通过一样),
  课堂条当场标成做完;只在这一页上刚评完的那次才算,进页面读到以前的 A 不跳
- 「把这一版载回画布」只在画布和那一版不一样时出现;载回、进页面读回草稿后都缩放到装下整张图
- 题单入口能画流程图了(原来只有题库入口能画),题单里的代码草稿、流程图草稿各存一份,
  加入题单之前写的、画的不会一进题单就摆在编辑器里
- 手机上不给「画流程图」(节点库是拖放,手机上拖不动),题面里以前画好的那张照样看得到

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 18:19:16 +08:00
xuyueandClaude Opus 5.5 45505e8384 feat(题目): 工具栏加「运行例子」、结果页签加「自己输入」,去掉每个例子旁的「测试」和顶栏的分栏切换
Deploy / deploy (push) Canceled after 0s
- 工具栏「运行例子」:一键用全部例子试跑(Judge0,不算提交),结果进「结果 › 运行例子」,
  每个例子 ✓ / ✕,没对上的沿用答案错误那套中文说明;比赛里只摆输出、不给提示句
  (后端在比赛里故意不做例子对比);SQL 题不给
- 「结果」页签分成提交结果 / 运行例子 / 自己输入三段;「自己输入」顶替顶栏「自测」模式
  那个单独的编辑器
- 试跑出错(编译、运行、超时)给中文说明,Judge0 的英文原文折叠起来
- 例子比对两边都去掉末尾空白:原来只 trim 了运行输出,样例末尾带空格的题永远「不通过」
- 去掉题面里每个例子旁的「测试」、顶栏的「双栏 / 自测 / 题目」切换、EditorForTest 和
  screenMode store

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 14:35:58 +08:00
xuyueandClaude Opus 5.5 26e22e2542 refactor(题目): 提交状态挪进 store——手机上切页签、桌面切分栏,判题结果和点评不再丢
提交按钮那个组件(SubmitCode)在编辑器的工具栏里,而提交的全部状态和判完之后的
反应都长在它身上:手机上交完切到「描述」页签(Naive 的页签切走即卸载)、桌面切到
「题目 / 自测」模式,编辑器一卸载,判题结果、AI 提示、失败计数、通过后的点评、
题单里的回题单全丢了。

- oj/store/submission.ts:这次提交、判题跟踪、语法检查报错、结果面板开合、冷却、
  AI 提示(useSubmissionHint)
- SubmissionEffects.vue:挂在题目页这一层,失败计数、标成已解决、烟花、强制点评
  (连同「先点评再换题」的导航拦截)、回题单
- SubmitCode 只剩按钮和结果面板
- WebSocket 通道和判题监控的收尾改成 onScopeDispose:onUnmounted 在 store 里挂不上

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:36:35 +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 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 6bf8c6e1d9 style(前台): 列表页去掉表头 emoji、已结束的比赛改成灰色;比赛列表置顶进行中的比赛,排名页先看榜单
- 前台 53 处表头改成纯文字,删掉只剩这一个用途的 utils/renders.ts
- 「已结束」从红色改灰色(比赛列表 / 详情 / 后台 / 首页一起)
- 比赛列表第一页、无筛选时顶部列出进行中和即将开始的比赛
- 内容少的页面页脚贴底,不再悬在半屏
- 排名页两张柱状图挪到最后,第一屏是 Top100、本周进步榜和我的排名

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 20:13:29 +08:00
xuyueandClaude Opus 5.5 31aa5f6e74 feat(前台): 登录后首页改成个人首页;题目详情页的代码要求挪到最前面、样例并排显示
- 登录后 / 是个人首页:继续学习、最近提交、进行中/即将开始的比赛、公告;
  没登录仍是题目列表,题目列表另有 /problem 地址,顶栏「题目」指向它
- 继续学习按服务端留痕取最近打开的一课,不用 localStorage(机房一机多人)
- 题目详情:标题下加难度与时空限制,代码要求提到最前,小节收紧,
  样例输入/输出并排;工具栏「提交信息」「更多操作」改为「本题提交」「更多」

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 20:08:47 +08:00
xuyueandClaude Opus 5.5 d3823430f9 feat(后台): 侧栏分组带图标、可收起,加顶栏;所有后台页面统一页头
Deploy / deploy (push) Canceled after 0s
- 侧栏按 概览 / 教学内容 / 学情分析 / 站点管理 分组,去掉超管菜单里的重复项;
  菜单项的角色与路由守卫一一对应,没有题目权限的教师不再看到点了就被踢回首页的「题目」
- 顶栏:面包屑、回到前台、明暗切换、用户菜单(退出登录);窄屏侧栏自动收起
- 新增 PageHeader:标题 + 右侧主操作 + 下方筛选栏,编辑页带返回按钮
- 卡点分析 / 年度趋势 / 标签管理从题目列表的按钮挪进侧栏
- 首页改成统计卡片 + 班级排名卡片;设置页按钮移到卡片右上角
- 题目、比赛、题单、用户列表的「选项」列固定在右侧,不再被挤出屏幕

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 19:54:42 +08:00
xuyue d25b5dbe6d update
Deploy / deploy (push) Canceled after 0s
2026-09-27 19:36:28 +08:00
xuyueandClaude Opus 5.5 a698ebf585 perf(前端): 首页和题目详情页按需加载,首页 477 → 380KB、详情页 1031 → 682KB(传输量)
Deploy / deploy (push) Canceled after 0s
浏览器实测(preview 构建,生产规模数据):首页解压后 1428 → 1112KB,
未登录的题目详情页 3317 → 2021KB。后端接口 6–8ms,不是瓶颈,没动。

首页:
- 登录速报弹框挂在默认布局上,静态 import 了 md-editor-v3(~160KB JS + 76KB CSS),
  而 AI 分析只在登录后、提交满 3 次才有。MdPreview 改成异步组件,目标是本地包装
  LoginSummaryPreview.vue —— 直接 import("md-editor-v3") 会让 rolldown 把它和
  CodeMirror 语言包并成一个 467KB 的 chunk,排名页反而涨了 560KB(实测)
- 题目列表经 oj/api.ts 还带着 zod(~70KB):那个文件静态 import 了题目详情、提交详情
  两个 schema。改成和请求并行动态加载(单独的 oj/detailSchemas.ts,理由同
  profileSchema.ts),闸门仍是同步的 —— submissionDetailSchema 有 .catch(),
  不能改 contractDeferred

题目详情页:
- skulpt(~226KB gzip)原来一选 Python 就立刻预取。改成登录后才取(没登录交不了),
  且等 requestIdleCallback,不和题面、编辑器抢带宽
- StatisticsPanel 只有老师可见,却被 EditorToolbar 静态 import,每个学生都白拉一份
  chart.js(~68KB gzip)。改成异步组件,打开课堂统计时才加载
- SubmissionResult(带 DataTable)改成异步组件,第一次提交弹出结果面板时才加载

浏览器核过:首页正常;详情页未登录不再加载 skulpt / chart.js / DataTable;学生登录后
skulpt 空闲预取、提交后结果面板正常弹出;老师点课堂统计按需加载图表并正常渲染。
登录速报的 AI 分析与语法错误拦截路径本机没能触发,未在浏览器里核。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 16:34:32 +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 572a818d49 style: 按 Oxfmt 重新格式化
Deploy / deploy (push) Canceled after 0s
换格式化器带来的差异,只有 5 个文件:长联合类型改成每项一行、以 | 开头。
和上一个提交分开,方便 blame 时跳过(git blame --ignore-rev)。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 15:37:23 +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 83b9d23c68 perf(前端): zod 移出首屏包,首屏 JS 721KB → 594KB(gzip 237 → 199KB)
首屏包里带着整个 zod 运行时(~100KB),来路有三条,缺一条都挪不出去(逐条撤回实测过):

- 契约包没有 sideEffects: false,入口从桶里取任何一个值都会把所有 schema 模块带上。
  契约包里没有顶层副作用(核过),加上之后 rolldown 才能按导出摇树
- roles.ts 里的 USER_TYPE / toAdminType 是入口要的,同文件却定义了两个 z.enum。
  schema 挪到 admin.ts(唯一用处),roles.ts 文件头写明不许 import zod
- 启动就要调的 getWebsiteConfig / getAILoginSummary 在 oj/api.ts 里,而那个文件同步
  import 了题目详情、提交详情两个 schema。这两个函数挪到 shared/api.ts;那两道
  闸门保持同步 —— submissionDetailSchema 有 .catch(),放行原文和解析结果不等价
- /me 的契约闸门改成 contractDeferred:先放行原文,schema 按需加载后在后台核、只记
  日志。userProfileSchema 没有 default / transform,两者等价。动态 import 的目标是
  单独的 shared/profileSchema.ts —— 直接 import 契约桶会让 rolldown 重排共享 chunk,
  实测首屏反而涨到 1811KB

浏览器实跑核过:登录后 profile 正常加载、profileSchema 按需拉取、无控制台报错;
故意喂一份不符的数据,后台闸门照常打出 [契约] 分歧日志。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 15:23:31 +08:00
xuyueandClaude Opus 5.5 7a390323fe refactor(前端): 接口错误改成 ApiError 类,catch 不再写 any
拦截器原来 reject 一个裸对象 `{ error, data }`,没有类型也没有类型守卫,于是 46 处
`catch (err: any)` 直接读 `err.data` / `err.error` —— 代码 bug 抛出的 TypeError 也按
接口错误读,弹出来的是 undefined 或英文。

- utils/api.ts:reject 改成 `ApiError extends Error`,字段名沿用 error(错误码)/
  data(文案),存量读法语义不变;加 isApiError / errorCode / errorMessage。
  errorMessage 对非接口错误一律用 fallback,不把 TypeError 的英文甩给学生
- 46 处 catch 全部换掉 any(45 处接口错误 + pythonSyntaxCheck 里 Skulpt 的错误对象)
- 断网等没有响应体的情况,文案从英文 "Request failed" 换成「网络异常,请检查网络后重试」

浏览器实跑核过:登录密码错误仍显示「用户名或密码不正确」(错误码分支)、
接口错误 reject 出来是 ApiError、网络不通时拿到中文文案、非接口错误走 fallback。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 15:12:40 +08:00
xuyueandClaude Opus 5.5 c43da01ff2 refactor(AI): 四份 SSE 请求代码合成 streamAI + useAIStream
学情分析、班级分析、班级 PK、AI 提示四处原来各有一份几乎一样的 fetch + SSE 解析,
错误处理各漏各的:

- 裸 fetch 绕过了 axios 拦截器,未登录时只显示「AI 分析生成失败」而不弹登录框。
  拦截器里的全站错误处理抽成 handleGlobalApiError,两条路共用
- 班级分析、班级 PK 离开页面不中止流。useAIStream 在作用域销毁时自动 abort
- AI 提示换了一次提交不掐上一条,旧提示会写进新提交的面板

utils/stream.ts 的 streamAI 负责请求 + 解析 + 错误翻译;组件用 useAIStream
(waiting = 第一个字还没到,running = 流没结束);学情分析在 store 里直接用 streamAI。

浏览器实跑核过:学情分析逐字流出、provider 500 时显示后端的固定中文文案、
未登录调用弹出登录框。班级 PK / 班级分析卸载即中止这条没有在浏览器里点过
(本机库里没有班级数据),逻辑在 useAIStream 的 onScopeDispose。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 15:01:43 +08:00
xuyueandClaude Opus 5.5 ca0dbbf0c5 fix(登录态): 退出和换人登录时整页重载,不留上一个人的数据
signOut 只清了 profile 和 localStorage,AI 分析、学情小结等 store 还在内存里。
机房一台机器轮着用,下一个学生登进来就能看到上一个人的 AI 分析。

- 主动退出:router.replace 换成 window.location.replace("/")
- 被动下线(会话过期、别的标签页登出)仍然原地弹登录框,学生正在写的代码不丢;
  getMyProfile 记住本页最后一个登录的用户,登进来的换了人就整页重载

挨个 store 去 reset 迟早漏一个,重载一次最彻底。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 14:51:52 +08:00
xuyueandClaude Opus 5.5 fb240d4254 feat(限流): 登录、注册、比赛密码防爆破
三处原来都不限次数。学生初始密码弱,/classes/:name/usernames 又能公开列出整班
用户名,等于现成的撞库名单。

services/throttling.ts 加固定窗口计数(INCR + EXPIRE NX,锁定时长就是剩余 TTL),
何时计数由调用方决定:

- 登录按用户名 15 分钟 10 次失败,成功清零;按 IP 15 分钟 100 次失败,成功不清零
  (否则拿自己的号登一次就能重置)。机房一个班共用出口 IP,所以 IP 那道放得宽
- 注册按 IP 每小时 100 个成功注册
- 比赛密码按「人 × 比赛」10 分钟 10 次失败
- IP 取 X-Real-IP:api 端口不对外,Caddy 用 {client_ip} 覆盖写入,可信

前端登录、注册、比赛密码三处按新错误码给中文提示。

本机实跑核过:第 11 次错误登录被拦、成功清零(用户名大小写不敏感)、同 IP 换
100 个用户名被拦且别的 IP 不受影响、比赛密码第 11 次被拦。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 14:51:52 +08:00
xuyueandClaude Opus 5 8b4d8899f9 feat(判题机): 自建镜像升级工具链,语言收敛到 C / C++ / Python
Deploy / deploy (push) Canceled after 0s
上游 QingdaoU/JudgeServer 停更在 2024-04(registry 上的 latest 和 1.6.1 是同一份
镜像,编译器停在 gcc-13),没有新版可拉,所以自己重编。docker/judge/ 是只改工具链
的 Dockerfile 分叉,server/ 和 Judger/ 从上游固定 commit b28aa56 拉,一行没动。

镜像 oj2-judge-2(不在任何 registry 上:本机 build.sh --save → scp → docker load)
- gcc/g++ 13 → 14.2,Python 3.12 → 3.13.5,都是 trixie 默认
- Go / JDK / Node 整套删掉:前端的题目语言复选框从来只给 C / C++ / Python / SQL,
  12 万条提交里 Java 44 条、Golang 15、JavaScript 3,全是很早以前的
- 体积 1.1GB → 433MB;默认走清华源,构建 12 分钟 → 40 秒(--no-mirror 换回官方)
- deploy.sh 加一道自检:镜像不在本机就中止,并打印该跑的三条命令

C 的编译参数加三个 -Wno-error(implicit-function-declaration / int-conversion /
incompatible-pointer-types):gcc-14 把它们从 warning 提成了 error,而 -w 压不住。

语言值统一成 Python(迁移 0019 / 0020)
- 0019:Python3(104527 条提交)与 Python2(3 条)并成 Python,一并改掉 937 道题的
  languages、75 个 template 键、15 个 ast_rules 键、257 条 answers、1235 个用户的
  成就指标 _languages(languages_used 重算,总和 1928 → 1925,少的 3 个是同时用过
  两种 Python 的人)
- 0020:把 Java / JavaScript / Golang 从 84 道题的可选语言里摘掉 —— 不摘的话那些题
  的语言下拉还能选 Java,提交必 SYSTEM_ERROR
- 契约新增 normalizeLanguage() 别名表,判题侧一律走 judgeConfigFor():旧客户端
  localStorage 里的 Python3、迁移前排进队列的任务都还能判;协作的语言归一也走它,
  否则上线那一刻学生页面里的 Python3 会静默落到 C
- 回滚要连数据一起回,只滚代码会让所有 Python 提交变 SYSTEM_ERROR

实跑
- 判题冒烟 docker/judge/smoke.ts 13 条全过:三种语言、六种状态码、gcc 宽松度
- 拿备份里的真实代码逐文件比对新旧镜像的编译结果,0 差异:C 提交 1951 份
  (1725 过 / 226 CE)、C++ 882 份、Python 2000 份、20 篇 C 教程的 93 个代码块。
  不加那三个 -Wno-error 的话,C 有 26 份会从能过变成 CE
- 迁移在灌了 12.4 万行真实数据的一次性库里跑过:0 残留、没有题目被清空;
  dev 库用真正的执行器跑通
- check:ast 56 个 target 全过,前后端 typecheck 均 0

顺带记下一个升级之前就有的坑(现在随 Go 一起消失,写在 README 里):GOCACHE 指向
容器的 tmpfs,判题机重启后第一次 Go 提交是冷构建,Go 1.22 要 5.6 秒 CPU、超过 3 秒
的编译预算,于是重启后第一个交 Go 的学生必吃一次 CE,后面的人缓存热了又都正常。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 06:24:05 -06:00
xuyueandClaude Opus 5 a0ef204bd2 feat(提交): 采集编辑过程信号,落进 submission_trace
Deploy / deploy (push) Has been cancelled
AI 时代 OJ 设计的第 1 步:给「可信 AC」和学情分析攒数据,本身不判任何事。
- 契约:提交请求加可选的 trace(活跃时长、键入/粘贴/删除字符数、切后台次数等,
  只有计数、不含按键内容);写成 .optional().catch(undefined),坏了就当没带,
  不让附带数据把提交挡成 400
- 迁移 0016 建 submission_trace,与 submission 一对一、CASCADE;since_prev_ms
  由服务端在同一条 INSERT 里算(排掉自身),bigint —— 实测已有 44 天的间隔,int4 装不下
- 后端写 trace 失败只记日志,不影响提交
- 前端 oj/problem/utils/editTrace.ts 是模块单例(扩展对象不能过 Pinia 的响应式代理),
  只数带 userEvent 的事务:格式化回写 / 载入草稿 / 协作对方的改动天然排除;
  closeBrackets 越过右括号时是原样替换,按 no-op 跳过。比赛编辑器同样挂上
- 实跑:后端四种请求、前端浏览器里键入/粘贴/删除/setCode 回写/切后台/提交后清零,
  计数与预期逐项一致

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 05:46:55 -06:00
xuyueandClaude Sonnet 5 b5ba56ccd0 refactor(契约): 判题状态码收进契约唯一一份,并收紧 18 处 as any
- 状态码常量与 judgeStatusSchema 移到 packages/contract/src/judge-status.ts,
  后端 judge/status.ts 只再导出;前端 SubmissionStatus 枚举加编译期断言对齐契约
  (实测改坏一个码会当场类型检查失败)
- 类型逃逸 22 处降到 4 处:collab/handler、pagination、configUpdate、
  ExerciseManager、ProblemSubmission、pk.vue tooltip;剩下的是词云插件无类型、
  生成的 .d.ts、skulpt 和 TextEditor

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 04:40:30 -06:00
xuyueandClaude Opus 5 88b695d34f feat(课堂求助): 教师端接单直接跳题目页协作,删掉 CollabModal
Deploy / deploy (push) Has been cancelled
点求助列表里的一条 = 跳到 /problem/:id,在页面自带的那个编辑器里和学生同步。
原来是弹一个 CollabModal(弹框里再挂一个 CodeMirror + 一份只读题面):

- 按一下 Esc 弹框就关、协作跟着结束(`show` 的 setter 里 leave 是唯一的关闭语义,
  Esc 和点遮罩都走它),上课太容易误触;
- 弹框里那份题面不能跑测试、不能提交,老师还是得另开标签页对照。

现在结束协作只有两条明确的路:工具栏的「结束协作」按钮、离开这一页。教师端也少了
一个 CodeMirror 实例 —— setBinaryHandler 那个单例槽位只剩 SyncCodeEditor 一个使用者。

改造中撞出两个真问题,根因是同一个:`/problem/1002` → `/problem/1001` 是同一条路由
换 params,**组件被复用、不卸载**。

- 老师在别的题上接单跳过来,`@ready` 不会再触发,而 room 早在导航前就 open 了 ——
  老师停在一个空编辑器上干等。watch 的源从 room 一个变成 [room, roomIsHere] 两个。
- 反过来老师协作中切去别的题,onUnmounted 不触发 → 不发 leave,学生一直挂着
  「老师正在帮你」而老师的字一个也过不去。加 `bound` 标记区分「房间从我这儿挪走了」
  (补发 leave)和「房间在别处开起来了」(跟我无关,接单那一瞬间就是这种)。

`leave` 分两种语义(协议加 reason):

| 前端 | 求助记录 | 对面看到 |
|---|---|---|
| leave("done") 点「结束协作」 | 删除 | 老师已结束这次帮忙 |
| leave("left") 离开这道题的页面 | 教师走→退回排队;学生走→删除 | 老师暂时离开,已重新排队 |

"left" 复用的是老师掉线那条路(requeueAfterTeacherGone),两件事语义相同。原来两者
都按 done 处理 —— 老师点一下「提交信息」,学生就得重新举手,而他看到的是
「协作已结束」,会以为被处理完了。发起方收到的 reason 单独一份(self_left/done),
不然学生自己切走了却看到「老师已结束这次帮忙」。

其余为这套交互补的闸:

- 学生排队期间离开那道题 → 自动取消求助。那条求助说的是「我卡在这道题」,人走了
  就不成立;原来它会一直挂在队列里,老师接进来时学生的编辑器不在这道题上、根本
  不会绑,老师对着空编辑器敲字,两边都没提示。
- 协作中**教师的语言选择跟着 room.language 走**(写 codeStore,不只是改高亮),
  结束后还原。只改高亮的话老师会拿自己那档语言提交学生的代码(学生写 C、老师选的
  是 Python,当场 CE),工具栏还可能显示「提交流程图」。学生端一个字不动 ——
  服务端的 room_language 只发给教师,学生本地那份停在建房那一刻。
- 协作中不给「重置代码」:v-model 一写回就顺着 Yjs 同步过去,等于一键清空学生的作业。
- 协作中「提交信息」走新标签 —— 那是教师工具栏上唯一会跳路由的按钮。
- 接单时 resetScreenMode():分屏在「题目」「自测」两档时右侧编辑器根本没挂出来,
  停在同一道题上接单会落进一个没有编辑器的页面(跳到别的题时 detail.vue 的 init()
  会重置,同页不会)。
- 老师已在一个房间里时前端也拦住接下一单(服务端本来就拦),不拦的话前端已经跳到
  新题目上,等于把手上那场协作断掉。
- 文案:协议层那四条英文(Invalid problemId 之类)会被原样弹成 toast,改成中文;
  「请先退出当前协作」统一成「结束」;room_closed 的提示按 reason × 角色展开。

验证:本机起 api + web,三个账号两两组合实跑 —— 跨题接单 / 同页接单、双向编辑、
连按 Esc、结束协作、老师跳走后再接、学生跳走、学生排队中切题、学生协作中切语言、
分屏在「题目」档接单、协作中重复接单,以及上面每一句提示的实际文案。
api typecheck / check:routes、前端 type-check / build、fmt 全过。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 19:13:42 -06: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 3559ae4d6f chore(前端): 浏览器基线从 Chrome < 94 提到 105,删掉 mermaid@9 那套 fallback
机房只有部分电脑还是 Chrome 105,其余更新,按最低那档定基线。

- legacy 插件留着:vite 8 的默认 build.target 是 chrome111,比机房高。
  modernTargets 不写,用插件自带的 chrome>=105 基线,正好是这一档。
- polyfill 清单按 105 重新探测,63 → 50 项,仍然写死:自动探测要对每个产物
  跑 Babel 扫描,构建 3s → 12s。写死后产出的 polyfills chunk 与自动探测同尺寸。
- 删 mermaid-legacy(mermaid@9)、useMermaid 里按 UA 分叉的 v9 回调式 render、
  为它存在的 cytoscape UMD→ESM 别名 —— 105 直接用 mermaid 11。
- View Transitions 要 111,darkTransition 的降级分支保留,注释改成 105。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 07:43:21 -06:00
xuyueandClaude Opus 5 ed3b2cf6de feat(课堂求助): 教师协作弹框左侧直接显示题面
Deploy / deploy (push) Has been cancelled
原来弹框里只有编辑器,要看题得点「打开题面」另开标签页来回切。
现在左右分栏(可拖动):左侧只读题面(描述、输入输出、例子、提示,
SQL 题显示数据表与期望结果),右侧协作编辑器。

不复用 ProblemContent:它读写全局 problemStore,老师接单时正开着
的题目页会被换掉题面,测试按钮跑的也是老师自己的代码。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 08:48:40 -06:00