feat: add manual confirmation toggle for incomplete exams
This commit is contained in:
+29
-4
@@ -22,7 +22,7 @@
|
||||
bankTotal: 0, roleCounts: {}, storageMode: 'userscript', pageStatus: '等待识别题目页面', pageMode: '',
|
||||
canAnswer: false, canExport: false, metrics: {}, exportEnabled: false, expanded: false, loading: false, position: null,
|
||||
activeTab: 'overview', uniqueTotal: 0, conflictTotal: 0,
|
||||
learning: { status: 'idle', mode: 'all', execution: 'sequential', rate: 1, answerInterval: 4, minSubmitMinutes: 6, tasks: [], total: 0, completed: 0, skipped: 0, waiting: 0, failed: 0, etaSeconds: null, video: {}, exam: {}, logs: [], message: '' }
|
||||
learning: { status: 'idle', mode: 'all', execution: 'sequential', rate: 1, answerInterval: 4, minSubmitMinutes: 6, manualConfirmIncomplete: true, tasks: [], total: 0, completed: 0, skipped: 0, waiting: 0, failed: 0, etaSeconds: null, video: {}, exam: {}, logs: [], message: '' }
|
||||
};
|
||||
let destroyed = false;
|
||||
let selectionText = '';
|
||||
@@ -440,6 +440,16 @@
|
||||
});
|
||||
return input;
|
||||
}
|
||||
function learningSwitch(container, key, label, fallback) {
|
||||
const control = makeSwitch(label, function () {
|
||||
state.learning[key] = control.input.checked;
|
||||
invoke('onLearningSetting', key, control.input.checked);
|
||||
refreshLearning();
|
||||
}, container);
|
||||
control.input.setAttribute('data-testid', 'setting-' + key);
|
||||
learningControls[key] = { input: control.input, fallback: fallback, switch: true };
|
||||
return control.input;
|
||||
}
|
||||
function taskButton(container, label, action, className) {
|
||||
const button = el(doc, 'button', className || '', label); button.type = 'button';
|
||||
button.setAttribute('data-testid', 'task-' + action);
|
||||
@@ -483,13 +493,17 @@
|
||||
const examModeNote = el(doc, 'p', 'mode-note'); examIntro.appendChild(examModeNote);
|
||||
learningSetting(examIntro, 'answerInterval', '答题间隔(秒)', null, 4, [0, 120, 0.5]);
|
||||
learningSetting(examIntro, 'minSubmitMinutes', '最早交卷(分)', null, 6, [0.5, 180, 0.5]);
|
||||
learningSwitch(examIntro, 'manualConfirmIncomplete', '题目不全时手动确认', true);
|
||||
const examInfo = el(doc, 'dl', 'info-grid');
|
||||
const examMessage = el(doc, 'p', 'explanation');
|
||||
const examThreshold = el(doc, 'p', 'threshold');
|
||||
const incompleteHint = el(doc, 'p', 'hint');
|
||||
examThreshold.setAttribute('data-testid', 'exam-threshold');
|
||||
incompleteHint.setAttribute('data-testid', 'incomplete-confirmation-hint');
|
||||
const examActions = el(doc, 'div', 'task-actions');
|
||||
const examPause = taskButton(examActions, '暂停考试任务', 'examPause');
|
||||
const examResume = taskButton(examActions, '继续考试任务', 'examResume');
|
||||
examIntro.append(examInfo, el(doc, 'p', 'threshold', '预计得分必须严格大于 80 分;正好 80 分等待人工。'), examMessage, examActions,
|
||||
el(doc, 'p', 'hint', '仅已精确匹配、点击并核验完整答案文字的题目计分。进入原试卷满设定时长、核验完成且满足条件后才自动交卷;预计分数以本地题库为依据。练习与课中题不使用考试交卷门槛。'));
|
||||
examIntro.append(examInfo, examThreshold, examMessage, examActions, incompleteHint);
|
||||
views.exam.insertBefore(examIntro, switches);
|
||||
|
||||
const bankCounts = el(doc, 'p', 'bank-counts'); bankSection.appendChild(bankCounts);
|
||||
@@ -692,8 +706,17 @@
|
||||
}
|
||||
Object.keys(learningControls).forEach(function (key) {
|
||||
const setting = learningControls[key];
|
||||
if (root.activeElement !== setting.input) setting.input.value = plain(learning[key] == null ? setting.fallback : learning[key]);
|
||||
if (setting.switch) setting.input.checked = learning[key] == null ? setting.fallback : learning[key] !== false;
|
||||
else if (root.activeElement !== setting.input) setting.input.value = plain(learning[key] == null ? setting.fallback : learning[key]);
|
||||
});
|
||||
const manualConfirmIncomplete = learning.manualConfirmIncomplete !== false;
|
||||
setText(examThreshold, manualConfirmIncomplete
|
||||
? '必须整卷每题核验且预计得分严格大于 80 分;题目不全时由用户在原网页手动确认交卷。'
|
||||
: '允许题库部分缺题时自动交卷:已核验预计得分严格大于 80 分,所有可匹配题均已核验,且已满最早交卷时间。');
|
||||
setText(incompleteHint, (manualConfirmIncomplete
|
||||
? '本开关已开启:存在未匹配、冲突或未核验题时,即使超过 80 分、已满交卷时长也不自动交卷;网页提示未答完时同样等待人工。'
|
||||
: '本开关已关闭:仅已精确匹配、点击并核验完整答案文字的题目计分,其余题目不计分;满足得分、计时与当前试卷核验条件后可自动交卷。')
|
||||
+ '切换会暂停当前计划,请在任务总览点击继续重新核验。无论开关状态,试卷未完整加载均禁止自动交卷;预计得分正好 80 分等待人工。练习与课中题不使用考试交卷门槛。');
|
||||
const videoEnabled = learning.mode !== 'exam';
|
||||
setText(videoModeNote, videoEnabled ? '' : '本模式未启用视频;可查看设置与记录。'); videoModeNote.hidden = videoEnabled;
|
||||
const examEnabled = learning.mode === 'exam' || learning.mode === 'all' || !learning.mode;
|
||||
@@ -709,6 +732,8 @@
|
||||
videoPause.disabled = !videoHasTask || ['paused', 'completed', 'done', 'idle'].includes(video.status || 'idle');
|
||||
videoResume.disabled = !videoHasTask || !['paused', 'waiting', 'waitingHuman', 'failed', 'error'].includes(video.status);
|
||||
infoRows(examInfo, [['考试主题', examTitle], ['题库预检', plain(firstValue(exam, ['preflightMessage', 'themeStatus', 'preflight'], '尚未预检'))],
|
||||
['全文核验', exam.total == null ? '待确认' : plain(exam.verifiedCount || 0) + ' / ' + plain(exam.total) + ' 题'],
|
||||
['交卷确认', exam.submitted || exam.status === 'submitted' ? '网站已确认交卷' : exam.requiresManualSubmission ? '题目未全部核验或网站提示未答完,请在原网页手动确认' : manualConfirmIncomplete ? '整卷每题核验后才按条件自动交卷' : '已核验得分超过 80 分并满最早交卷时间后才按条件自动交卷'],
|
||||
['预计得分', firstValue(exam, ['predictedScore', 'score'], null) == null ? '待核算' : plain(firstValue(exam, ['predictedScore', 'score'], 0)) + ' 分(题库估计)'],
|
||||
['网页剩余', duration(firstValue(exam, ['remainingSeconds', 'remainingTime'], null))], ['进入试卷', duration(firstValue(exam, ['elapsedSeconds', 'elapsedTime'], null))],
|
||||
['最早交卷', duration(firstValue(exam, ['submitWaitSeconds', 'waitSeconds'], null))], ['交卷状态', statusName(exam.status || 'idle')]]);
|
||||
|
||||
Reference in New Issue
Block a user