- 部署:JUDGE_STATE_DIR 不再强制设;删掉搬库脚本和只为搬库存在的自检、提醒 - 语言:Python3 / Python2 别名表删掉,normalizeLanguage 改名 parseLanguage - 旧链接:后台题单详情的跳转、用户列表 -last_login 的转换 - 旧页面:布置作业必须带 language(null = 没选);不再清旧版出题页草稿 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9e074f3ab8
commit
8427475337
23 files changed
+47
-386
No files matched your search
@@ -6,8 +6,6 @@
|
||||
* 所以内存态够用,不需要 Redis 同步。进程重启丢掉全部状态,两端重连后回到干净状态。
|
||||
*/
|
||||
|
||||
import { normalizeLanguage } from '@oj2/contract'
|
||||
|
||||
export type CollabSocket = Bun.ServerWebSocket<import('../websocket').SubmissionSocketData>
|
||||
|
||||
/**
|
||||
@@ -19,14 +17,10 @@ export const COLLAB_LANGUAGES = ['C', 'C++', 'Python', 'Java', 'JavaScript', 'Go
|
||||
export type CollabLanguage = (typeof COLLAB_LANGUAGES)[number]
|
||||
|
||||
/**
|
||||
* 认不出来的一律当 C:老客户端不带这个字段,而它以前就是写死 C 的。
|
||||
*
|
||||
* 先过契约的别名表 —— 上线那一刻学生页面里还揣着 `Python3`,不翻译的话会**静默**
|
||||
* 落到 C,求助窗口里的代码高亮和同步编辑都按 C 走,没人会报错。
|
||||
* 认不出来的一律当 C。
|
||||
*/
|
||||
export function normalizeCollabLanguage(value: unknown): CollabLanguage {
|
||||
const normalized = normalizeLanguage(value) ?? value
|
||||
return (COLLAB_LANGUAGES as readonly string[]).includes(normalized as string) ? (normalized as CollabLanguage) : 'C'
|
||||
return (COLLAB_LANGUAGES as readonly string[]).includes(value as string) ? (value as CollabLanguage) : 'C'
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1327,8 +1327,7 @@ export const classLesson = pgTable(
|
||||
createdBy: integer('created_by').notNull(),
|
||||
/**
|
||||
* 这天第一次布置的时刻,之后「改」只动 updatedAt。清掉(删行)再布置算重新开始。
|
||||
* 加这一列之前布置的用 updated_at 回填(0034)。带默认值是给共库的另一个站点:
|
||||
* 机房那套还没升级时,它的旧代码插入不带这一列
|
||||
* 加这一列之前布置的用 updated_at 回填(0034)
|
||||
*/
|
||||
createdAt: timestamp('created_at', {
|
||||
withTimezone: true,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { normalizeLanguage } from '@oj2/contract'
|
||||
|
||||
/**
|
||||
* 判题沙箱认得的语言,**只有 C / C++ / Python 这三种**。
|
||||
*
|
||||
@@ -11,8 +9,7 @@ import { normalizeLanguage } from '@oj2/contract'
|
||||
* 想恢复某种语言,得同时改这里和 `docker/judge/Dockerfile` 的工具链,再重建镜像。
|
||||
*
|
||||
* `Python` 这个键 2026-09 之前叫 `Python3`(库里还有 3 条更老的 `Python2`),
|
||||
* 0019 迁移把数据并成了一个值。查配置一律走 `judgeConfigFor()`,别直接下标 ——
|
||||
* 那里带着旧值的别名,迁移之前排进队列的任务、旧客户端传上来的值都还能判。
|
||||
* 0019 迁移把数据并成了一个值。
|
||||
*
|
||||
* SQL 题不走这里,走 `judge/sql/`;流程图题走 AI 评分。
|
||||
*/
|
||||
@@ -84,10 +81,7 @@ export const languageConfigs: Record<string, Record<string, unknown>> = {
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* 按语言取判题配置。**判题侧一律走这个函数**,不要直接 `languageConfigs[x]`:
|
||||
* 它先过 `normalizeLanguage()`,所以 `Python3` / `Python2` 这类旧值也能命中。
|
||||
*/
|
||||
/** 按语言取判题配置,判题机不认的语言(Java 等历史值、SQL、流程图)返回 null */
|
||||
export function judgeConfigFor(language: string) {
|
||||
return languageConfigs[language] ?? languageConfigs[normalizeLanguage(language) ?? ''] ?? null
|
||||
return languageConfigs[language] ?? null
|
||||
}
|
||||
@@ -733,8 +733,7 @@ classroomRoutes.put('/classroom/lesson', requireTeacher, async (c) => {
|
||||
const parsed = await parseBody(c, classLessonRequestSchema, '题号或语言不对')
|
||||
if (!parsed.success) return parsed.response
|
||||
const user = c.get('user')!
|
||||
const { className, problemDisplayIds } = parsed.data
|
||||
const language = parsed.data.language ?? null
|
||||
const { className, problemDisplayIds, language } = parsed.data
|
||||
const day = calendarDay()
|
||||
|
||||
const [exists] = await db.select({ id: schema.user.id }).from(schema.user).where(eq(schema.user.className, className)).limit(1)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
AST_SUPPORTED_LANGUAGES,
|
||||
isSqlProblem,
|
||||
normalizeLanguage,
|
||||
parseLanguage,
|
||||
problemListSortSchema,
|
||||
problemTypeFilterSchema,
|
||||
type ChallengeList,
|
||||
@@ -142,9 +142,8 @@ problemRoutes.get('/problems', optionalAuth, async (c) => {
|
||||
if (undone && states && states.solved.size > 0) filters.push(notInArray(schema.problem.id, [...states.solved]))
|
||||
|
||||
const where = and(...filters)
|
||||
// 排序值沿用原来的(地址栏里存着的旧链接照样能用),但「最多 / 最少」现在按**人数**排,
|
||||
// 和列表最后一列「做对 / 做过」对得上:submission_number 是做过的人,accepted_number 是做对的人。
|
||||
// 旧的「画流程图 / 语法检查」排序已经拆成类型筛选,传进来落到默认(最新创建)
|
||||
// 「最多 / 最少」按**人数**排,和列表最后一列「做对 / 做过」对得上:
|
||||
// submission_number 是做过的人,accepted_number 是做对的人。认不出的排序值落到默认(最新创建)
|
||||
const sort = problemListSortSchema.safeParse(c.req.query('sort') ?? '').data ?? ''
|
||||
const byPeople = sort.endsWith('submission_number') || sort.endsWith('accepted_number')
|
||||
const allCounts = byPeople ? await allProblemUserCounts() : null
|
||||
@@ -231,7 +230,7 @@ problemRoutes.get('/problems/random', optionalAuth, async (c) => {
|
||||
const type = problemTypeFilterSchema.safeParse(c.req.query('type')).data
|
||||
// 上次用的是 SQL(刚做完一道 SQL 题)不算偏好:SQL 题一共 9 道,照它挑就成了「随便来一道
|
||||
// SQL」。要 SQL 题的人会选「SQL」知识点或类型,那时按上面说的照样抽得到
|
||||
const saved = normalizeLanguage(c.req.query('language'))
|
||||
const saved = parseLanguage(c.req.query('language'))
|
||||
const language = saved && saved !== 'SQL' && saved !== 'Flowchart' ? saved : 'Python'
|
||||
const states = user ? await problemStates(user.id) : null
|
||||
const solved = states ? [...states.solved] : []
|
||||
|
||||
@@ -233,14 +233,12 @@ export function getUserList(
|
||||
className = '',
|
||||
) {
|
||||
return api.get<AdminUserList>('admin/users', {
|
||||
// "-last_login" 是旧接口传下来的取值(路由 query 里可能还存着),改叫 "-lastLogin";
|
||||
// "-online" 是新增的,原样透传
|
||||
params: {
|
||||
offset,
|
||||
limit,
|
||||
keyword,
|
||||
type,
|
||||
orderBy: orderBy === '-last_login' ? '-lastLogin' : orderBy,
|
||||
orderBy,
|
||||
className: className || undefined,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -521,8 +521,6 @@ function clearDraft() {
|
||||
}
|
||||
|
||||
function loadDraft() {
|
||||
// 旧版出题页的草稿(另一个 key、另一种形状)不认了
|
||||
localStorage.removeItem(STORAGE_KEY.ADMIN_PROBLEM)
|
||||
const saved = draft.value
|
||||
// 草稿是本机存的,形状不对(旧版本、被别的页面写坏)就当没有,别让整页起不来
|
||||
if (saved && typeof saved.form === 'object' && Array.isArray(saved.rows)) {
|
||||
|
||||
@@ -67,7 +67,7 @@ const adminOptions = [
|
||||
const sortOptions = [
|
||||
{ label: '最近建号', value: '' },
|
||||
{ label: '按用户名', value: 'username' },
|
||||
{ label: '最近登录', value: '-last_login' },
|
||||
{ label: '最近登录', value: '-lastLogin' },
|
||||
{ label: '在线优先', value: '-online' },
|
||||
]
|
||||
const [create, toggleCreate] = useToggle(false)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { normalizeLanguage } from '@oj2/contract'
|
||||
import { parseLanguage } from '@oj2/contract'
|
||||
import { defineStore } from 'pinia'
|
||||
import { STORAGE_KEY } from 'utils/constants'
|
||||
import storage from 'utils/storage'
|
||||
@@ -9,7 +9,7 @@ import type { Code, LANGUAGE } from 'utils/types'
|
||||
* 管理全局的代码、输入、输出状态
|
||||
*/
|
||||
function savedCodeLanguage() {
|
||||
const saved = normalizeLanguage(storage.get(STORAGE_KEY.LANGUAGE))
|
||||
const saved = parseLanguage(storage.get(STORAGE_KEY.LANGUAGE))
|
||||
return saved && saved !== 'Flowchart' ? saved : null
|
||||
}
|
||||
|
||||
@@ -17,9 +17,6 @@ export const useCodeStore = defineStore('code', () => {
|
||||
// ==================== 状态 ====================
|
||||
const code = reactive<Code>({
|
||||
value: '',
|
||||
// 过一道 normalizeLanguage:上线那一刻学生浏览器的 localStorage 里存的还是
|
||||
// 旧值 Python3,直接拿来用会被后端的契约挡掉(而且报错看不出是这个原因)
|
||||
// 以前的版本会把 Flowchart 也记成语言偏好,那种老值在这里一并不认
|
||||
language: savedCodeLanguage() ?? 'Python',
|
||||
})
|
||||
|
||||
|
||||
@@ -330,15 +330,6 @@ export const admins: RouteRecordRaw = {
|
||||
props: true,
|
||||
meta: { requiresTeacherAdmin: true },
|
||||
},
|
||||
// 原来的「详情」页(题目 / 奖章 / 进度三个页签)并进了一屏编辑,老链接转过去
|
||||
{
|
||||
path: 'problemset/:problemSetId',
|
||||
name: 'admin problemset detail',
|
||||
redirect: (to) => ({
|
||||
name: 'admin problemset edit',
|
||||
params: { problemSetId: to.params.problemSetId },
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: 'ai/reports',
|
||||
name: 'admin ai reports',
|
||||
|
||||
@@ -152,7 +152,6 @@ export const STORAGE_KEY = {
|
||||
ACCESS_TOKEN: 'accessToken',
|
||||
REFRESH_TOKEN: 'refreshToken',
|
||||
LANGUAGE: 'problemLanguage',
|
||||
ADMIN_PROBLEM: 'adminProblem',
|
||||
ADMIN_SQL_PROBLEM: 'adminSqlProblem',
|
||||
ADMIN_CODE_PROBLEM: 'adminCodeProblem',
|
||||
ADMIN_PROBLEM_TAGS: 'adminProblemTags',
|
||||
|
||||
Reference in new issue
Block a user