fix: resume video playback and advance linked exams with attempt controls
This commit is contained in:
+28
-1
@@ -100,8 +100,24 @@
|
||||
}
|
||||
function settings() { return options.getSettings ? options.getSettings() : {}; }
|
||||
function manualIncomplete() { return settings().manualConfirmIncomplete !== false; }
|
||||
function attemptPolicy() {
|
||||
const policy = (options.getAttemptPolicy ? options.getAttemptPolicy() : root.YianAttemptPolicy?.read(doc.querySelector('app-examdetail,app-examtest,.pc_examtest'))) || {};
|
||||
const active = settings().skipSingleAttemptQuiz !== false;
|
||||
return { active, blocked: active && policy.blocked === true, count: policy.count == null ? null : policy.count,
|
||||
reason: clean(policy.reason) || '仅有 1 次答题机会,已停止自动答题与交卷,请在原网页人工操作',
|
||||
signature: active ? JSON.stringify([policy.signature || '', policy.blocked === true, policy.count == null ? null : policy.count]) : '' };
|
||||
}
|
||||
function blockSingleAttempt(policy) {
|
||||
generation++; enabled = false;
|
||||
if (['submitting', 'confirming', 'unknown'].includes(stage)) stage = 'unknown';
|
||||
else stage = 'waiting';
|
||||
error = policy.reason;
|
||||
return emit({ skipSingleAttemptQuiz: policy.active, singleAttemptBlocked: true, attemptCount: policy.count,
|
||||
requiresManualSubmission: true, message: error });
|
||||
}
|
||||
function scopeValue(ctx, evidence, topic) {
|
||||
return JSON.stringify([keyFor(ctx), ctx.revision, evidence.signature, topic?.courses, manualIncomplete()]);
|
||||
const policy = attemptPolicy();
|
||||
return JSON.stringify([keyFor(ctx), ctx.revision, evidence.signature, topic?.courses, manualIncomplete(), policy.active, policy.signature]);
|
||||
}
|
||||
function resultVisible() {
|
||||
return Array.from(doc.querySelectorAll('.exam_submited_box,.exam-result,app-exam-result,[data-exam-result]'))
|
||||
@@ -156,8 +172,12 @@
|
||||
async function enable() {
|
||||
const token = ++generation, requested = context();
|
||||
enabled = false;
|
||||
const initialPolicy = attemptPolicy();
|
||||
if (initialPolicy.blocked) { blockSingleAttempt(initialPolicy); return false; }
|
||||
await observe();
|
||||
if (token !== generation || !sameContext(requested, context()) || !entry || ['submitting', 'confirming', 'unknown'].includes(stage) || destroyed || resultVisible()) return false;
|
||||
const currentPolicy = attemptPolicy();
|
||||
if (currentPolicy.blocked) { blockSingleAttempt(currentPolicy); return false; }
|
||||
if (entry.manualRequired && stage !== 'awaitingAttempt' && manualIncomplete()) {
|
||||
stage = 'waiting'; error = '网站提示存在未作答题,请在原网页手动确认交卷';
|
||||
emit({ requiresManualSubmission: true, message: error }); return false;
|
||||
@@ -176,6 +196,8 @@
|
||||
if (!manualIncomplete() && entry.manualRequired) { entry.manualRequired = false; entry.confirmed = false; delete entry.submitAt; }
|
||||
scope = scopeValue(ctx, evidence, topic);
|
||||
enabled = true; stage = 'answering'; error = ''; entry.stage = stage; entry.paperSignature = evidence.signature; await persist();
|
||||
const finalPolicy = attemptPolicy();
|
||||
if (token === generation && finalPolicy.blocked) { blockSingleAttempt(finalPolicy); return false; }
|
||||
if (token !== generation || destroyed || !enabled || !sameContext(ctx, context()) || !context().ready || options.getTopic()?.status !== 'matched' || scope !== scopeFor(context())) {
|
||||
if (token === generation) disable('启动过程中页面、题库或任务状态已变化,请重新启动'); return false;
|
||||
}
|
||||
@@ -196,6 +218,8 @@
|
||||
}
|
||||
function canClick(token, ctx, confirmation) {
|
||||
if (token !== generation || destroyed || !enabled || !sameContext(ctx, context())) return false;
|
||||
const policy = attemptPolicy();
|
||||
if (policy.blocked) { blockSingleAttempt(policy); return false; }
|
||||
const current = context(), topic = options.getTopic(), evidence = readPaper(doc, current, options.getSnapshot(), topic);
|
||||
const configured = Number(settings().minSubmitMinutes), minimum = Number.isFinite(configured) && configured > 0 ? configured * 60 : 360;
|
||||
const pendingTooLong = confirmation && now() - entry.submitAt > 12000;
|
||||
@@ -234,6 +258,7 @@
|
||||
return emit({ message: '网站已显示考试结果', submitted: true, requiresManualSubmission: false });
|
||||
}
|
||||
const topic = options.getTopic(), evidence = readPaper(doc, ctx, options.getSnapshot(), topic);
|
||||
const policy = attemptPolicy();
|
||||
const elapsedSeconds = Math.max(0, (now() - entry.startedAt) / 1000);
|
||||
const configured = Number(settings().minSubmitMinutes);
|
||||
const minimum = Number.isFinite(configured) && configured > 0 ? configured * 60 : 360;
|
||||
@@ -243,8 +268,10 @@
|
||||
entry.lastObservedAt = now(); entry.lastRemaining = remaining;
|
||||
emit(Object.assign({}, evidence, { elapsedSeconds: Math.floor(elapsedSeconds), waitSeconds, remainingSeconds: remaining,
|
||||
manualConfirmIncomplete: manualIncomplete(),
|
||||
skipSingleAttemptQuiz: policy.active, singleAttemptBlocked: policy.blocked, attemptCount: policy.count,
|
||||
requiresManualSubmission: manualIncomplete() && (Boolean(entry.manualRequired) || runner === 'complete' && !evidence.fullyVerified),
|
||||
predictedScore: Math.round(evidence.predictedScore * 100) / 100, submitted: false, message: error || evidence.reason }));
|
||||
if (policy.blocked) return blockSingleAttempt(policy);
|
||||
if (!enabled) return last;
|
||||
if (scope !== scopeValue(ctx, evidence, topic) || topic?.status !== 'matched') {
|
||||
disable('试卷、题库或主题关联已变更,请重新启动核验'); return last;
|
||||
|
||||
Reference in New Issue
Block a user