Files
OJ2/apps/web/src/utils/constants.ts
yuetsh 36a4663193
Some checks failed
Deploy / deploy (push) Has been cancelled
chore(前端): 清掉四处零引用的死代码
按名字扫了一遍 api 层导出和 utils 常量,四处全仓零引用:

**`getContestProblem`**(admin/api.ts)—— 和紧挨在它上面的 `getProblem` 逐字
相同,同一个 URL、同一个类型。旧后端 admin 侧比赛题和公开题是两个端点,合并
之后这个壳留下来了。

**`createMessage`**(oj/api.ts)—— 两代前端都只有定义没有调用。参数名还是旧
后端那套(recipient / submission),函数体里再映射成契约的
recipientId / submissionId,等于给一个不存在的调用方写了个兼容层。
d3b05b8 删掉了它的类型 CreateMessage,函数漏了。

  后端 `POST /messages` 是完整实现的,只是后台那个页面
  (admin/communication/messages.vue)两代都是一句「未完待续」的占位。
  在端点上加了注释说明这件事,免得下次扫「无人调用的端点」时被当成可删。

**`CONTEST_TYPE`**(constants.ts)—— 和上面 30 行处的 `ContestType` 枚举
一模一样。枚举那份有 8 处在用,这个对象零引用。

**`LANGUAGE_ID`**(constants.ts)—— Judge0 的语言 id。真正在用的那份在
utils/judge.ts 的 JUDGE0_LANGUAGE_ID,而且**只有那份是对的**:死掉的这份把
Golang / JavaScript / Python2 全写成了 0,谁要是拿它去调 Judge0,这三种语言
的在线试运行会静默发出 `language_id: 0`。

顺带确认过没有 `constants["LANGUAGE_ID"]` 这类动态取值。

验证:vue-tsc 0 error、vite build 通过、tsc(apps/api) 0 error、
check:routes 168 条无遮蔽。四处都是零文本引用的纯删除。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 23:32:50 -06:00

360 lines
8.4 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 type { AchievementRarity, SUBMISSION_RESULT, ReactionKey } from "./types"
// 与后端 judge/status.ts 的 JudgeStatus 逐条对齐submitting 除外,见下)。
// 注意:原来 time_limit_exceeded 写成 `1 | 2`TS 按位或算成 3
// memory_limit_exceeded 撞了同一个值 —— 后端这两个是分开的两个码。
export enum SubmissionStatus {
compile_error = -2,
wrong_answer = -1,
accepted = 0,
cpu_time_limit_exceeded = 1,
real_time_limit_exceeded = 2,
memory_limit_exceeded = 3,
runtime_error = 4,
system_error = 5,
pending = 6,
judging = 7,
partial_accepted = 8,
// 前端自造的伪状态:点了提交、还没拿到判题结果时本地先填 9。
// 后端永远不会下发它,所以契约的 judgeStatusSchema 里没有。
submitting = 9,
ast_check_failed = 10,
}
export enum ContestStatus {
initial = "2", // 这里不需要传入到后端,只是为了一开始加载数据的时候,做一个初始位
not_started = "1",
underway = "0",
finished = "-1",
}
export enum ContestType {
public = "Public",
private = "Password Protected",
}
export const JUDGE_STATUS: {
[key in SUBMISSION_RESULT]: {
name: string
title: string
type: "error" | "success" | "warning" | "info"
}
} = {
"-2": {
name: "编译失败",
title: "编译失败",
type: "warning",
},
"-1": {
name: "答案错误",
title: "答案错误",
type: "error",
},
"0": {
name: "答案正确",
title: "答案正确",
type: "success",
},
"1": {
name: "运行超时",
title: "运行超时",
type: "error",
},
"2": {
name: "运行超时",
title: "运行超时",
type: "error",
},
"3": {
name: "内存超限",
title: "内存超限",
type: "error",
},
"4": {
name: "运行时错误",
title: "运行时错误",
type: "warning",
},
"5": {
name: "系统错误",
title: "系统错误",
type: "error",
},
"6": {
name: "等待评分",
title: "等待评分",
type: "warning",
},
"7": {
name: "正在评分",
title: "正在评分",
type: "warning",
},
"8": {
name: "部分正确",
title: "部分正确",
type: "warning",
},
"9": {
name: "正在提交",
title: "正在提交",
type: "info",
},
"10": {
name: "语法未通过",
title: "答案正确,但语法未通过",
type: "success",
},
}
export const CONTEST_STATUS: {
[key in ContestStatus]: {
name: string
type: "error" | "success" | "warning"
}
} = {
// 这里不需要传入到后端,只是为了一开始加载数据的时候,做一个初始位
"2": {
name: "未开始",
type: "warning",
},
"1": {
name: "未开始",
type: "warning",
},
"0": {
name: "进行中",
type: "success",
},
"-1": {
name: "已结束",
type: "error",
},
}
export const USER_TYPE = {
REGULAR_USER: "Regular User",
STUDENT_ADMIN: "Student Admin",
TEACHER_ADMIN: "Teacher Admin",
SUPER_ADMIN: "Super Admin",
}
export const PROBLEM_PERMISSION = {
NONE: "None",
OWN: "Own",
ALL: "All",
}
export const STORAGE_KEY = {
AUTHED: "authed",
LANGUAGE: "problemLanguage",
LEARN_CURRENT_STEP: "learnStep",
ADMIN_PROBLEM: "adminProblem",
ADMIN_PROBLEM_TAGS: "adminProblemTags",
DEMO_MODE: "demoMode",
}
export const DIFFICULTY = {
Low: "简单",
Mid: "中等",
High: "困难",
} as const
const cSource =
"#include<stdio.h>\r\n\r\nint main()\r\n{\r\n \r\n return 0;\r\n}"
const cppSource =
"#include<iostream>\r\n\r\nusing namespace std;\r\n\r\nint main()\r\n{\r\n \r\n return 0;\r\n}"
const pythonSource = ""
const javaSource =
'public class Main {\r\n public static void main(String[] args) {\r\n System.out.println("黄岩一职");\r\n }\r\n}'
export const SOURCES = {
C: cSource,
"C++": cppSource,
Java: javaSource,
Python3: pythonSource,
Python2: "",
JavaScript: "",
Golang: "",
Flowchart: "",
SQL: "",
} as const
export const LANGUAGE_FORMAT_VALUE = {
C: "c",
"C++": "cpp",
Java: "java",
Python2: "python",
Python3: "python",
JavaScript: "javascript",
Golang: "go",
Flowchart: "flowchart",
SQL: "sql",
} as const
export const LANGUAGE_SHOW_VALUE = {
Flowchart: "流程图",
C: "C语言",
"C++": "C++",
Java: "Java",
Python2: "Python",
Python3: "Python",
JavaScript: "JS",
Golang: "Go",
SQL: "SQL",
} as const
export const ICON_SET = {
Flowchart: "vscode-icons:file-type-drawio",
Python2: "devicon:python",
Python3: "devicon:python",
C: "devicon:c",
"C++": "devicon:cplusplus",
Java: "devicon:java",
JavaScript: "devicon:javascript",
Golang: "devicon:go",
SQL: "devicon:sqlite",
} as const
const cTemplate = `//TEMPLATE BEGIN
#include <stdio.h>
int main() {
printf("黄岩一职");
return 0;
}
//TEMPLATE END`
const cppTemplate = `//TEMPLATE BEGIN
#include <iostream>
int main() {
return 0;
}
//TEMPLATE END`
const blankTemplate = `//PREPEND BEGIN
//PREPEND END
//TEMPLATE BEGIN
//TEMPLATE END
//APPEND BEGIN
//APPEND END`
export const CODE_TEMPLATES = {
C: cTemplate,
"C++": cppTemplate,
Python2: blankTemplate,
Python3: blankTemplate,
Java: blankTemplate,
JavaScript: blankTemplate,
Golang: blankTemplate,
Flowchart: blankTemplate,
SQL: blankTemplate,
} as const
export enum ScreenMode {
both = "双栏",
code = "自测",
problem = "题目",
}
export enum ChartType {
Rank,
Activity,
}
// 成就稀有度
export const RARITY_LABEL: Record<AchievementRarity, string> = {
bronze: "青铜",
silver: "白银",
gold: "黄金",
platinum: "白金",
}
// 边框、色块用的原色:饱和度够高,明暗底上都醒目。
// 青铜往红偏(色相 23黄金往纯黄推色相 47中间隔开两档亮度
// 不然两个都落在橙棕区,扫一眼分不出来
export const RARITY_COLOR: Record<AchievementRarity, string> = {
bronze: "#c2703d",
silver: "#9fa6b2",
gold: "#f2c012",
platinum: "#7dd3fc",
}
// 文字要另配一套。上面那组是照深色底调的,搬到白底上白金只有 1.7:1、
// 黄金 2.2:112px 的稀有度标签根本看不清。取色见 useRarityColor
export const RARITY_TEXT_COLOR: Record<
"dark" | "light",
Record<AchievementRarity, string>
> = {
dark: {
bronze: "#e08d63",
silver: "#b6bcc7",
gold: "#f2c012",
platinum: "#7dd3fc",
},
light: {
bronze: "#a13d1e",
silver: "#6b7280",
gold: "#8f6f00",
platinum: "#0369a1",
},
}
// 时间范围配置
export const DURATION_OPTIONS = [
{ label: "本节课内", value: "hours:1" },
{ label: "两节课内", value: "hours:2" },
{ label: "一天内", value: "days:1" },
{ label: "一周内", value: "weeks:1" },
{ label: "一个月内", value: "months:1" },
{ label: "两个月内", value: "months:2" },
{ label: "半年内", value: "months:6" },
{ label: "一年内", value: "years:1" },
] as const
// 班级号的位数范围。学生用户名形如 ks<班级号><姓名>,班级号还要跟
// 网站配置里的班级列表对得上。
// 后端 OnlineJudge/utils/shortcuts.py 的 CLASS_NAME_MIN/MAX_DIGITS
// 是同一条规则的另一份,改这里必须同时改那边。
export const CLASS_NAME_MIN_DIGITS = 3
export const CLASS_NAME_MAX_DIGITS = 4
/** 合法班级号3~4 位纯数字 */
export const CLASS_NAME_RE = new RegExp(
`^\\d{${CLASS_NAME_MIN_DIGITS},${CLASS_NAME_MAX_DIGITS}}$`,
)
/** 用户名开头的 ks<班级号>,用于从用户名里认出班级 */
export const USERNAME_CLASS_RE = new RegExp(
`^ks\\d{${CLASS_NAME_MIN_DIGITS},${CLASS_NAME_MAX_DIGITS}}`,
)
/** 班级号作为数字时的上下界,给 n-input-number 用 */
export const CLASS_NAME_MIN_VALUE = 10 ** (CLASS_NAME_MIN_DIGITS - 1)
export const CLASS_NAME_MAX_VALUE = 10 ** CLASS_NAME_MAX_DIGITS - 1
export const REACTIONS: {
key: ReactionKey
label: string
icon: string
}[] = [
{
key: "too_easy",
label: "太简单",
icon: "fluent-emoji:smiling-face-with-sunglasses",
},
{ key: "too_hard", label: "太难了", icon: "fluent-emoji:exploding-head" },
{
key: "confusing",
label: "没看懂",
icon: "fluent-emoji:face-with-spiral-eyes",
},
{ key: "buggy", label: "题目有错", icon: "fluent-emoji:bug" },
{ key: "learned", label: "学到了", icon: "fluent-emoji:light-bulb" },
{ key: "interesting", label: "有意思", icon: "fluent-emoji:star-struck" },
{ key: "want_explain", label: "想听讲解", icon: "fluent-emoji:books" },
]