fix: 前端多选题不显示选项(multiple_choice 未渲染 options,补 checkbox 渲染、toggle 交互与判定)
Deploy Examination / deploy (push) Successful in 7s

This commit is contained in:
2026-09-03 15:03:17 +08:00
parent 12da7a6974
commit 8c97560a40
+56 -9
View File
@@ -156,6 +156,10 @@ body { font-family: -apple-system, 'Segoe UI', sans-serif; background: var(--bg)
.option.correct .radio::after { content: ''; width: 8px; height: 8px; border-radius: 50%; background: var(--green); }
.option.wrong .radio { border-color: var(--red); }
.option.wrong .radio::after { content: ''; width: 8px; height: 8px; border-radius: 50%; background: var(--red); }
.option .checkbox { width: 18px; height: 18px; border: 2px solid var(--surface2); border-radius: 4px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-size: 12px; color: white; transition: all 0.2s; }
.option.selected .checkbox { border-color: var(--accent); background: var(--accent); }
.option.correct .checkbox { border-color: var(--green); background: var(--green); }
.option.wrong .checkbox { border-color: var(--red); background: var(--red); }
/* Actions */
.actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-top: 4px; }
@@ -508,19 +512,33 @@ function renderQuestionCard(q, i) {
html += `</div>`;
// Options for single_choice
if (q.type === 'single_choice' && q.options) {
// Options for single_choice and multiple_choice
if ((q.type === 'single_choice' || q.type === 'multiple_choice') && q.options) {
const isMC = q.type === 'multiple_choice';
const selectedSet = isMC ? (state?.selected || []) : [];
html += `<div class="options">`;
for (const [letter, text] of Object.entries(q.options)) {
let optClass = '';
if (revealed) {
if (letter === q.answer) optClass = 'correct';
else if (state?.value === letter) optClass = 'wrong';
} else if (state?.value === letter) {
if (isMC) {
// multiple_choice: 'correct' = 答案里的正确项; 'wrong' = 用户误选的非正确项
const isCorrectAnswer = (q.answer || []).includes(letter);
const userSelected = selectedSet.includes(letter);
if (isCorrectAnswer) optClass = 'correct';
else if (userSelected) optClass = 'wrong';
} else {
if (letter === q.answer) optClass = 'correct';
else if (state?.value === letter) optClass = 'wrong';
}
} else if (isMC ? selectedSet.includes(letter) : state?.value === letter) {
optClass = 'selected';
}
html += `<div class="option ${optClass}" onclick="selectOption('${q.id}','${letter}')">
<div class="radio"></div>
const clickFn = isMC ? `toggleOption('${q.id}','${letter}')` : `selectOption('${q.id}','${letter}')`;
const marker = isMC
? `<div class="checkbox"><span>${selectedSet.includes(letter) ? '✓' : ''}</span></div>`
: `<div class="radio"></div>`;
html += `<div class="option ${optClass}" onclick="${clickFn}">
${marker}
<span><strong>${letter}.</strong> ${escapeHtml(text)}</span>
</div>`;
}
@@ -562,6 +580,19 @@ function selectOption(qId, letter) {
renderQuiz();
}
// Toggle an option for multiple_choice questions
function toggleOption(qId, letter) {
const q = currentQuestions.find(x => x.id === qId);
if (!q || q.type !== 'multiple_choice' || answers[qId]?.revealed) return;
const cur = answers[qId];
const selected = cur?.selected ? [...cur.selected] : [];
const idx = selected.indexOf(letter);
if (idx >= 0) selected.splice(idx, 1);
else selected.push(letter);
answers[qId] = { value: selected.join(','), selected, correct: false, revealed: false };
renderQuiz();
}
function saveFill(qId) {
const input = document.getElementById(`input-${qId}`);
if (!input) return;
@@ -611,6 +642,12 @@ function revealAnswer(qId) {
if (q.type === 'single_choice') {
answers[qId].correct = answers[qId].value === q.answer;
} else if (q.type === 'multiple_choice') {
const userSel = (answers[qId].selected || []).slice().sort();
const correctSel = (q.answer || []).slice().sort();
answers[qId].correct = userSel.length === correctSel.length &&
userSel.every((x, i) => x === correctSel[i]);
// 让多选选项未选中状态也能正确显示
}
answers[qId].revealed = true;
renderQuiz();
@@ -619,9 +656,14 @@ function revealAnswer(qId) {
function showAllAnswers() {
currentQuestions.forEach(q => {
if (!answers[q.id]?.revealed) {
if (!answers[q.id]) answers[q.id] = { value: '', correct: false };
if (!answers[q.id]) answers[q.id] = { value: '', selected: [], correct: false };
if (q.type === 'single_choice') {
answers[q.id].correct = answers[q.id].value === q.answer;
} else if (q.type === 'multiple_choice') {
const userSel = (answers[q.id].selected || []).slice().sort();
const correctSel = (q.answer || []).slice().sort();
answers[q.id].correct = userSel.length === correctSel.length &&
userSel.every((x, i) => x === correctSel[i]);
}
answers[q.id].revealed = true;
}
@@ -631,10 +673,15 @@ function showAllAnswers() {
function submitAll() {
currentQuestions.forEach(q => {
if (!answers[q.id]) answers[q.id] = { value: '', correct: false };
if (!answers[q.id]) answers[q.id] = { value: '', selected: [], correct: false };
if (!answers[q.id].revealed) {
if (q.type === 'single_choice') {
answers[q.id].correct = answers[q.id].value === q.answer;
} else if (q.type === 'multiple_choice') {
const userSel = (answers[q.id].selected || []).slice().sort();
const correctSel = (q.answer || []).slice().sort();
answers[q.id].correct = userSel.length === correctSel.length &&
userSel.every((x, i) => x === correctSel[i]);
} else if (q.type === 'fill_blank') {
answers[q.id].correct = matchFillAnswer(answers[q.id].value, q.answer, q.answer_rule || 'any');
}