Files
OJ2/packages/contract/src/language.ts
T
xuyueandClaude Opus 5.5 29c31640b5 refactor(课堂任务): 「课堂看板」改名「课堂任务」,地址换成 /task;班级 PK 换成 /pk
- 界面上的「课堂看板」「课堂作业」统一叫「课堂任务」,顶栏、老师首页、后台菜单一起改
- 前端 oj/classroom → oj/task、oj/class → oj/pk,两个名字不再只差几个字母却毫不相干;旧地址不留跳转
- 后端 routes/classroom.ts 拆开:课堂任务的接口进 routes/task.ts(/task/board|lesson|today),
  首页的「上次来」「班里在做」进 routes/home.ts;共用的取题口径挪进 services/lesson.ts
- 契约 classroom.ts 同样拆成 task.ts / home.ts,ClassBoard* 改叫 TaskBoard*

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 22:53:07 +08:00

85 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { z } from 'zod'
/**
* 判题沙箱认得的语言。**这是全仓唯一的语言集合定义处。**
*
* 键名必须与 `apps/api/src/judge/languages.ts` 的 `languageConfigs` 一致 ——
* 沙箱的编译/运行命令按这些键查表,查不到就是 `Unsupported judge language`。
* 后端那边是 `Record<string, …>`(判题机要按名字取配置,不能窄化成联合),
* 所以这个联合是**手写**的,改 languages.ts 时两边一起改。
*
* **这里列的是历史上出现过的值,不等于现在能提交的语言。** 现在判题沙箱只认
* `C` / `C++` / `Python`(`languages.ts` 里就这三块),前端的语言复选框也只给这三个
* 加 SQL。`Java`(44 条) / `Golang`(15) / `JavaScript`(3) 是历史值:判题机没有它们的
* 编译配置、镜像里也没有工具链了,但生产库里有这些提交记录,提交列表要能渲染出来,
* 所以键必须留着。
*
* Java / JavaScript / Golang 是 2026-09 随判题镜像升级一起下掉的,理由见
* `apps/api/src/judge/languages.ts` 顶部。
*
* `Python2` / `Python3` 这两个旧值**已经不在这里了** —— 0019 迁移把库里的
* 104530 条提交、937 道题、1235 个用户的成就指标全并成了 `Python`。
*/
export const judgeLanguageSchema = z.enum(['C', 'C++', 'Python', 'Java', 'JavaScript', 'Golang'])
/**
* 题目可以挂的语言 = 沙箱语言 + 两种非沙箱题型。
*
* - `SQL` 走 `judge/sql/` 那条独立链路(子进程 + sql.js),不经过沙箱;
* - `Flowchart` 走 AI 评分(flowchart/run.ts),也不经过沙箱。
*
* **两者都是真实可选、真实有历史数据的**,不是预留值:生产库 961 道题里有
* 9 道 SQL 题、124191 条提交里有 91 条 SQL。前端原来手抄的语言联合漏了 SQL,
* 于是那 91 条提交的 `language` 在类型上是 `undefined` —— 这就是两份真相
* 各自演进的代价,现在并成一份。
*/
export const problemLanguageSchema = z.enum([...judgeLanguageSchema.options, 'SQL', 'Flowchart'])
/**
* 判题沙箱**现在**跑得了的语言,就是 `apps/api/src/judge/languages.ts` 里那三块。
* 试运行(`POST /trial-runs`)只收这几个:历史语言交上来只会在判题机那边报系统错误。
*/
export const runnableLanguageSchema = judgeLanguageSchema.extract(['C', 'C++', 'Python'])
/**
* 老师布置任务能选的语言:判题机跑得了的三种,加 SQL(数据库课一整节都是 SQL 题)。
* SQL 题只收 SQL,所以 C / Python 的作业里夹 SQL 题也行 —— 那几道不受作业语言限制
*/
export const lessonLanguageSchema = problemLanguageSchema.extract(['Python', 'C', 'C++', 'SQL'])
/**
* 这节课做什么,老师布置时选(2026-11 加):
* - `code`:写代码,「做完」只认代码交对(加这一项之前布置的课都是它);
* - `flowchart`:画流程图,只认画到 A / S,不选语言(language 为 null);
* - `both`:先画再写,一道题画到 A / S **并且**代码交对才算做完。学生画一道写一道、
* 全画完再写都行,所以是一节课里的两步,不是两节课。
*
* 画流程图的两种只能布置打开了「让学生自己画」的题(problem.allowFlowchart)。
* 推断出来的课没有它(null):代码交对或流程图画到 A / S 都算做完,和加这一项之前一样
*/
export const lessonModeSchema = z.enum(['code', 'flowchart', 'both'])
export type LessonMode = z.infer<typeof lessonModeSchema>
export const LESSON_MODE_LABEL: Record<LessonMode, string> = { code: '写代码', flowchart: '画流程图', both: '先画再写' }
/** 这种课要不要画、要不要写 */
export function lessonNeeds(mode: LessonMode) {
return { draw: mode !== 'code', code: mode !== 'flowchart' }
}
/**
* SQL 题:可选语言里有 SQL(后端保存时强校验 SQL 只能单独出现)。题型只认这一条,
* 前后端一律走它,别再各自看 sqlConfig 或 languages
*/
export function isSqlProblem(problem: { languages: readonly string[] }) {
return problem.languages.includes('SQL')
}
export type JudgeLanguage = z.infer<typeof judgeLanguageSchema>
export type LessonLanguage = z.infer<typeof lessonLanguageSchema>
export type RunnableLanguage = z.infer<typeof runnableLanguageSchema>
export type ProblemLanguage = z.infer<typeof problemLanguageSchema>
/** 认语言名(地址栏、localStorage 里来的);认不出来返回 null,由调用方决定怎么兜底。 */
export function parseLanguage(value: unknown): ProblemLanguage | null {
return problemLanguageSchema.safeParse(value).data ?? null
}