feat(提交结果): 没通过时显示「通过 x/y 个测试点」;编译失败不等三次就能用 AI 分析
Some checks failed
Deploy / deploy (push) Has been cancelled
Some checks failed
Deploy / deploy (push) Has been cancelled
学生拿不到 info(每个点带 output_md5,只给管理员),测试点表格从来只有管理员看得见, 学生这边只有一句「答案错误」—— 从 2/8 交到 6/8 的人,感受是连输五次。 - 提交详情新增 caseSummary,后端从 info 数出通过数下发,不放开原文。 比赛提交、SQL 题(被杀的测试点会 break,total 偏小)、无逐点结果时为 null - 结果面板标题缀上通过数并加进度条,提交详情页标题同步;一个都没过时不缀 - POST /ai/hint 对编译失败跳过失败次数门槛,throttleAi 照旧;前端显示条件同口径 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013TecwAowmYcoNZRheSyTgH
This commit is contained in:
@@ -502,8 +502,12 @@ aiRoutes.post("/ai/hint", requireAuth, async (c) => {
|
||||
// 不然这就是个不限次数的免费 LLM 接口。数法(判题中的不算、判题机自己崩的不算)
|
||||
// 由 countFailedSubmissions 统一,题目详情的 myFailedCount 走的是同一个函数,
|
||||
// 所以前端亮出按钮的时刻和这里放行的时刻严格对齐。
|
||||
const failed = await countFailedSubmissions(c.get("user")!.id, row.submission.problemId)
|
||||
if (failed < HINT_MIN_FAILURES) return failure(c, 403, "hint-locked", `Hint unlocks after ${HINT_MIN_FAILURES} failed submissions`)
|
||||
// 编译失败不数次数(理由见 HINT_MIN_FAILURES 的注释)。放开的只是这一次提交本身,
|
||||
// 下面的 throttleAi 照样卡着,不会因此变成不限次数的接口。
|
||||
if (row.submission.result !== JudgeStatus.COMPILE_ERROR) {
|
||||
const failed = await countFailedSubmissions(c.get("user")!.id, row.submission.problemId)
|
||||
if (failed < HINT_MIN_FAILURES) return failure(c, 403, "hint-locked", `Hint unlocks after ${HINT_MIN_FAILURES} failed submissions`)
|
||||
}
|
||||
const limited = await throttleAi(c)
|
||||
if (limited) return limited
|
||||
// 这里**不要**把 problem.answers 的参考答案放进 prompt。学生的代码本身就是 prompt 的
|
||||
|
||||
@@ -813,6 +813,18 @@ const submissionListColumns = {
|
||||
},
|
||||
} as const
|
||||
|
||||
/**
|
||||
* 从判题原文里数出通过的测试点,为 null 的情形见契约 `caseSummary` 的注释。
|
||||
* 这里只信「有没有 data 数组」,数组项的形状信判题机,和前端 submissionCaseResults 同口径。
|
||||
*/
|
||||
function caseSummary(submission: typeof schema.submission.$inferSelect) {
|
||||
if (submission.contestId !== null || submission.language === "SQL") return null
|
||||
const data = objectValue(submission.info).data
|
||||
if (!Array.isArray(data) || data.length === 0) return null
|
||||
const passed = data.filter((item) => objectValue(item).result === JudgeStatus.ACCEPTED).length
|
||||
return { passed, total: data.length }
|
||||
}
|
||||
|
||||
async function submissionDetail(id: string, user: AuthUser) {
|
||||
const [row] = await db.select({ submission: schema.submission, problem: schema.problem, contest: schema.contest })
|
||||
.from(schema.submission)
|
||||
@@ -846,6 +858,7 @@ async function submissionDetail(id: string, user: AuthUser) {
|
||||
// problem 表本来就 join 了,不额外查库
|
||||
problemDisplayId: row.problem.displayId,
|
||||
showLink: true,
|
||||
caseSummary: caseSummary(row.submission),
|
||||
} satisfies SubmissionDetail
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user