xuyue and Claude Opus 5.5
179d5fa67d
feat(语法要求): 能要求「调用 print() 时必须用 sep 参数」,题目说要用 sep/end 的不再被绕过
...
Deploy / deploy (push) Canceled after 0s
原来只能数 print 调用几次,写成 print("1-2-3***4") + print() 也算达标。
新加 must_use_keyword(只有 Python),后台「关键字参数」一组里配函数名和参数名。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-27 22:16:44 +08:00
xuyue and Claude Opus 5.5
8427475337
chore(清理): 删掉并行试跑、搬库、Python3 别名、旧链接这些过渡期的兼容写法
...
Deploy / deploy (push) Canceled after 0s
- 部署:JUDGE_STATE_DIR 不再强制设;删掉搬库脚本和只为搬库存在的自检、提醒
- 语言:Python3 / Python2 别名表删掉,normalizeLanguage 改名 parseLanguage
- 旧链接:后台题单详情的跳转、用户列表 -last_login 的转换
- 旧页面:布置作业必须带 language(null = 没选);不再清旧版出题页草稿
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-26 14:15:04 +08:00
xuyue and Claude 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
xuyue and Claude Opus 5.5
647186e276
fix(后台): 出题页收起的那几栏只有中间一行字能点,教程列表的项目行只有小三角能点
...
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-26 13:45:53 +08:00
xuyue and Claude Opus 5.5
1a173f75d7
feat(挑战): 这节课做完了给「还能挑战」,挑战中编辑器顶上一条紫色的,老师看板上看得出谁在挑战
...
Deploy / deploy (push) Canceled after 0s
做完这节课(或题库里自己做对)之后列出还能挑战的题;去挑战后编辑器顶上写着要求,
没做到标出是哪几行,做到了写本班第几个、全站第几个。课堂看板做到的格子贴一枚紫色筹码、
在挑战的加一圈紫边,题卡片写挑战成功几人。出题页多一块「挑战」,能从做对的代码里找候选。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-26 08:52:50 +08:00
xuyue and Claude Opus 5.5
b0700d0bd9
fix(界面): 能点的文字平时就是绿色,不用再把鼠标移上去才看得出能点
...
Deploy / deploy (push) Canceled after 0s
首页「全部」、提交详情的用户名和题名、题目页「点开看全部」「有 N 道差一点」、
班级对抗的班级名、知识点、后台标题等 30 多处原来和正文同色,鼠标移上去才变色,
手机上根本没有「移上去」。现在一律主题绿,移上去加下划线;没设颜色的文字按钮补上
type="primary"。排名名字列、整行可点的列表、后台 quaternary 次要按钮不动。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-23 10:39:49 +08:00
xuyue and Claude Opus 5.5
f7c4af0c01
fix(年度趋势): 刚学一个月的届不再拿去和学了一年多的往届比,两边都只算同样学了这么久时做的
...
Deploy / deploy (push) Canceled after 0s
以前往届那一侧把所有记录都算进去,25 级比 24 级显示 73% / 82%,
其实 24 级在这些题上近一半是学了半年以上才做的;同期比是 73% / 75%。
现在每个人以自己第一次交题为起点,两边都只算离起点不超过 N 天的人题对,
N = 两届里学得短的那届一半人开始做题到现在的天数。按人不按日历,因为各届
开始做题的时间不一样(25 级第二年才开始)。比哪届改成后端算,接口带 grade / compare。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-20 21:21:22 +08:00
xuyue and Claude Opus 5.5
9e2217e09d
refactor(后台富文本): 编辑器从 wangEditor 换成 Tiptap,老题面的图片尺寸、缩进、颜色打开再保存都不丢
...
Deploy / deploy (push) Canceled after 0s
拿库里全部 3384 条题面 / 提示 / 公告 / 比赛说明做过往返比对,补上图片 style、base64 图片、
段落缩进三处后文字和格式都对得上。工具栏照画布做成一行浅灰小图标,四套档位不变,
加了行内代码、光标在表格里出加删行列。表格格子里的段落在学生端不再把行撑高。
编辑器 JS 638 kB → 455 kB,wangEditor 的 39 kB 样式不用了;polyfill 清单重新审过,
去掉只有 wangEditor 用到的 web.immediate。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-20 20:20:13 +08:00
xuyue and Claude Opus 5.5
67fcd11907
feat(题目): 参考流程图不用再点开,摊在例子后面,画法和学生自己画的图一样
...
Deploy / deploy (push) Canceled after 0s
原来折成一条「老师给的参考流程图」要点开,用 Mermaid 画、整张缩进左栏后字只剩十来像素。
现在默认摊开、放在例子后面(长图不把例子挤出第一屏),用画流程图那套排版和符号画
(FlowchartView,颜色形状和画布共用 paint.ts);只有手写 Mermaid 的老图照旧走 Mermaid。
出题页预览和说明文字一起改。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-20 16:56:44 +08:00
xuyue and Claude Opus 5.5
a1d14a06bc
refactor(卡点分析): 右栏一道题的详情拆成 StuckDetail 组件
...
Deploy / deploy (push) Canceled after 0s
Stuck.vue 从 1006 行减到 544 行,右栏(做过几人、一次就对、错在哪、各班、交了几次才对、
历年、还没做对的人)连同它的计算和样式挪到 components/StuckDetail.vue;取数、三栏联动、
手机上整屏盖住的那层还在 Stuck.vue。两边都用的百分比和平均次数放 stuckMath.ts,
两边都用的几条小样式(muted / num / track …)各留一份。
纯搬家。全部班级、选一个班、手机打开一道题的详情,各自的顶部和滚到底改前改后截图一致。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-19 20:40:27 +08:00
xuyue and Claude Opus 5.5
ff3fdc0b1d
refactor(出题页): 编程题和 SQL 题两个出题页抄了两份的零件收到一处
...
Deploy / deploy (push) Canceled after 0s
admin/problem/components/problemForm.ts:判空富文本 isBlankHtml(原来三份,CodePreview 里还有
一份)、难度选项、返回列表的路由、保存失败的提示、标签超长校验、新建页的草稿
(useCreateDraft:停 0.8 秒存、什么都没填就清、编辑页不存)。
纯搬家。新建 / 编辑 × 编程 / SQL 四个页面改前改后整页截图逐像素一致;两种新建页填个
标题、刷新能恢复,「清空草稿」之后本地存储清掉。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-16 15:43:25 +08:00
xuyue and Claude Opus 5.5
e8a20d12f9
refactor(前端): shared / utils 不再 import oj 和 admin 下的任何东西
...
依赖方向原来是反的:顶栏、登录框、举手列表这些 shared 组件从 oj/ 里拿东西。
- 跨端的接口挪进 shared/api.ts(按 apps/web/CLAUDE.md 的分法):学生端题目列表、
出题人列表、这节课的题、待弹的成就
- 这节课的 store → shared/store/lesson.ts;头像 RankAvatar → shared/components
- 纯函数挪进 utils/:举手列表的错法归类 errorKind、它依赖的答案错误分类 wrongAnswer
和 Python 报错翻译 pythonError、题目列表行的 toProblemRow
- 只有后台在用的出题人下拉 AuthorSelect 挪回 admin/components
纯搬家。首页、题目列表、题目页、排名、课堂看板、后台题目列表打开无报错,
顶栏题号框敲 1001 回车直达题目页。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-16 15:11:21 +08:00
xuyue and Claude Opus 5.5
d4aadc7722
fix(后台列表): 加载失败有提示、慢的时候表格转圈、旧请求晚回来不再盖掉新结果
...
Deploy / deploy (push) Canceled after 0s
后台八个列表(题目、比赛、用户、公告、题单、AI 报告、从题库加题、标签下的题)原来是
`const res = await getXxx(); rows.value = res.results`:接口 500 或断网时什么都不提示,
表格停在旧数据上;关键词防抖和翻页一交错,先发的晚回来会把新结果盖掉。
shared/composables/listLoader.ts 的 track() 把请求包一层:带请求序号、出错按后端文案提示
(登录过期、没权限这几种全局拦截器已经提示过,不弹第二遍)、表格挂 loading。
实跑:六个列表各 10 行正常;拦掉题目列表的接口再翻页,弹「网络异常,请检查网络后重试」
(原来没有任何反应)。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-16 15:07:10 +08:00
xuyue and Claude Opus 5.5
309ca0ece2
refactor(前端): 全站共用的班级下拉、胶囊配色挪出提交列表目录,编辑器不再偷读题目页的 store
...
Deploy / deploy (push) Canceled after 0s
- classLabel / groupClassOptions / classSelectOptions 挪到 utils/classes.ts,useTone 挪到
shared/composables/tone.ts:原来放在 oj/submission/ 下,被前台、后台、shared 引了 50 多处
- 流程图编辑器的草稿键改由题目页传进来(键名不变,学生存着的草稿照样读得到)。原来编辑器
自己读题目页的 store 和路由拼,后台出题页也用这个组件,那边 store 是空的
- SQL 表名补全改由题目页传表进来。原来补全直接读题目页的 store,自学页的 SQL 代码块会
补出上一道看过的题的表名
实跑:提交列表、题目页、排名、后台题目页、SQL 题、流程图题打开无报错;SQL 题输入 stu
补出 students;流程图加一步,草稿照旧存在 flowchart-v2-problem-<题号>。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-16 14:59:55 +08:00
xuyue and Claude Opus 5.5
02e2fa7d9b
feat(后台): 手机上也能用了——菜单收进左边抽屉,列表一行一张卡,不用再横着滑
...
- 侧栏手机上不再占一列图标,顶栏左边 ☰ 拉出整张菜单,按返回键先关菜单
- 题目、比赛、用户、公告、题单列表手机上一项一张卡:名字一行、小字一行、按钮一行,
「学生看得到」开关单独一列靠右
- 卡点分析、AI 报告手机上点开一项整屏看,返回键关掉;年度趋势、自学情况、首页改成上下排
- 出题页、教程编辑、题单编辑、标签、设置手机上排成一列;测试数据「删掉」手机上常驻
- 弹框一律收进屏幕宽度
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-16 11:21:58 +08:00
xuyue and Claude Opus 5.5
cea2c7f102
fix(手机): 比赛排名表看不出能往右滑;班级 PK 每周图日期字太小;后台题目列表「藏着的」被切掉
...
Deploy / deploy (push) Canceled after 0s
- 比赛排名:手机上名字、做对、用时就占满一屏,每题的格子全在屏幕外。列收窄,前一两道题的格子露出来
- 班级 PK:每周人均横轴在手机上是 10px 的「10月12日」,改成 12px 的「10/12」
- 后台题目列表:手机上「全部 / 学生看得到 / 藏着的」换小号按钮,放不下就横着滑
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-15 12:44:57 +08:00
xuyue and Claude Opus 5.5
30bff2acc4
style(后台): 后台各张列表都改成斑马底纹(题目、用户、比赛、公告、练一练记录、标签、AI 报告、成就)
...
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-13 14:45:22 +08:00
xuyue and Claude Opus 5.5
6470f56f87
fix(后台): 用户、题目、比赛、公告、标签几张列表的操作不再收进 ⋯,直接摆在行尾;名字和题目那列不再吃掉整行的空,创建日期不再折成两行
...
1366 宽的屏上题目列表、比赛列表的按钮都放得下;题目的知识点多于两个时只摆一个加「+N」。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-13 14:29:56 +08:00
xuyue and Claude Opus 5.5
c59e31eeb2
feat(后台标签): 标签页改成知识点、主题左右两栏,一眼看出每个标签挂了几道题;改名、换分类、删除收进 ⋯,没归类的单独放最上面
...
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-13 14:04:06 +08:00
xuyue and Claude Opus 5.5
97049d562b
feat(后台题目): 题目列表重排——1366 屏上不用横滚就看得到「学生看得到」开关;一行只剩「编辑」和 ⋯,有人交过的题删除直接灰掉;勾几道一次放出、藏起、加减知识点
...
去掉内部 ID、难度、看不懂的「功能」图标和反馈表情几列;题目名点了就是编辑。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-13 13:27:39 +08:00
xuyue and Claude Opus 5.5
6e946c99fb
feat(出题): 参考流程图改用画布画,「让学生自己画」不再要参考图
...
Deploy / deploy (push) Canceled after 0s
- 学生画的图现在按例子和测试数据评(拼成程序跑),参考图用不上了:「让学生自己画」
只剩一句说明,保存前改成检查有没有例子;「给学生的提示」那一栏去掉(学生从来看不到,
16 道题也都没填)
- 「给学生看一张参考流程图」改用学生画图的同一个编辑器,存结构树(problem.flowchart_data,
原来是死列),Mermaid 由后端照它生成,题面里的图和学生交的图同一套形状
- 「AI 照 Python 答案画一张」改成出结构树,直接摆在画布上接着改;for 循环画成
计数变量 + 当型循环
- 老题手写的 Mermaid 照旧给代码框,旁边「改用画布画」
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-12 21:39:50 +08:00
xuyue and Claude Opus 5.5
6f47ad8358
perf(Markdown): 题面、教程、AI 提示每次打开都去 unpkg.com 拉四个库,机房网络下又慢又不稳
...
md-editor-v3 的 MdPreview 不管正文里有没有代码、公式,都会从 unpkg.com 加载
highlight.js、katex、mermaid、echarts(mermaid 还是另一份 11.x)。而我们只用到最基础的
Markdown:题面 95% 是富文本存的 HTML,教程是标题、表格、图片,AI 输出是标题、列表、
表格、少量代码块,库里一处公式、mermaid 都没有。
- 显示:新组件 shared/components/Markdown.vue,直接用 markdown-it,代码高亮走本地的
highlight.js(和练一练共用 shared/highlight.ts,补了 C++ / SQL)。9 处 MdPreview 全换掉。
正文默认 16px,教程也统一成 16px。
- 编辑:后台教程编辑器换成项目已有的 CodeMirror,加一排格式按钮;图片可以按按钮选、
粘贴、拖进来,都是先上传再插入。md-editor-v3 从依赖里删掉。
- AI 生成的内容(AI 提示、AI 分析、班级报告)不再放行原生 HTML:学生能在代码里诱导
AI 吐出 <img onerror>,老师在后台一打开就执行。库里 1196 条 AI 输出没有一个 HTML
标签,关掉不影响显示。题面、教程照旧放行。
- 长英文改成在单词之间折行,原来 break-all 会把 "I live" 断成 "I l / ive"。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-12 14:02:54 +08:00
xuyue and Claude Opus 5.5
cd75d42a64
feat(年度趋势): 后台年度趋势改成「这届和往届比」,比往届差的题排在最前面
...
Deploy / deploy (push) Canceled after 0s
- 选一届和往届(或另一届)比,两边都至少 20 人做过的题才比;分比往届差 / 差不多 / 比往届好三组,一题一根哑铃条
- 侧栏「历年概况」改回「年度趋势」,地址换成 /admin/problem/trend
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-12 13:10:18 +08:00
xuyue and Claude Opus 5.5
318ffac90f
feat(年度趋势): 历年概况那张表只有一堆数、看不出趋势;改成按届比,这届和往届在同一批题上逐题比一次就对
...
- 新接口 /problem-analytics/grades:每道题在各届(班号前两位)的人数和一次就对人数
- 删掉 /problem-analytics/yearly 和只给它用的学年时间函数
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-12 13:10:18 +08:00
xuyue and Claude Opus 5.5
0980ea858a
feat(卡点分析): 后台卡点分析按知识点 → 题 → 一道题重做,年度趋势改名历年概况只留逐学年总表
...
Deploy / deploy (push) Canceled after 0s
- 选班后只列这个班课上布置过的题,右栏换成「交了几次才对」和交得最多的人
- 历年概况可以导出表格;旧地址 top_ac_trend 跳到新页面
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-12 12:55:49 +08:00
xuyue and Claude Opus 5.5
b2c802174c
feat(卡点分析): 「卡住」原来数的是错过一次的人,做的人多的题全排在前面;改成看一次就对、交几次才对,能按班级和时间段筛
...
- 卡点按「人 × 题」算:一次就对、做对之前交了几次、还没做对几人,带知识点;一道题给每个人的情况、错在哪、全站历年一次就对
- 年度趋势换成历年概况:学年按 9 月切(原来按自然年),进行中的学年和去年同期并排
- 删掉旧的 /problem-analytics/stuck 全站前 40 和 /ac-trend
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-12 12:55:49 +08:00
xuyue and Claude Opus 5.5
eaab224ba8
feat(出题): 测试数据最多 20 组,几百组的题提交详情截图截不下
...
上传 zip 超过 20 组直接报错(编程题、SQL 题都算);出题页加满 20 组后「加一组」
「AI 想几组输入」变灰,导入超过 20 组的 zip 在浏览器里就拦下,改老题超了不让保存。
上限在契约 TEST_CASE_MAX_CASES。线上超过 20 组的题已经手工缩到 20 组。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-10 14:07:30 +08:00
xuyue
2224478294
fix
Deploy / deploy (push) Canceled after 0s
2026-10-09 21:35:34 +08:00
xuyue and Claude Opus 5.5
dd10e64b38
style(出题页): 左边写的地方放大、右边「学生看到的样子」缩小,右边能收起来专心写
...
Deploy / deploy (push) Canceled after 0s
编程题、SQL 题两张出题页一起改:两栏 3 : 2,右栏头上「收起 ›」,收起后剩一条竖着的「学生看到的样子」点了再展开;收没收记在本机
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-09 21:03:50 +08:00
xuyue and Claude Opus 5.5
4ef2794552
fix(后台): 出题页读回来的测试数据每组多一行空白;导入大包后原来的例子丢了
...
Deploy / deploy (push) Canceled after 0s
- 测试点文件末尾的换行读回来时去掉(上传时补回去),比对改没改过也按去掉后的比,没改的题不会白白重传
- 导入超过 100 组的 zip 时先把例子拿下来再切成「不展开」,例子不再丢
- 「不展开」时保存栏改说「加一个例子」;刚导入还没保存时不给「下载 zip」(下到的是库里的旧数据)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-09 20:14:36 +08:00
xuyue and Claude 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
xuyue and Claude Opus 5.5
033a245abb
feat(SQL 题): 增删改题除了第 1 组,其余测试数据可以一行都不改——用来抓学生多改(WHERE 写漏、写宽)
...
Deploy / deploy (push) Canceled after 0s
原来每组数据都必须有被标准答案改到的行,所以「这组里没有研发部,看学生会不会把别的部门也改了」
这种测试数据建不了。现在只有第 1 组(题面上给学生看的那组)还要求改到行;其余组一行都没改时
出题页写「一行都没改」、预览写「执行后所有表都没有变化」。删掉第 1 组、别的组顶上来时自动按
新位置重查。判题本来就不管这一条,不受影响。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-09 19:17:42 +08:00
xuyue and Claude Opus 5.5
2cb39fd96b
feat(后台): SQL 题有了自己的出题页——左边写,右边就是学生看到的样子,改答案、改数据马上重跑
...
- 「新建题目」先选编程题还是 SQL 题,选了就不能改;编辑时按题目本身进对应的页
- SQL 出题页(设计稿「SQL 出题页」方案 B):测试数据一组一行,改完自动重跑,
跑不通的用中文说原因;保存时才打包上传测试点,不用再手动「预览」「上传」
- 新建时存草稿,误关页面不丢
- 编程题出题页去掉 SQL 那一堆分支(以前勾上 SQL 会静默清掉语法要求和流程图)
- 题目列表能按题型筛,SQL 题标题后面挂标签
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-09 18:59:15 +08:00
xuyue and Claude Opus 5.5
25d3296410
feat(SQL 题): 增删改题的期望结果标出执行后变了的格子,删掉的行写清是哪几行
...
学生原来只能拿两张表逐格对,看不出要改的是哪几行。现在改过的格子、新插的行标黄,
删掉的行在表下面写「删掉了 2 行(id 是 2、3)」。按第一列配对,对不上就不标。
数据表和期望结果抽成一个组件,后台出题页的预览也用它。
题型判断统一走契约的 isSqlProblem()。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-09 18:59:15 +08:00
xuyue
bde387e8bc
fix
Deploy / deploy (push) Canceled after 0s
2026-10-08 12:29:35 +08:00
xuyue and Claude 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
xuyue and Claude 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 and Claude 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
xuyue and Claude 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
xuyue and Claude 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
xuyue and Claude 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
xuyue and Claude 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
xuyue and Claude 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
xuyue and Claude Opus 5
cc51e305cf
refactor(时区): 常量收进契约、SQL 统一走 localTime,去掉会话时区与 TZ 兜底
...
Deploy / deploy (push) Has been cancelled
- TIME_ZONE / TIME_ZONE_OFFSET_MINUTES 移到 packages/contract/src/time.ts,
前后端共用一份,不再各写一遍靠注释对齐。
- apps/api/src/time.ts 新增 localTime(列),替换散落 7 处的
`at time zone ${TIME_ZONE_SQL}`;ac-trend 的 where 复用同一个 year 表达式。
- /problems/:displayId/yearly-ac 漏写了时区、按 UTC 切年,被会话时区兜底掩盖;
改为按东八区切(只影响每年 12-31 北京 0–8 点的提交归年)。
- 删掉数据库连接的 TimeZone 和 Dockerfile 的 TZ:正确代码不依赖它们,
它们只会在线上掩盖漏写处、让 dev 与线上答案不同。
- time.ts:calendarDayYearsAgo/pad 并入 shiftMonthsByCalendar,startOfCalendarDay
并入 todayStart,localWeekday 改用 getUTCDay,删掉历史叙述注释。
- 前端 zonedParts 改为固定偏移 + getUTC*(与后端、日期选择器同一写法),
去掉 Intl formatToParts;10 万次 299ms → 11ms。zonedYear 去掉按浏览器时区的兜底。
- 两份 CLAUDE.md 同步;n-date-picker 那条过时说明改成现用法。
验证:新旧「近两年起点」21359 个时刻 0 差异、localWeekday 0 差异、
前端固定偏移与 Intl 在 America/New_York 下 47821 个时刻 0 差异;
localTime 在 select/group by/where 复用可用;fix-achievement-hours 预演仍为 148 / 60。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01K1d8B3f4SXJwDvUY625eQd
2026-09-14 06:06:52 -06:00
xuyue and Claude Opus 5
4c0c38445c
fix(时区): 日历口径收回东八区,读出的时刻统一成 ISO 并保留微秒
...
旧栈 Django 按 Asia/Shanghai 算日历,OJ2 重写时这个锚点丢了:容器和数据库会话
都是 UTC,于是「今日提交」在北京时间 0–8 点是空的,「凌晨/早起提交次数」整体偏
8 小时,热力图、AC 趋势年份、近两年活跃人数也各按进程时区切。
- 新增 apps/api/src/time.ts 作为唯一锚点(固定 +8 偏移,不依赖进程 TZ / tzdata),
todayStart、成就小时/日期键、热力图、月份平移、年份夹逼全部改走它;
SQL 里按日历切的一律显式 at time zone。
- db/index.ts:连接会话时区设为东八区(兜底);给 timestamptz(1184) 挂 parser,
读出统一成 ISO 8601 UTC,撤掉为拿 PG 文本形状写的 ::text。parser 保留微秒 ——
生产库 12.3 万条提交几乎全带微秒,截成毫秒会让翻页分界行和班级 AC 排名的
<= min(create_time) 把自己排除(翻页每页丢一条、排名少 1)。
- 前端 parseTime/zonedParts/zonedYear 按 Asia/Shanghai 渲染,n-date-picker 做
toPickerValue/fromPickerValue 平移,站内不再按浏览器时区取时间部件。
- Dockerfile 设 TZ=Asia/Shanghai 作为第二道兜底。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01K1d8B3f4SXJwDvUY625eQd
2026-09-14 05:55:17 -06:00
xuyue and Claude Opus 5
a6ba5cdf07
refactor(AST): 两张 target 表合成一张,加节点类型漏配在结构上不再可能
...
契约的 AST_NODE_TARGETS_BY_LANGUAGE 是 target → 中文名,judge/ast.ts 的 mappings 是
target → tree-sitter 节点类型,同一批键分在两个包里,靠一句「两边必须同增同减」的注释
维持。只加一边是静默错判:老师给 C 题选到只有 Python 有的 list_comprehension,判题机
拿裸名去比节点类型,C 的语法树里永远不存在它,于是「必须使用列表推导式」永远失败、
「不能使用 f-string」永远通过,两头都不报错,只有学生受着。
现在一个 target 一条 { label, node }:label 给后台下拉和题目页,node 给判题机。加 target
而漏配节点类型在结构上就不可能了。judge/ast.ts 的 mappings 整张删掉,解析统一走契约的
astTargetNodeType()(节点查 node,运算符查运算符表 —— 那张表的值本身就是要比的 token,
判题机原来抄的 and→&& 三条取值逐个相同,纯属重复)。
顺带把同一份数据的四份拷贝收成一份:C 的 14 条原来在契约和判题机里各抄了两遍
(C 一份、C++ 一份),现在 C++ 逐条引用 C_NODE_TARGETS;运算符表的 C++ 改成
{ ...C_OPERATOR_TARGETS, "<<", ">>" }。C++ 那几条仍逐条列出而不是 spread,是为了保住
下拉框的显示顺序(C++ 独有的几条插在中间)。
## 验证
行为零变化,是逐个 target 机械比对过的:把 HEAD 版的两张表原样取出来,对三种语言的
全部 target 比对「label / 运算符文案 / tree-sitter 解析结果 / 下拉框顺序」四项 ——
C 37 个、C++ 47 个、Python3 43 个,全部一致,键集与顺序也一致。
实跑:给题目 1004 配两条 Python3 规则(必须有 for 循环、不能用 f-string),交一发没有
for 循环的正确答案,判成 AST_CHECK_FAILED(10),statistic_info.ast_results 为
「必须使用 for 循环 / 不通过」「不能使用 f-string / 通过」—— label 与 node 两半都走到了。
再交一发带 for 循环的,判成 ACCEPTED(0)。
tsc、vue-tsc、vite build、单二进制编译均通过。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_012j1vgeDqay8wKCh8dPgPcH
2026-09-10 19:30:35 -06:00
xuyue and Claude Opus 5
25b86ec17e
refactor(提交): 删掉从来没用起来的「提交互相可见」
...
Deploy / deploy (push) Has been cancelled
problem.share_submission(题目级)和 submission.shared(单条)两个开关,连同
判定分支一起删掉。
生产备份(2026-08-07)里的实际用量:956 道题只有 2 道开过 share_submission,
还都是 contest_id=1 的比赛题 —— 比赛未结束时那条分支根本走不到,等于一天都没
生效过。123140 条提交里 shared=true 的有 40 条,39 条在 2022 年、1 条在
2023-03-30,之后近三年零使用;出题页从来没给过题目级开关,单条分享的入口在更早
那版前端上,ojnext 和 OJ2 都没搬过来,OJ2 里 PUT /submissions/:id 一个调用方
都没有。
canViewSubmission 剩下三条:本人 / 管理员(比赛中的 Student Admin 除外)/ 本题
作者,其余一律看不到。结尾的 `shareSubmission || shared` 没了;它上面那条「比赛
未结束一律不给」也一并去掉 —— 走到那里的必然不是这三种人,现在无论比赛与否都是
false,留着是重复的。allowShared 参数随之消失,它唯一的用途就是分享开关的归属
校验。
一并删掉:PUT /submissions/:id、响应里的 shared / canUnshare(列表、详情、站内
信内嵌三处)、题目详情与后台题目里的 shareSubmission、shareSubmissionRequestSchema,
以及新建提交时那句 shared: false(列上本来就有 default false)。
两个数据库列保留不删,只在 schema.ts 上注明已停用:删列是破坏性迁移,而留着不读
不写零成本,还留着那 40 条的历史痕迹。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01XvmqDsZNyUo9P3sFQtoWVB
2026-09-07 07:18:41 -06:00
xuyue and Claude Opus 5
2256597838
fix(后台建题): 修好 dev 代理走错服务,以及新建页带出上一题 id、超长标签报英文
...
三处不相干的小毛病,都在「新建/编辑题目」这条路上。
vite 的 /api 代理写的是 localhost:3000。api 用 Bun.serve 起、只绑 IPv4 的
0.0.0.0:3000,而 Node 解析 localhost 时 ::1 排在前面 —— 别的项目的 dev server
一占 [::1]:3000,两边端口就不冲突(一个 v4 一个 v6,谁都不报错),浏览器发出的
/api/* 整个落到那个站上,表现是后台一进就被弹回首页。改成 127.0.0.1。
新建页和编辑页共用同一个 localStorage 草稿键,而编辑页会把服务器数据连 id 一起
写进去。没保存就离开的话,这个 id 跟着草稿漂到新建页:「下载测试点」下的是那道旧
题的包,SQL 测试点编辑器也会去回显那道旧题的脚本。新建分支进来先把 id 摘掉。
新标签没有长度限制,超过 32 字要到保存时才撞出 zod 的英文原文(Too big:
expected string to have <=32 characters)。把 32 提成契约里的
PROBLEM_TAG_MAX_LENGTH,输入框拿它做 maxlength,validateNewTags 再兜一道粘贴
绕过的情况,提示换成中文。校验的松紧没动,32 字仍然存得进、33 字仍然拦下。
editContestProblem 和 editProblem 函数体逐字相同(都是 PUT admin/problems/:id,
比赛由后端从题目自己推导),合成一个。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01XvmqDsZNyUo9P3sFQtoWVB
2026-09-07 07:18:23 -06:00
xuyue and Claude Opus 5
d1d071ff7b
fix(后台): 测试用例生成器允许无输入的测试点
...
Deploy / deploy (push) Has been cancelled
「这行算不算数」原来判的是 `f.in.trim()`,把「这题没有输入」和「这行我还没
填」撞成了同一种状态。打印类题目(输出星号矩形、只靠 print 的格式化输出题)
输入留空 → 点「先运行」整行被删 → 一行不剩 → 「上传」永远是灰的,老师只能
往输入框里塞个「无」才存得下去,那两个字节就真的进了 stdin。8019 / 8020 /
8021 三道题的 1.in 就是这么变成 3 字节「无」的。
拆成两个判据:
- hasOutput —— 有输出且没报错,这一行才打进 zip,输入空不空无所谓;
- isFilled —— 输入或输出任一非空,只用来在「先运行」里筛掉面板上的空占位行,
全没填时留一行当无输入题跑。
canUpload 保留原来那条守卫:填了输入却没跑出输出的行仍然挡住上传。「先运行」
不再要求先填输入。
后端本来就收空的 .in(processTestCaseZip 无非空校验),已上线的 8007、P003
的 1.in 就是 0 字节,卡住的一直只有这个面板。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01AdMvixPo27sWFrUmk6ZStZ
2026-09-07 06:29:23 -06:00