Files
OJ2/apps/web/src/utils/judge.ts
T
xuyueandClaude Opus 5.5 e7b95d211d fix(题目): 修掉题目页重构审查查出的问题——提交途中换题会把结果算到新题上、运行例子把对的菱形判错、点评完「下一题」不跳等
题目页重构之后按「功能对照 / 状态 / 结果页 / 布局与后端」四路审查了一遍,查出的问题一起修:

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

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

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

结果与题面
- 「去自己输入拿 51 这些数试试」取到了题面 HTML 里的颜色值;「题目原话」露出 "
- 流程图 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

51 lines
2.0 KiB
TypeScript

import axios from "axios"
import { base64DecodeUtf8, base64EncodeUtf8 } from "./functions"
import type { Code, LANGUAGE } from "./types"
const http = axios.create({ baseURL: import.meta.env.PUBLIC_JUDGE0_URL })
// Judge0 的语言 id。Flowchart 和 SQL 不在其中 —— 前者根本不是可执行代码,
// 后者由本站自己的 SQL 沙箱判,都走不到 Judge0。
const JUDGE0_LANGUAGE_ID: Partial<Record<LANGUAGE, number>> = {
C: 50,
"C++": 54,
Java: 62,
Golang: 60,
JavaScript: 63,
Python: 71,
}
export async function createTestSubmission(code: Code, input: string) {
const encodedCode = base64EncodeUtf8(code.value)
const id = JUDGE0_LANGUAGE_ID[code.language]
if (id === undefined) {
return { status: null, output: `${code.language} 不支持在线试运行` }
}
let compilerOptions = ""
if (id === 50) compilerOptions = "-lm" // 解决 GCC 的链接问题
const payload = {
source_code: encodedCode,
language_id: id,
stdin: base64EncodeUtf8(input),
redirect_stderr_to_stdout: true,
compiler_options: compilerOptions,
}
const response = await http.post("/submissions", payload, {
params: { base64_encoded: true, wait: true },
})
const data = response.data
const status: number | null = data.status?.id ?? null
const stdout = base64DecodeUtf8(data.stdout)
// 跑通了(3 = Accepted)就只要程序自己的输出,而且只去掉末尾的空白:
// - C 有警告(隐式声明 sqrt、用了 gets)时 Judge0 跑通了也带回 compile_output,拼进来
// 就成了「你的输出」的一部分,例子永远对不上;后台生成测试点时还会写进 .out
// - 开头的空格是输出的一部分(打印菱形、三角形),原来整体 trim() 会把它削掉,
// 对的代码被判成「只是空格不一样」
if (status === 3) return { status, output: stdout.trimEnd() }
// 没跑通:报错原文给人看,两段拼起来
return {
status,
output: [base64DecodeUtf8(data.compile_output), stdout].join("\n").trim(),
}
}