Files
IOT_SIM/server/src/grading/selfcheck.ts
T
xuyueandClaude Opus 5.5 f256b313f7 实验页"评价项"和自测:提交前自己检查,不计分
- 工具栏"评价项"打开侧栏,列出自动检查的功能项(作业显示布置时的规则和各项分值)
- "自己检查"在服务器上按评分规则运行学生现在的程序,逐项显示通过与否和原因;不计分、不留记录,
  自由练习和作业都能用;每人同时一次,结果保留到下一次,之后改过代码提示结果可能过时;
  和提交评分共用全站并发上限
- 实验的评价项接口学生也能用(老师布置作业的对话框改用它)
- 修正:运行区的窗体和"放大"按钮会盖住网页的抽屉和对话框

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 18:35:25 +08:00

42 lines
1.6 KiB
TypeScript

// 自测:学生提交前自己跑一遍评分,告诉他哪几项不通过、为什么;不计分、不留记录。
// 每人同时只能有一次,结果放在内存里,保留到下一次自测(服务器重启后就没有了)。
// 检查项和提交评分一样受全站并发上限(grader.ts 的 GRADE_CONCURRENCY)约束,机器忙时排队。
import type { SelfCheck, SourceFile } from '@iot/shared'
import { rm } from 'node:fs/promises'
import { join } from 'node:path'
import { config } from '../config'
import type { Check } from './checks'
import { grade } from './grader'
import { writeProject } from './queue'
export function createSelfCheck() {
const states = new Map<number, SelfCheck>()
return {
/** 开始自测;上一次还没完成时返回 false */
start(userId: number, target: string, files: SourceFile[], checks: Check[], sampleId: string): boolean {
if (states.get(userId)?.status === 'running') return false
const state: SelfCheck = { status: 'running', target, result: null, startedAt: Date.now() }
states.set(userId, state)
const dir = join(config.runsDir, `selfcheck-${userId}`)
void (async () => {
try {
await writeProject(dir, files)
state.result = await grade(dir, checks, sampleId)
state.status = 'done'
} catch (error) {
console.error(`自测出错(用户 ${userId}):`, error)
state.status = 'error'
} finally {
await rm(dir, { recursive: true, force: true })
}
})()
return true
},
get(userId: number): SelfCheck | null {
return states.get(userId) ?? null
},
}
}