fix: retain question images and repair evidenced legacy records

This commit is contained in:
suanyuit-cyber
2026-10-29 22:40:38 +08:00
parent 15fa009f9e
commit c3edf3975e
45 changed files with 2778 additions and 103 deletions
+10 -5
View File
@@ -9,6 +9,10 @@ const QBAuto = (() => {
const sorted = values => [...values].sort();
const optionSet = question => JSON.stringify(sorted(question.options.map(option => optionKey(option.text, question.type))));
const localCore = supplied => supplied || (typeof QBCore !== 'undefined' ? QBCore : typeof require === 'function' ? require('./core.js') : null);
const richText = value => {
const adapter = typeof QBAdapter !== 'undefined' ? QBAdapter : typeof require === 'function' ? require('./adapter.js') : null;
return adapter ? adapter.richText(value) : tidy(value && typeof value === 'object' ? value.textContent : value);
};
function planAnswer(records, current, suppliedCore) {
const result = (status, message, more = {}) => ({ status, message, labels: [], answerTexts: [], ...more });
@@ -19,7 +23,8 @@ const QBAuto = (() => {
catch (_) { return result('unsupported', '当前题目结构不完整,已跳过。'); }
if (!['single', 'multiple', 'judge'].includes(question.type) || question.options.length < 2 || question.options.length > 100) return result('unsupported', '当前题型暂不支持自动选择。');
const contents = question.options.map(option => optionKey(option.text, question.type));
if (new Set(contents).size !== contents.length || new Set(question.options.map(option => option.label)).size !== question.options.length) return result('ambiguous', '当前选项文字或标记重复,无法唯一对应,已跳过。');
// Multiple-choice repeated text is checked against explicit correct IDs by mapAnswers.
if ((question.type !== 'multiple' && new Set(contents).size !== contents.length) || new Set(question.options.map(option => option.label)).size !== question.options.length) return result('ambiguous', '当前选项文字或标记重复,无法唯一对应,已跳过。');
const relevant = [];
for (const input of records) {
let record;
@@ -78,13 +83,13 @@ const QBAuto = (() => {
if (!label) label = input.closest('label');
if (label) {
const rich = label.querySelector('.yxtf-radio__label [data-rich-text], .yxtf-checkbox__label [data-rich-text]');
if (rich) return tidy(rich.textContent);
if (rich) return richText(rich);
const clone = (label.querySelector('.yxtf-radio__label, .yxtf-checkbox__label') || label).cloneNode(true);
clone.querySelectorAll('input,button,script,style').forEach(node => node.remove());
return tidy(clone.textContent).replace(/^(?:[A-Z][.、.)::]|\[[A-Z]\])\s*/u, '');
return richText(clone).replace(/^(?:[A-Z][.、.)::]|\[[A-Z]\])\s*/u, '');
}
const labelled = tidy(input.getAttribute('aria-labelledby')).split(/\s+/u).filter(Boolean).map(id => doc.getElementById(id)).filter(node => node && container.contains(node));
return tidy(labelled.length ? labelled.map(node => node.textContent).join(' ') : input.getAttribute('aria-label'));
return tidy(labelled.length ? labelled.map(node => richText(node)).join(' ') : input.getAttribute('aria-label'));
}
function controls(container, site) {
const selector = site ? '.yxtulcdsdk-ques-radio input[type="radio"],.yxtulcdsdk-ques-checkbox input[type="checkbox"]' : 'input[type="radio"],input[type="checkbox"]';
@@ -113,7 +118,7 @@ const QBAuto = (() => {
if (!set) return null;
const titles = [...container.querySelectorAll(':scope > legend, :scope > .question-title, :scope > [data-question-title], :scope > .question-stem, :scope > .stem, :scope > h2, :scope > h3, :scope > p')].filter(node => visible(node) && !node.querySelector('input'));
if (titles.length !== 1) return null;
const stem = tidy(titles[0].textContent);
const stem = richText(titles[0]);
if (!stem || stem.length > 100000) return null;
const judged = set.type === 'single' && set.texts.length === 2 && set.texts.map(judgeText).includes('正确') && set.texts.map(judgeText).includes('错误');
const type = judged ? 'judge' : set.type;