fix: 填空题智能匹配(空格/逗号/小数) + 即时显示解析, exam模式同步修复

This commit is contained in:
hangshuo652
2026-06-29 13:32:35 +08:00
parent 0b9a2e4f23
commit 31a097c591
+55 -28
View File
@@ -956,13 +956,14 @@ function examCli(j){
if(kor)examScore++;examIdx++;setTimeout(showExamQ,400); if(kor)examScore++;examIdx++;setTimeout(showExamQ,400);
} }
function examCfil(){ function examCfil(){
let q=Q.find(x=>x.id===examQid[examIdx]);if(!q)return; let q=Q.find(function(x){return x.id===examQid[examIdx];});if(!q)return;
let v=$('eip')?$('eip').value.trim():'';if(!v)return; let v=$(('eip'))?$(('eip')).value.trim():'';if(!v)return;
let kor=v===q.ans; function n(s){return s.replace(/[\s,,、;;。..]+/g,",").replace(/^,+|,+$/g,"").replace(/,+/g,",").replace(/\s+/g,"").toLowerCase();}
let inp=$('eip');inp.disabled=true;inp.className='inp '+(kor?'ok':'no'); var kor=n(v)===n(q.ans);
if(!kor){var nv=parseFloat(v);var na=parseFloat(q.ans);if(!isNaN(nv)&&!isNaN(na)&&Math.abs(nv-na)<0.001)kor=true;}
var inp=$(('eip'));inp.disabled=true;inp.className='inp '+(kor?'ok':'no');
if(kor)examScore++;examIdx++;setTimeout(showExamQ,600); if(kor)examScore++;examIdx++;setTimeout(showExamQ,600);
} }function finishExam(){
function finishExam(){
if(examTimer){clearInterval(examTimer);examTimer=null;} if(examTimer){clearInterval(examTimer);examTimer=null;}
$('eh').className='exam-hdr'; $('eh').className='exam-hdr';
let pct=examQid.length?Math.round(examScore/examQid.length*100):0; let pct=examQid.length?Math.round(examScore/examQid.length*100):0;
@@ -1103,42 +1104,68 @@ function showFullExp(id){
cd.appendChild(fb);upd(); cd.appendChild(fb);upd();
} }
function cfil(id){ function cfil(id){
let q=Q.find(x=>x.id===id);if(!q)return; let q=Q.find(function(x){return x.id===id;});if(!q)return;
let v=$('ip'+id)?$('ip'+id).value.trim():'';if(!v)return; let v=$('ip'+id)?$('ip'+id).value.trim():'';if(!v)return;
let kor=(v===q.ans); // Normalize both input and answer for flexible comparison
function normalize(s){
return s.replace(/[\s,、;;。..]+/g,",").replace(/^,+|,+$/g,"").replace(/,+/g,",").replace(/\s+/g,"").toLowerCase();
}
let userNorm=normalize(v);
let ansNorm=normalize(q.ans);
// Support partial match for comma-separated answers
let kor=(userNorm===ansNorm);
if(!kor&&ansNorm.indexOf(",")>0){
let userParts=userNorm.split(",").filter(function(p){return p.length>0;});
let ansParts=ansNorm.split(",").filter(function(p){return p.length>0;});
if(userParts.length===ansParts.length){
var allMatch=true;
for(var pi=0;pi<ansParts.length;pi++){
if(userParts[pi]!==ansParts[pi]){allMatch=false;break;}
}
kor=allMatch;
}
}
// Also support mathematical equivalence for fraction/decimal
if(!kor){
var numV=parseFloat(v);
var numAns=parseFloat(q.ans);
if(!isNaN(numV)&&!isNaN(numAns)&&Math.abs(numV-numAns)<0.001)kor=true;
}
conv[id]=kor?q.ans:'__w__';recAns(id,kor);if(kor)AUDIO.correct();else AUDIO.wrong(); conv[id]=kor?q.ans:'__w__';recAns(id,kor);if(kor)AUDIO.correct();else AUDIO.wrong();
let inp=$('ip'+id);inp.disabled=true;inp.className='inp '+(kor?'ok':'no'); let inp=$('ip'+id);inp.disabled=true;inp.className='inp '+(kor?'ok':'no');
let br=inp.parentElement.querySelector('.br');if(br)br.remove(); let br=inp.parentElement.querySelector('.br');if(br)br.remove();
if(!kor){ // Always show explanation immediately (remove hint-first flow)
let m=meta[id]; let cd=inp.closest('.cd');
if(m&&m.h===0){ let existingFB=cd?cd.querySelector('.fb'):null;
m.h=1;let cd=inp.closest('.cd'); if(existingFB)existingFB.remove();
let ht=document.createElement('div');ht.className='ht sh';
ht.innerHTML='💡 提示: '+getHintText(q)+'<br><span class="rt" onclick="retryFill(\''+id+'\')">🔄 再试一次</span><span style="margin-left:8px" class="rt" onclick="showFullExp(\''+id+'\')">👀 看解析</span>';
cd.appendChild(ht);return;
}
}
let fb=document.createElement('div'); let fb=document.createElement('div');
fb.className='fb sh '+(kor?'go':'bd'); fb.className='fb sh '+(kor?'go':'bd');
fb.innerHTML=(kor?'✅ PERFECT! 完美通过!':'❌ MISS! 再练练!')+'<br><strong>🔧 维修站解析:</strong>'+q.exp; if(kor){
if(!kor)fb.innerHTML+='<br><strong>正确赛道路线</strong>'+q.ans; fb.innerHTML='✅ PERFECT! 完美通过!<br><strong>🔧 维修站解析</strong>'+q.exp;
inp.parentElement.appendChild(fb); }else{
if(!kor){ fb.innerHTML='❌ MISS! 再练练!<br><strong>🔧 维修站解析:</strong>'+q.exp+'<br><strong>✅ 正确答案:</strong>'+q.ans;
let sims=getSimQuestions(q,3); if(v!==q.ans)fb.innerHTML+='<br><small style="color:#888;">你的答案: '+v+'</small>';
// Show similar questions for practice
let sims=getSimQuestions(q,2);
if(sims.length){ if(sims.length){
let cd=inp.closest('.cd');let sdiv=document.createElement('div');sdiv.className='sim sh'; let sdiv=document.createElement('div');sdiv.className='sim sh';
let shtml='<span class="tp2">🏎 关联练习(同题型巩固)</span>'; let shtml='<span class="tp2">🏎 关联练习(同题型巩固)</span>';
sims.forEach((sq,si)=>{ sims.forEach(function(sq,si){
shtml+='<div class="st">'+(si+1)+'. '+sq.stem.replace(/\n/g,'<br>')+'</div>'; shtml+='<div class="st">'+(si+1)+'. '+sq.stem.replace(/\n/g,'<br>')+'</div>';
if(sq.type==='choice'){shtml+='<div class="opts">';sq.opts.forEach((o,j)=>{let c='op';shtml+='<button class="'+c+'" onclick="cli(\''+sq.id+'\','+j+')" id="oc'+sq.id+'_'+j+'">'+o+'</button>';});shtml+='</div>';} if(sq.type==='choice'){
else{shtml+='<input class="inp" id="ip'+sq.id+'" placeholder="输入答案..."><div class="br"><button class="cf" onclick="cfil(\''+sq.id+'\')">🏎 确认</button><button class="sh" onclick="skip(\''+sq.id+'\')">👀 解析</button></div>';} shtml+='<div class="opts">';
sq.opts.forEach(function(o,j2){shtml+='<button class="op" onclick="cli(\''+sq.id+'\','+j2+')" id="oc'+sq.id+'_'+j2+'">'+o+'</button>';});
shtml+='</div>';
}else{
shtml+='<input class="inp" id="ip'+sq.id+'" placeholder="输入答案..."><div class="br"><button class="cf" onclick="cfil(\''+sq.id+'\')">🏎 确认</button><button class="sh" onclick="skip(\''+sq.id+'\')">👀 解析</button></div>';
}
}); });
sdiv.innerHTML=shtml;cd.appendChild(sdiv); sdiv.innerHTML=shtml;cd.appendChild(sdiv);
} }
} }
if(cd)cd.appendChild(fb);
upd(); upd();
} }function retryFill(id){
function retryFill(id){
delete conv[id];let el=document.querySelector('.cd:has(.ht)'); delete conv[id];let el=document.querySelector('.cd:has(.ht)');
if(el){let q=Q.find(x=>x.id===id);if(q)el.outerHTML=renderCard(q,0,true);} if(el){let q=Q.find(x=>x.id===id);if(q)el.outerHTML=renderCard(q,0,true);}
upd(); upd();