xuyue and Claude Opus 5.5
5561e0bc3a
feat(后台用户): 用户列表按班级看、「重置密码」常驻;批量建号粘进名单当场列出会建成的账号,重名和已有的先点出来,建好能下载名单、打印账号条
...
用户列表去掉 ID、真名、占位邮箱和四颗彩色按钮。下载的名单开头带 BOM,Excel 打开中文不再乱码。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-13 13:56:03 +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
4240a451e4
chore(站内信): 消息页、后台空壳页、两个接口和 message 表一起下线
...
Deploy / deploy (push) Canceled after 0s
历史上一共 6 条站内信(最后一条 2025-06),发信接口两代前端都没接过,后台页面只有一句
「未完待续」,OJ2 顶栏也没有入口。
0033 是 DROP TABLE,部署要显式放行:OJ2_ALLOW_DESTRUCTIVE=1 docker/deploy.sh,
或 CI 手工触发时勾 allow_destructive。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-13 00:51:12 +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
e6c02dce33
chore(依赖): 前后端依赖升到最新,补上机房 Chrome 105 缺的两个 polyfill
...
几处随升级改的:
- VueUse 15 的 useNow 不再收 interval,不传 scheduler 默认逐帧刷新。比赛列表(1 秒)
和后台建比赛(15 秒)改成用 useIntervalFn 当调度器,频率不变。
- 重新探测 modernPolyfills:mermaid 12 用了 Object.groupBy(Chrome 117),core-js 新数据
把 URL.parse(Chrome 126)也算进来了,不补的话机房老机器上静默报 TypeError。清单 52 项。
- vue-router 5.4 弃用了导航守卫里的 next(),全局守卫改成返回值。
- web-tree-sitter 0.27:AST 规则在 dev 和编译后的二进制里各跑过一遍,判过、判不过都对;
jieba 2.0.4 原生模块在仓库外起二进制能正常分词。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-12 14:03:34 +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
845e41c060
feat(自学): 自学重做——首页课程地图、读一课按项目分目录、代码块就地运行、学完给题做
...
Deploy / deploy (push) Canceled after 0s
- 顶栏「自学」进新的自学首页 /learn:接着学(按服务端记录,不再串到上一个学生)+ 按项目分组的课程地图
- 读一课:左边目录按项目折叠,正文加宽,右边本课大纲带练一练标记;去掉了不能运行的示例代码栏
- 正文里的代码块能改能运行,报错用题目页那套中文解释;读输入的代码出输入框
- 课末:练一练做到几道 → 学完了 → 老师挑的几道题(必会标出来)→ 下一课
- 练一练统一成绿色提交、结果一行字;手机版目录从底部弹出
- 后台:教程列表按项目分组拖动排序,编辑页左写右看、练一练插到光标处、挑相关题;
自学情况改成方块格 + 还没打开过的名单
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-12 09:40:34 +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 and Claude 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
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
151bbdcb50
feat(比赛): 比赛页一页看题目和自己的名次;排名竞争感做足、结束有领奖台;老师考试中看全班、考完看成绩;新建比赛一屏做完
...
Deploy / deploy (push) Canceled after 0s
- 学生比赛页(设计稿 B):左边题目带几人做对、谁最先做对;右边我第几名、5 分钟里升了几名、再做对 1 道能到第几名、我前后的人
- 期中、期末考试中只有自己的进度,写明「排名考完公布」,题目页的排名入口也藏起来
- 排名页:按班筛、名次变化、最先做对的深绿格、自己那行钉住;结束后前三名领奖台 + 我的成绩卡;排名曲线和学生的「导出数据」去掉
- 老师的「全班情况」:卡在一道题、15 分钟没交的放最上面,没进来的人对上看板的请假;考完变「成绩」,点格子看代码、标看过了(代替后台审核页),导出成绩
- 比赛列表:进行中的一大块「接着比」,已结束的写我第几名,前三带奖杯
- 新建比赛:默认 10 分钟后开始,时长点按钮,搜题号把题加进来自动编号、拖动排顺序
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-09 20:58:59 +08:00
xuyue and Claude Opus 5.5
b94e028ff4
feat(比赛): 榜单一次给全,带名次变化和每题谁最先做对;期中、期末考试中学生看不到排名;老师能看全班情况
...
- GET /contests/:id/scoreboard 代替 /rank:整张榜、5 分钟前的名次、每题做对 / 做过人数和学生里最先做对的人(不再用 is_first_ac,老师赛中试做会占掉它)
- 期中、期末进行中:学生只拿到自己那一行,人数清零、「全班最先」也不给,考完一起公布
- GET /contests/:id/class-view(老师):真名、每人最后一次交、没进来的人 —— 比赛不绑班,来了一半以上的班才算这场的班
- 比赛列表带题数、参赛人数、我的名次和做对数,能筛「我参加过的」「期中 · 期末」
- PUT /admin/contests/:id/problems/order:比赛题按顺序重编 1、2、3,比赛结束后不让动
- 后台「审核」列表接口去掉,并进前台老师的成绩页;「看过了」的写接口留着
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-09 20:58:59 +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 and Claude 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
xuyue and Claude 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
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
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
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
6b2da41882
refactor(题单后台): 添加 / 编辑弹窗两两合并成 ProblemModal、BadgeModal
...
AddBadgeModal / EditBadgeModal、AddProblemModal / EditProblemModal 各是两份八成相同
的组件,改一处表单项另一处总要漏。合并成一个组件,传了 badge / problem 就是编辑、
null 就是添加;两种模式分别 emit create / update,detail.vue 的四个 handler 不变。
表单项、校验、文案、提交的数据形状都照旧(题目弹窗添加时带 problemId、编辑时只显示
标题)。有一处刻意的行为变化:编辑弹窗原来只在换了一条记录时才重新填表,取消后再打开
同一条会看到上次没保存的改动;现在每次打开都按库里的值重新填。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-09-27 15:16:03 +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 Sonnet 5
20a6ddc79c
feat(自学): 重做学生端页面与教师端学情概览
...
Deploy / deploy (push) Has been cancelled
学生端:目录 + 居中限宽正文 + 可收起的示例代码栏;目录改成三态圆点,
顶部加总进度;上一课/下一课栏桌面端固定在底部。
教师端:汇总卡片、学生状态标签与筛选(未开始/7 天没学/只读不练等)、
最后学习补「N 天前」、按练习表加「没人一次对/多数人卡住」提示。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com >
2026-09-19 05:07:37 -06:00
xuyue and Claude 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
xuyue and Claude Opus 5
f90d01338e
feat(自学情况): 按学生加姓名/学号搜索,后端补稳定排序
...
Deploy / deploy (push) Has been cancelled
搜索是纯前端过滤(整表本来就一次拉完),和班级筛选可以叠加。
学生查询原来没有 orderBy,前端默认按「已读」升序排之后,同分的一大批
(尤其一堆 0)落回聚合的任意顺序,刷新一次换一个样;按班级、学号兜底。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-09-17 02:23:01 -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
4189c59162
update
Deploy / deploy (push) Has been cancelled
2026-09-14 08:39:58 -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
fe4fc46243
fix
Deploy / deploy (push) Has been cancelled
2026-09-13 23:40:58 -06:00
xuyue
271123179a
fix
Deploy / deploy (push) Has been cancelled
2026-09-13 19:29:45 -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
3a8f4fcd51
fix(后台用户): 管理员密码显示出来之后能再隐藏
...
Deploy / deploy (push) Has been cancelled
原来只发 reveal 事件,露出去就没有回头路,只有翻页 / 搜索才会回到打码状态 ——
看一眼就该关掉,不然一整页管理员密码那么摊着。改成 toggle,打码与否只看
revealed 这一个 prop,按钮文案跟着走。
密码列顺带从 150 拓到 180:露出明文后面还跟着「隐藏」按钮,150 挤不下。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_017xu912Rv5JUUuy6MqMcQW2
2026-09-07 19:59:54 -06:00
xuyue and Claude Opus 5
856b7a280e
feat(后台用户): 新增「在线优先」排序,列表直接显示在线标记
...
在线状态库里没有、会话也判定不了 —— session 的 TTL 是 7 天且每次请求续期,
「有会话」只说明这人一周内来过。新开一个 Redis sorted set(auth/presence.ts)
记最后活动时间,5 分钟内有活动算在线。
写入全搭在已有的 pipeline 上,不多一趟往返:登录、每个带鉴权请求的续期、
以及 touchSession —— 只挂着 WebSocket 不发请求的人靠最后这条,sweepSessions
每 60 秒一轮,所以窗口取 5 分钟,明显大于那个间隔。登出、改密码、禁用账号
会立刻把人摘掉;过期成员在后台读列表时顺手清理(整个 key 不能设 TTL,
ZADD 不重置 key 的 TTL,到期会把还在线的人一起抹掉)。
排序 orderBy=-online 先捞在线 id,SQL 里 case when 分两档,档内继续按
最近登录排;没人在线时那个 case 恒等于 1,直接省掉。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_017xu912Rv5JUUuy6MqMcQW2
2026-09-07 19:30:45 -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