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);
}
function examCfil(){
let q=Q.find(x=>x.id===examQid[examIdx]);if(!q)return;
let v=$('eip')?$('eip').value.trim():'';if(!v)return;
let kor=v===q.ans;
let inp=$('eip');inp.disabled=true;inp.className='inp '+(kor?'ok':'no');
let q=Q.find(function(x){return x.id===examQid[examIdx];});if(!q)return;
let v=$(('eip'))?$(('eip')).value.trim():'';if(!v)return;
function n(s){return s.replace(/[\s,,、;;。..]+/g,",").replace(/^,+|,+$/g,"").replace(/,+/g,",").replace(/\s+/g,"").toLowerCase();}
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);
}
function finishExam(){
}function finishExam(){
if(examTimer){clearInterval(examTimer);examTimer=null;}
$('eh').className='exam-hdr';
let pct=examQid.length?Math.round(examScore/examQid.length*100):0;
@@ -1103,42 +1104,68 @@ function showFullExp(id){
cd.appendChild(fb);upd();
}
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 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();
let inp=$('ip'+id);inp.disabled=true;inp.className='inp '+(kor?'ok':'no');
let br=inp.parentElement.querySelector('.br');if(br)br.remove();
if(!kor){
let m=meta[id];
if(m&&m.h===0){
m.h=1;let cd=inp.closest('.cd');
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;
}
}
// Always show explanation immediately (remove hint-first flow)
let cd=inp.closest('.cd');
let existingFB=cd?cd.querySelector('.fb'):null;
if(existingFB)existingFB.remove();
let fb=document.createElement('div');
fb.className='fb sh '+(kor?'go':'bd');
fb.innerHTML=(kor?'✅ PERFECT! 完美通过!':'❌ MISS! 再练练!')+'<br><strong>🔧 维修站解析:</strong>'+q.exp;
if(!kor)fb.innerHTML+='<br><strong>正确赛道路线</strong>'+q.ans;
inp.parentElement.appendChild(fb);
if(!kor){
let sims=getSimQuestions(q,3);
if(kor){
fb.innerHTML='✅ PERFECT! 完美通过!<br><strong>🔧 维修站解析</strong>'+q.exp;
}else{
fb.innerHTML='❌ MISS! 再练练!<br><strong>🔧 维修站解析:</strong>'+q.exp+'<br><strong>✅ 正确答案:</strong>'+q.ans;
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){
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>';
sims.forEach((sq,si)=>{
sims.forEach(function(sq,si){
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>';}
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>';}
if(sq.type==='choice'){
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);
}
}
if(cd)cd.appendChild(fb);
upd();
}
function retryFill(id){
}function retryFill(id){
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);}
upd();