fix(exam): 考试组已交卷禁止再进入与重复提交(4006 门控)

This commit is contained in:
2026-09-30 15:46:43 +08:00
parent a2e24aba2a
commit d44d466a90

View File

@@ -216,6 +216,20 @@ class ExamController extends Controller {
return; return;
} }
// 🔴 已正式交卷禁止再次进入(考试组一次性答题,测试反馈 #3)。
// 这里是「进入考试」的真实门控:题目经此下发,拒绝即等于无法进入答题界面,
// 前端按钮置灰只是 UX 层,绕过前端直调本接口同样被拦。
// hasSubmitted 仅在 exam_submissions.submit_time 落库后为 true ⇒
// 未交卷的意外退出(断网/断电)不受影响,仍可重进恢复作答。
// 仅约束考试组;本科/教师走作品提交,不在此限制。
if (group === 'zhongzhi' || group === 'gaozhi') {
const alreadySubmitted = await service.exam.hasSubmitted(aggregation.aggregation_uid, group);
if (alreadySubmitted) {
ctx.body = ctx.helper.error(4006, '您已提交试卷,无法再次进入考试');
return;
}
}
// 团队锁:同一小组只能一人进入正式考试(原子检查+占位,G1 修复) // 团队锁:同一小组只能一人进入正式考试(原子检查+占位,G1 修复)
const teamGate = await this._enterExamWithTeamLock(aggregation); const teamGate = await this._enterExamWithTeamLock(aggregation);
if (!teamGate.allowed) { if (!teamGate.allowed) {
@@ -852,6 +866,19 @@ class ExamController extends Controller {
} }
} }
// 🔴 窗口内重复交卷拦截(考试组,测试反馈 #3)。
// 背景:下方窗口内分支会重新校验请求体答案并覆盖写库 ⇒ 已交卷者若可重进,
// 即可「改答案 → 再交卷」无损刷分。入口 questions() 已拦重进,此处再堵住
// 绕过前端直接重放 submit-all 的路径。
// ⚠️ 只作用于窗口打开时;窗口关闭后走上方结算通道(那是补写标记,不是重新作答)。
if (windowOpen && (group === 'zhongzhi' || group === 'gaozhi')) {
const alreadyDone = await service.exam.hasSubmitted(aggregation.aggregation_uid, group);
if (alreadyDone) {
ctx.body = ctx.helper.error(4006, '您已提交试卷,不能重复提交');
return;
}
}
// 团队锁:同一小组只能一人进入正式考试(G1 修复,防绕过 questions 直接提交) // 团队锁:同一小组只能一人进入正式考试(G1 修复,防绕过 questions 直接提交)
// ⚠️ 结算通道跳过:一是窗口已关闭不应再产生 setTeamLock 写副作用, // ⚠️ 结算通道跳过:一是窗口已关闭不应再产生 setTeamLock 写副作用,
// 二是结算绝不能被队友残留锁拦下(否则又回到「答案在库却交不上」)。 // 二是结算绝不能被队友残留锁拦下(否则又回到「答案在库却交不上」)。