'
].join('');
mkSwitch(body,'set-autoAnswer','自动答题','搜题后自动填写答案',SET.autoAnswer);
mkSwitch(body,'set-humanMode','模拟真人','随机延迟,降低检测风险',SET.humanMode);
mkSwitch(body,'set-retryOnFail','失败重试','搜题失败后自动重试',SET.retryOnFail);
mkSwitch(body,'set-autoNext','自动下一任务','完成当前任务后自动跳转',SET.autoNext);
body.querySelector('#set-key').addEventListener('change',function(){ SET.apiKey=this.value; saveS(); });
body.querySelector('#set-key-vis').addEventListener('click',function(){ var i=body.querySelector('#set-key'); i.type=i.type==='password'?'text':'password'; });
body.querySelector('#set-test').addEventListener('click',function(){
var k=body.querySelector('#set-key').value;
if(!k){ toast('请先输入 API Key','warn'); return; }
var s=body.querySelector('#set-st'); s.className='tp-st tp-st-id'; s.innerHTML=' 检测中...';
testConn(k,function(ok,ms,err){
if(ok){ s.className='tp-st tp-st-ok'; s.innerHTML=' 连接正常 · '+ms+'ms'; SET.apiKey=k; saveS(); toast('连接成功!'+ms+'ms','info'); }
else { s.className='tp-st tp-st-err'; s.innerHTML=' '+err+' · '+ms+'ms'; toast(err,'err'); }
});
});
body.querySelector('#set-speed').addEventListener('change',function(){ SET.playbackRate=parseFloat(this.value); saveS(); applySpeed(); });
body.querySelector('#set-dmin').addEventListener('change',function(){ SET.humanDelayMin=parseInt(this.value)||1500; saveS(); });
body.querySelector('#set-dmax').addEventListener('change',function(){ SET.humanDelayMax=parseInt(this.value)||5000; saveS(); });
body.querySelector('#set-clear-cache').addEventListener('click',function(){ clearAnswerCache(); });
}
// ═══════════════════════════════════
// QUESTION DETECTION (OCS-REF)
// ═══════════════════════════════════
function findQuestions(){
var questions = [];
var plat = platform();
var docs = [document];
// Gather all iframe documents
document.querySelectorAll('iframe').forEach(function(iframe){
try {
var d = iframe.contentDocument || iframe.contentWindow.document;
if(d && d.body) docs.push(d);
} catch(e){}
});
docs.forEach(function(doc){
if(plat === 'cx'){
// 超星: 章节测试 .TiMu
doc.querySelectorAll('.TiMu').forEach(function(node){
if(questions.find(function(q){ return q.element===node; })) return;
var titleEl = node.querySelector('.Zy_TItle .clearfix');
var title = titleEl ? clean(titleEl.innerText) : '';
if(!title || title.length < 3) return;
var typeEl = node.querySelector('input[id^="answertype"]');
var val = typeEl ? parseInt(typeEl.value) : -1;
var type = val===0?'single':val===1?'multiple':val===3?'judgement':[2,4,5,6,7,8,9,10].indexOf(val)>-1?'completion':val===11?'line':val===14?'fill':val===15?'reader':undefined;
var options = [];
var optionEls = [];
node.querySelectorAll('ul li .after, ul li label:not(.before), ul li textarea, ul textarea').forEach(function(opt){
var t = clean(opt.textContent); if(t) { options.push(t); optionEls.push(opt); }
});
// 补充 CKeditor 文本框
node.querySelectorAll('textarea').forEach(function(ta){ if(ta.value) options.push(clean(ta.value)); });
questions.push({ title:title, type:type||guessType(doc,node), options:options, optionEls:optionEls, element:node, doc:doc, plat:'cx_timu' });
});
// 超星: 作业/考试 .questionLi
doc.querySelectorAll('.questionLi').forEach(function(node){
if(questions.find(function(q){ return q.element===node; })) return;
var titleEls = node.querySelectorAll('h3, .mark_name strong, .splitS-left .mark_name');
var title = '';
titleEls.forEach(function(el){ var t=clean(el.textContent); if(t) title=(title?title+'\n':'')+t; });
if(!title || title.length < 3) return;
var typeEl = node.querySelector('input[name^="type"], input[id^="answertype"]');
var val = typeEl ? parseInt(typeEl.value) : -1;
var type = val===0?'single':val===1?'multiple':val===3?'judgement':[2,4,5,6,7,8,9,10].indexOf(val)>-1?'completion':val===11?'line':val===14?'fill':val===15?'reader':undefined;
var options = [];
var optionEls = [];
node.querySelectorAll('.answerBg .answer_p, .textDIV, .eidtDiv, .line_answer input[name^=answer]').forEach(function(opt){
var t = clean(opt.textContent||opt.value||''); if(t) { options.push(t); optionEls.push(opt); }
});
questions.push({ title:title, type:type||guessType(doc,node), options:options, optionEls:optionEls, element:node, doc:doc, plat:'cx_questionli' });
});
}
if(plat === 'zhs'){
// 共享课考试/作业 (gxkWorkAndExam)
doc.querySelectorAll('.examPaper_subject').forEach(function(node){
if(questions.find(function(q){ return q.element===node; })) return;
var titleEl = node.querySelector('.subject_describe > div, .smallStem_describe > div:nth-child(2), .subject_describe');
var title = titleEl ? clean(titleEl.textContent) : '';
if(!title || title.length < 3) return;
var typeEl = node.querySelector('.subject_type');
var type = typeEl ? (typeEl.textContent.indexOf('单选')>-1?'single':typeEl.textContent.indexOf('多选')>-1?'multiple':typeEl.textContent.indexOf('判断')>-1?'judgement':typeEl.textContent.indexOf('填空')>-1?'completion':undefined) : undefined;
var options = [];
var optionEls = [];
node.querySelectorAll('.subject_node .nodeLab').forEach(function(opt){ var t=clean(opt.textContent); if(t) { options.push(t); optionEls.push(opt); } });
questions.push({ title:title, type:type||guessType(doc,node), options:options, optionEls:optionEls, element:node, doc:doc, plat:'zhs_gxk' });
});
// smartWork / smartExam: Tailwind 样式题目
doc.querySelectorAll('.subject-box').forEach(function(node){
if(questions.find(function(q){ return q.element===node; })) return;
var titleEl = node.querySelector('.subject-describe, .stem-describe > div:first-child');
var title = titleEl ? clean(titleEl.textContent) : '';
if(!title || title.length < 3) return;
var typeEl = node.querySelector('.subject-type, [class*="type"]');
var typeTxt = typeEl ? typeEl.textContent : '';
var type = typeTxt.indexOf('单选')>-1?'single':typeTxt.indexOf('多选')>-1?'multiple':typeTxt.indexOf('判断')>-1?'judgement':typeTxt.indexOf('填空')>-1?'completion':undefined;
var options = [];
var optionEls = [];
node.querySelectorAll('.option-item, .subject-option, label').forEach(function(opt){
var t=clean(opt.textContent); if(t) { options.push(t); optionEls.push(opt); }
});
questions.push({ title:title, type:type||guessType(doc,node), options:options, optionEls:optionEls, element:node, doc:doc, plat:'zhs_smart' });
});
// fusioncourse / hike: 多形态考试
doc.querySelectorAll('.exam_item, .course-exam-item, .exam-item, .q_main, .question-item').forEach(function(node){
if(questions.find(function(q){ return q.element===node; })) return;
var titleEl = node.querySelector('.questionContent, .questionName .centent-pre, .quest-title .option-name, .question-topic, .qeustion-content, .combination-content, .stem-content');
var title = titleEl ? clean(titleEl.textContent) : '';
if(!title || title.length < 3) return;
var typeEl = node.querySelector('.subject_type, .letterSortNum, .quest-type, .question_score, .title-box, .combination-title');
var typeTxt = typeEl ? typeEl.textContent : '';
var type = typeTxt.indexOf('单选')>-1?'single':typeTxt.indexOf('多选')>-1?'multiple':typeTxt.indexOf('判断')>-1?'judgement':typeTxt.indexOf('填空')>-1||typeTxt.indexOf('问答')>-1?'completion':undefined;
var options = [];
var optionEls = [];
node.querySelectorAll('.optionUl label, .radio-view li.clearfix, .checkbox-views label.el-checkbox, label').forEach(function(opt){
var t=clean(opt.textContent); if(t && t.length>1) { options.push(t); optionEls.push(opt); }
});
// 也尝试 .option-item
if(options.length===0){
node.querySelectorAll('.option-item').forEach(function(opt){
var t=clean(opt.textContent); if(t && t.length>1) { options.push(t); optionEls.push(opt); }
});
}
questions.push({ title:title, type:type||guessType(doc,node), options:options, optionEls:optionEls, element:node, doc:doc, plat:'zhs_fusion' });
});
// 校内课 (xnkWork): .questionBox
doc.querySelectorAll('.questionBox_info .questionBox, [class*="questionBox"]:not([class*="info"])').forEach(function(node){
if(questions.find(function(q){ return q.element===node; })) return;
var titleEl = node.querySelector('.questionContent, .q_content');
var title = titleEl ? clean(titleEl.textContent) : '';
if(!title || title.length < 3) return;
var typeEl = node.querySelector('.subject_type, [class*="type"]');
var typeTxt = typeEl ? typeEl.textContent : '';
var type = typeTxt.indexOf('单选')>-1?'single':typeTxt.indexOf('多选')>-1?'multiple':typeTxt.indexOf('判断')>-1?'judgement':typeTxt.indexOf('填空')>-1?'completion':undefined;
var options = [];
var optionEls = [];
node.querySelectorAll('label, .option-item, li').forEach(function(opt){
var t=clean(opt.textContent); if(t && t.length>1) { options.push(t); optionEls.push(opt); }
});
questions.push({ title:title, type:type||guessType(doc,node), options:options, optionEls:optionEls, element:node, doc:doc, plat:'zhs_xnk' });
});
}
if(plat === 'icve' || plat === 'zjy'){
// 智慧职教/职教云: .questionLi (vbContent) 或 .testContnet 或 .e-q-body
doc.querySelectorAll('.questionLi, .testContnet .questionBox, .e-q-body, .subject-list .subject-item').forEach(function(node){
if(questions.find(function(q){ return q.element===node; })) return;
var titleEl = node.querySelector('.questionTit, .mark_name, .q-title, .subject-title, .subject_describe');
var title = titleEl ? clean(titleEl.textContent) : '';
if(!title || title.length < 3){
title = clean(node.textContent.split('\n')[0]||'').slice(0,120);
}
if(!title || title.length < 3) return;
var typeEl = node.querySelector('input[name^="type"], input[id^="answertype"], .subject_type, [class*="type"]');
var typeTxt = typeEl ? (typeEl.value || typeEl.textContent || '') : '';
var type = typeTxt.indexOf('0')===0?'single':typeTxt.indexOf('1')===0?'multiple':typeTxt.indexOf('3')===0?'judgement':typeTxt.indexOf('单选')>-1?'single':typeTxt.indexOf('多选')>-1?'multiple':typeTxt.indexOf('判断')>-1?'judgement':typeTxt.indexOf('填空')>-1?'completion':undefined;
var options = [];
var optionEls = [];
if(plat === 'zjy'){
// 职教云旧版: label input + span
node.querySelectorAll('label input[type="radio"], label input[type="checkbox"]').forEach(function(inp){
var label = inp.closest('label');
if(label){ var t=clean(label.textContent); if(t){ options.push(t); optionEls.push(label); } }
});
}
if(options.length === 0){
node.querySelectorAll('.answerBg .answer_p, .optionLi label, .option-item, .el-radio, .el-checkbox, label').forEach(function(opt){
var t=clean(opt.textContent); if(t && t.length>1){ options.push(t); optionEls.push(opt); }
});
}
if(options.length === 0){
node.querySelectorAll('.ivu-radio-wrapper, .ivu-checkbox-wrapper, .answer_item').forEach(function(opt){
var t=clean(opt.textContent); if(t && t.length>1){ options.push(t); optionEls.push(opt); }
});
}
questions.push({ title:title, type:type||guessType(doc,node), options:options, optionEls:optionEls, element:node, doc:doc, plat:'icve' });
});
// 智慧职教: .e-q-body 题目
doc.querySelectorAll('.e-q-body').forEach(function(node){
if(questions.find(function(q){ return q.element===node; })) return;
var titleEl = node.querySelector('.e-q-header .e-q-title, .e-q-title');
var title = titleEl ? clean(titleEl.textContent) : '';
if(!title || title.length < 3) return;
var typeEl = node.querySelector('.e-q-header .e-q-type');
var typeTxt = typeEl ? typeEl.textContent : '';
var type = typeTxt.indexOf('单选')>-1?'single':typeTxt.indexOf('多选')>-1?'multiple':typeTxt.indexOf('判断')>-1?'judgement':typeTxt.indexOf('填空')>-1?'completion':undefined;
var options = [];
var optionEls = [];
node.querySelectorAll('.e-q-option .e-q-option-item, .option-item, .e-q-options label').forEach(function(opt){
var t=clean(opt.textContent); if(t && t.length>1){ options.push(t); optionEls.push(opt); }
});
questions.push({ title:title, type:type||guessType(doc,node), options:options, optionEls:optionEls, element:node, doc:doc, plat:'icve' });
});
}
if(plat === 'ykt'){
// 雨课堂: .problem_item 或 .question_item
doc.querySelectorAll('.problem_item, .question_item, .exam_question, [class*="problem"]').forEach(function(node){
if(questions.find(function(q){ return q.element===node; })) return;
var titleEl = node.querySelector('.problem_des, .question_name, .stem-content, .q_content, p');
var title = titleEl ? clean(titleEl.textContent) : '';
if(!title || title.length < 3){
title = clean(node.textContent.split('\n')[0]||'').slice(0,120);
}
if(!title || title.length < 3) return;
var typeEl = node.querySelector('.problem_type, .question_type, [class*="type"]');
var typeTxt = typeEl ? typeEl.textContent : '';
var type = typeTxt.indexOf('单选')>-1?'single':typeTxt.indexOf('多选')>-1?'multiple':typeTxt.indexOf('判断')>-1?'judgement':typeTxt.indexOf('填空')>-1?'completion':undefined;
var options = [];
var optionEls = [];
node.querySelectorAll('.problem_option label, .option_item, .el-radio, .el-checkbox, label, .answer_item').forEach(function(opt){
var t=clean(opt.textContent); if(t && t.length>1){ options.push(t); optionEls.push(opt); }
});
questions.push({ title:title, type:type||guessType(doc,node), options:options, optionEls:optionEls, element:node, doc:doc, plat:'ykt' });
});
}
if(plat === 'mooc'){
// 中国大学MOOC: .u-questionItem 或 .question-wrap
doc.querySelectorAll('.u-questionItem, .question-wrap, .exam-question').forEach(function(node){
if(questions.find(function(q){ return q.element===node; })) return;
var titleEl = node.querySelector('.u-questionContent, .question-content, .q-title, .stem');
var title = titleEl ? clean(titleEl.textContent) : '';
if(!title || title.length < 3){
title = clean(node.textContent.split('\n')[0]||'').slice(0,120);
}
if(!title || title.length < 3) return;
var typeEl = node.querySelector('.u-questionType, .question-type, [class*="type"]');
var typeTxt = typeEl ? typeEl.textContent : '';
var type = typeTxt.indexOf('单选')>-1?'single':typeTxt.indexOf('多选')>-1?'multiple':typeTxt.indexOf('判断')>-1?'judgement':typeTxt.indexOf('填空')>-1?'completion':undefined;
var options = [];
var optionEls = [];
node.querySelectorAll('.u-questionOp .u-questionList-li, .option-item, label, .answer_item').forEach(function(opt){
var t=clean(opt.textContent); if(t && t.length>1){ options.push(t); optionEls.push(opt); }
});
questions.push({ title:title, type:type||guessType(doc,node), options:options, optionEls:optionEls, element:node, doc:doc, plat:'mooc' });
});
}
if(plat === 'icve' || plat === 'mooc'){
// 通用检测:找 radio/checkbox/textarea 的父容器
var seen = new Set();
doc.querySelectorAll('input[type="radio"], input[type="checkbox"], textarea').forEach(function(input){
var parent = input.closest('div,form,li,p,fieldset');
if(!parent || seen.has(parent)) return;
seen.add(parent);
var title = clean(parent.textContent.split('\n')[0]||'').slice(0,120);
if(title.length < 5) return;
var radios = parent.querySelectorAll('input[type="radio"]');
var checks = parent.querySelectorAll('input[type="checkbox"]');
var textas = parent.querySelectorAll('textarea');
var type = textas.length>0?'completion':checks.length>2?'multiple':radios.length===2?'judgement':radios.length>2?'single':'completion';
var options = [];
var optionEls = [];
parent.querySelectorAll('label, .option, li').forEach(function(opt){ var t=clean(opt.textContent); if(t) { options.push(t); optionEls.push(opt); } });
questions.push({ title:title, type:type, options:options, optionEls:optionEls, element:parent, doc:doc, plat:'generic' });
});
}
});
return questions;
}
function guessType(doc, node){
var r=node.querySelectorAll('input[type="radio"]').length;
var c=node.querySelectorAll('input[type="checkbox"]').length;
var t=node.querySelectorAll('textarea').length;
if(t>0) return 'completion';
if(r===2) return 'judgement';
if(c>2) return 'multiple';
if(r>2) return 'single';
return 'completion';
}
// ═══════════════════════════════════
// ANSWER FILLING (OCS exact matching logic)
// ═══════════════════════════════════
// OCS clearString: strip everything except Chinese, English, numbers
function _clear(s, ex){
ex = ex || [];
ex.push('①②③④⑤⑥⑦⑧⑨');
return (s||'').trim().toLowerCase().replace(RegExp('[^\\u2e80-\\u9fffA-Za-z0-9'+ex.join('')+']+','g'),'');
}
// OCS normalizeString
function _norm(s){
return _clear((s||'')
.replace(/[,。!?;:""''、()【】《》\s]/g,'')
.replace(/[,.\-!?;:'"()[\]<>]/g,'')
.replace(/[a-zA-Z0-9]/g,function(c){ return String.fromCharCode(c.charCodeAt(0)-0xfee0); })
.replace(/%/g,'%')
);
}
// OCS removeRedundant: strip option prefix
function _strip(s){
return (s||'').replace(/^[A-H][..、::\s]+/i,'').replace(/^[((][A-H][))]\s*/i,'').trim();
}
// OCS answer-to-option match (保留作为兜底)
function _matchOpt(ansText, optText, loose){
var a = _norm(_strip(ansText));
var o = _norm(_strip(optText));
if(!a || !o) { console.log('[TiKu] match: empty after norm ans="'+a+'" opt="'+o+'"'); return false; }
if(a === o) { console.log('[TiKu] match: exact '+a); return true; }
if(a.indexOf(o) > -1) { console.log('[TiKu] match: ans⊇opt ans="'+a.slice(0,30)+'" opt="'+o.slice(0,30)+'"'); return true; }
if(loose && o.indexOf(a) > -1) { console.log('[TiKu] match: opt⊇ans ans="'+a.slice(0,30)+'" opt="'+o.slice(0,30)+'"'); return true; }
var score = _diceCoefficient(a, o);
var ok = score > (loose?0.5:0.65);
if(ok) console.log('[TiKu] match: dice='+score.toFixed(2)+' ans="'+a.slice(0,30)+'"');
return ok;
}
// ═══════════════════════════════════
// DICE COEFFICIENT (OCS string-similarity)
// 基于 bigram 的 Dice 系数,比字符重叠率更精准
// ═══════════════════════════════════
function _diceBigrams(s){
var m = {};
for(var i=0; i -1){ level = 1; }
}
if(level > 0) result.push({ opt: options[i], level: level });
});
result.sort(function(a,b){ return b.level - a.level; });
return result.map(function(r){ return r.opt; });
}
// ═══════════════════════════════════
// OCS answerSimilar — Dice系数相似度
// 返回每个选项的 {rating, target}
// ═══════════════════════════════════
function _answerSimilar(answers, options){
var _ans = answers.map(function(a){ return _clear(_strip(a)); });
var _opts = options.map(function(o){ return _clear(_strip(o)); });
return _opts.map(function(opt){
if(!opt||!opt.trim()) return { rating:0, target:'' };
var best=0, bestTarget='';
for(var i=0; i<_ans.length; i++){
var r = _diceCoefficient(opt, _ans[i]);
if(r > best){ best=r; bestTarget=_ans[i]; }
}
return { rating:best, target:bestTarget };
});
}
// ═══════════════════════════════════
// OCS answerSimilarWithGap — 带领先度消歧
// 最高分选项附 gap(最高分与次高分差值)
// ═══════════════════════════════════
function _answerSimilarWithGap(answers, options){
var ratings = _answerSimilar(answers, options);
var sorted = ratings.slice().sort(function(a,b){ return b.rating-a.rating; });
var maxR = sorted[0] ? sorted[0].rating : 0;
var secondR = 0;
for(var i=1; i threshold){
if((ratings[i]||0) >= (ratings[j]||0)){ elim[j]=true; }
else { elim[i]=true; break; }
}
}
}
return selectedOptions.filter(function(_,i){ return !elim[i]; });
}
// ═══════════════════════════════════
// isPlainAnswer — 检测答案是否为纯ABCD字母格式
// ═══════════════════════════════════
function _isPlainAnswer(s){
return /^[A-Ha-h]+$/.test((s||'').replace(/[\s,,、]/g,''));
}
function _resolvePlainAnswer(s){
if(!_isPlainAnswer(s)) return null;
return (s||'').replace(/[\s,,、]/g,'').toUpperCase();
}
// OCS judgement words
var _CORRECT = ['是','对','正确','确定','√','对的','是的','正确的','true','True','T','yes','1'];
var _INCORRECT = ['非','否','错','错误','×','X','错的','不对','不正确的','不正确','不是','不是的','false','False','F','no','0'];
function _judgeMatch(s, words){
return words.some(function(w){ return _clear(_strip(w), ['√','×']) === _clear(_strip(s), ['√','×']); });
}
function fillAnswer(q, answer){
if(!q.element || !answer) { console.log('[TiKu] fill skip: no el/ans'); return false; }
answer = answer.trim();
var doc = q.doc || document;
var node = q.element;
if(!doc.body.contains(node) && !document.body.contains(node)) { console.log('[TiKu] fill skip: node detached'); return false; }
var optionEls = q.optionEls || [];
var options = q.options || [];
console.log('[TiKu] fill: type='+q.type+' ans="'+answer.slice(0,60)+'" opts='+options.length+' els='+optionEls.length);
// --- Judgement: OCS keyword matching ---
if(q.type==='judgement'){
var ansCorrect = _judgeMatch(answer, _CORRECT);
var ansIncorrect = _judgeMatch(answer, _INCORRECT);
if(ansCorrect || ansIncorrect){
for(var i=0; i 0 ? parts : [answer];
// 也尝试将完整答案作为一个整体去匹配
if(parts.length > 1) allAnswers.push(answer);
console.log('[TiKu] multi: allAnswers=['+allAnswers.join('|').slice(0,80)+']');
// ===== Stage 1: 归一化匹配 (仅 ans⊇opt 方向) =====
var normalizedMatch = _answerNormalizedMatch(allAnswers, options);
if(normalizedMatch.length > 0){
var normRatings = normalizedMatch.map(function(){ return 0.8; });
var disambig = _disambiguateSimilarOptions(normalizedMatch, normRatings);
console.log('[TiKu] multi S1 norm: '+disambig.length+' options');
var anyClick = false;
for(var d=0; d 0.6) simGroup.push({ opt: options[i], rating: r.rating, gap: r.gap });
});
if(simGroup.length > 0){
var simOpts = simGroup.map(function(s){ return s.opt; });
var simRatings = simGroup.map(function(s){ return s.rating; });
var disambig2 = _disambiguateSimilarOptions(simOpts, simRatings);
console.log('[TiKu] multi S2 sim: '+disambig2.length+' options');
var anyClick2 = false;
for(var d2=0; d2=0 && cIdx 0;
if(!fallbackOk) console.log('[TiKu] multi: ALL STAGES FAILED');
return fallbackOk;
}
// --- Completion ---
if(q.type==='completion'){
var ta = node.querySelector('textarea');
var inp = node.querySelector('input[type="text"], input:not([type])');
if(!ta && !inp){
var p = node.parentElement;
if(p){ ta = p.querySelector('textarea'); if(!ta) inp = p.querySelector('input[type="text"], input:not([type])'); }
}
var target = ta || inp;
// Try CKEditor/UEditor first
if(target && _fillCKEditor(target, answer)){
console.log('[TiKu] fill: CKEditor OK');
return true;
}
if(target){
target.focus();
if(SET.humanMode){
target.value = '';
for(var j=0; j 0){
var idx = options.indexOf(normalizedMatch[0]);
if(idx >= 0 && optionEls[idx] && optionEls[idx].isConnected){
console.log('[TiKu] single S1 norm: idx='+idx);
return clickOptWrap(optionEls[idx], q.plat);
}
}
// ===== Stage 2: 相似匹配 (取最优 > 0.6) =====
var ratings = _answerSimilar(allAnswers, options);
var bestIdx = -1, bestRating = 0;
ratings.forEach(function(r, i){
if(r.rating > bestRating){ bestRating = r.rating; bestIdx = i; }
});
if(bestIdx >= 0 && bestRating > 0.6){
console.log('[TiKu] single S2 sim: idx='+bestIdx+' rating='+bestRating.toFixed(2));
return clickOptWrap(optionEls[bestIdx], q.plat);
}
// ===== Stage 3: 纯ABCD答案兜底 (仅单字母) =====
var plain = _resolvePlainAnswer(answer);
if(plain && plain.length === 1){
var pIdx = plain.charCodeAt(0)-65;
if(pIdx >= 0 && optionEls[pIdx] && optionEls[pIdx].isConnected){
console.log('[TiKu] single S3 plain: '+plain);
return clickOptWrap(optionEls[pIdx], q.plat);
}
}
// ===== Stage 4: 多片段答案合并重试 =====
var parts = answer.split(/[#,;,;、\s]+/).filter(Boolean);
if(parts.length > 1){
var merged = parts.join('');
console.log('[TiKu] single S4 merge: '+merged.slice(0,60));
var mergedMatch = _answerNormalizedMatch([merged], options);
if(mergedMatch.length > 0){
var mIdx = options.indexOf(mergedMatch[0]);
if(mIdx >= 0 && optionEls[mIdx] && optionEls[mIdx].isConnected){
console.log('[TiKu] single S4 merge match: idx='+mIdx);
return clickOptWrap(optionEls[mIdx], q.plat);
}
}
// Merge + similarity fallback
var mergedSim = _answerSimilar([merged], options);
var mBestIdx = -1, mBestRating = 0;
mergedSim.forEach(function(r, i){
if(r.rating > mBestRating){ mBestRating = r.rating; mBestIdx = i; }
});
if(mBestIdx >= 0 && mBestRating > 0.5){
console.log('[TiKu] single S4 merge sim: idx='+mBestIdx+' rating='+mBestRating.toFixed(2));
return clickOptWrap(optionEls[mBestIdx], q.plat);
}
}
// ===== Stage 5: loose fallback =====
for(var i=0; i',
'
',
'',
'',
'',
'
',
'
就绪
',
'',
// 搜索进度
'
',
'
',
'
答题进度
',
'',
'',
'
',
'',
'
',
// 填入进度
'
',
'
',
'
填入进度
',
'',
'',
'
',
'',
'
',
// 题目列表
'
',
'
题目列表
',
'',
'
'
].join('');
body.querySelector('#exam-detect').addEventListener('click', doDetect);
body.querySelector('#exam-start').addEventListener('click', doStart);
body.querySelector('#exam-fill').addEventListener('click', doAutoFill);
body.querySelector('#exam-stop').addEventListener('click', doStop);
var fstop = body.querySelector('#fill-stop');
if(fstop) fstop.addEventListener('click', doFillStop);
updateProg();
updateList();
}
function doDetect(){
examQuestions = findQuestions().map(function(q,i){
return { index:i, title:q.title, type:q.type, options:q.options, optionEls:q.optionEls, element:q.element, doc:q.doc, plat:q.plat, status:'pending', answer:'', error:'' };
});
// Restore cached answers
var restored = 0;
examQuestions.forEach(function(item){
var cached = getAnswerCache(item);
if(cached && cached.answer){
item.status = 'found';
item.answer = cached.answer;
item.cached = true;
restored++;
}
});
if(examQuestions.length===0){ toast('未检测到题目','warn'); }
else {
var msg = '检测到 '+examQuestions.length+' 题';
if(restored>0) msg += ',恢复缓存 '+restored+' 题';
toast(msg,'info');
}
updateList(); updateProg();
}
function switchToPreview(){
// 检测是否在考试开始页面(OCS: exam-ans/exam/test/reVersionTestStartNew)
var isExamStart = /\/exam\/test\//i.test(location.href) || /reVersionTestStart/i.test(location.href);
if(!isExamStart) return;
// 检查是否禁止整卷预览
var markInfo = document.querySelector('.mark_info');
if(markInfo && /不允许整卷预览/i.test(markInfo.textContent||'')){
toast('本考试不允许整卷预览,将逐题作答','warn');
return;
}
// 尝试调用超星的 topreview 函数跳转到整卷预览
var win = (typeof unsafeWindow !== 'undefined' ? unsafeWindow : window);
if(typeof win.topreview === 'function'){
toast('正在跳转到整卷预览...','info');
win.topreview();
return;
}
// 备选:查找并点击"整卷预览"按钮
var previewBtns = document.querySelectorAll('a, button, .btn, [onclick]');
for(var i=0; i 0){
var found = [];
await doMultiThreadSearch(examQuestions, found);
}
var ok = examQuestions.filter(function(q){ return q.status==='found'||q.status==='filled'; }).length;
toast('搜索完成: '+ok+'/'+examQuestions.length,(ok===examQuestions.length?'info':'warn'));
examRunning=false; examStop=false;
renderExam(panel.querySelector('#tp-body'));
}
function doStop(){ examStop=true; examRunning=false; toast('搜索已停止','warn'); renderExam(panel.querySelector('#tp-body')); }
function doFillStop(){ fillStop=true; fillRunning=false; toast('填入已停止','warn'); updateFillProg(); }
function updateProg(){
var el = panel.querySelector('#exam-prog');
var txt = panel.querySelector('#exam-prog-txt');
if(!el) return;
if(examQuestions.length===0){ el.innerHTML=''; if(txt) txt.textContent=''; return; }
var oks=0, ers=0, srs=0;
examQuestions.forEach(function(q){ if(q.status==='found'||q.status==='filled') oks++; else if(q.status==='failed') ers++; else if(q.status==='searching') srs++; });
var total=examQuestions.length;
var done=oks+ers;
el.innerHTML = '';
if(txt){
if(srs>0) txt.textContent = '搜索中... '+done+'/'+total+' 已完成';
else if(done===total) txt.textContent = '全部完成: '+oks+' 成功, '+ers+' 失败';
else if(done>0) txt.textContent = done+'/'+total+' 已处理 ('+oks+' 成功)';
else txt.textContent = '0/'+total+' 等待搜索';
}
}
function updateList(){
var el = panel.querySelector('#exam-list');
if(!el) return;
if(examQuestions.length===0){ el.innerHTML='
点击「检测题目」开始
'; return; }
// Save accordion collapse state before rebuild
var collapsed = {};
el.querySelectorAll('.tp-acc-hd').forEach(function(hd){
if(!hd.classList.contains('open')) collapsed[hd.dataset.grp] = true;
});
var groups = {};
var typeNames = { single:'单选题', multiple:'多选题', judgement:'判断题', completion:'填空题/问答题' };
examQuestions.forEach(function(q){
var t = q.type || 'completion';
if(!groups[t]) groups[t] = [];
groups[t].push(q);
});
var order = ['single','multiple','judgement','completion'];
var html = '';
order.forEach(function(type){
var items = groups[type];
if(!items || items.length===0) return;
var done = items.filter(function(q){ return q.status==='found'||q.status==='failed'||q.status==='filled'; }).length;
var title = (typeNames[type]||type) + ' ('+done+'/'+items.length+')';
var isOpen = !collapsed[type]; // default open, restore previous state
html += '
';
if(q.type) html += ''+q.type+'';
if(q.confidence!==undefined) html += '置信:'+Math.round(q.confidence*100)+'%';
if(q.status==='found') html += '';
if(q.status!=='pending' && q.status!=='filled') html += '';
html += '
';
});
html += '
';
});
el.innerHTML = html;
// Accordion toggle
el.querySelectorAll('.tp-acc-hd').forEach(function(hd){
hd.addEventListener('click',function(){
var body = el.querySelector('[data-grp-body="'+this.dataset.grp+'"]');
if(body){
this.classList.toggle('open');
body.classList.toggle('cl');
}
});
});
// Retry buttons
el.querySelectorAll('.retry-q').forEach(function(btn){
btn.addEventListener('click', async function(){
var idx = parseInt(this.dataset.idx);
var q = examQuestions[idx];
q.status='searching'; q.error=''; q.answer=''; updateList(); updateProg();
try {
var r = await apiQuery(q.title, q.type, q.options);
q.status='found'; q.answer=r.answer||''; q.confidence=r.confidence;
} catch(err){ q.status='failed'; q.error=err.message; }
updateList(); updateProg();
});
});
// Single fill buttons
el.querySelectorAll('.fill-one-q').forEach(function(btn){
btn.addEventListener('click', function(){
var idx = parseInt(this.dataset.idx);
var q = examQuestions[idx];
try { fillAnswer(q, q.answer); q.status='filled'; toast('已填入第'+(idx+1)+'题','info'); } catch(e){ toast('填入失败','err'); }
updateList(); updateProg();
});
});
}
function updateFillProg(){
var el = panel.querySelector('#fill-prog');
var txt = panel.querySelector('#fill-prog-txt');
if(!el) return;
var found = examQuestions.filter(function(q){ return q.status==='filled'||q.status==='found'; }).length;
var filled = examQuestions.filter(function(q){ return q.status==='filled'; }).length;
if(found===0){ el.innerHTML=''; if(txt) txt.textContent=''; return; }
el.innerHTML = '';
if(txt){
if(fillRunning) txt.textContent = '填入中... '+filled+'/'+found;
else if(filled===found) txt.textContent = '填入完成: '+filled+'/'+found;
else txt.textContent = '已填入 '+filled+'/'+found;
}
}
async function doAutoFill(){
var found = examQuestions.filter(function(q){ return q.status==='found' && q.answer; });
if(found.length===0){ toast('没有可填入的答案','warn'); return; }
fillRunning=true; fillStop=false;
// Disable fill button
var fb = panel.querySelector('#exam-fill'); if(fb) fb.disabled=true;
var fs = panel.querySelector('#fill-stop'); if(fs) fs.disabled=false;
updateFillProg();
for(var i=0; i0) await sleep(SET.humanMode ? rand(SET.humanDelayMin, SET.humanDelayMax) : 500);
// 滚动题目到可见区域(实时显示填入过程)
var qEl = found[i].element;
if(qEl && qEl.isConnected){
try { qEl.scrollIntoView({ behavior:'smooth', block:'center' }); } catch(e){}
await sleep(200); // 等待滚动完成
}
if(fillAnswer(found[i], found[i].answer)) found[i].status='filled';
} catch(e){ /* fill failed, keep status */ }
updateFillProg();
}
var filled = examQuestions.filter(function(q){ return q.status==='filled'; }).length;
toast('自动填入完成: '+filled+'/'+found.length, filled===found.length?'info':'warn');
panel.querySelector('#exam-st').textContent = '已填入 '+filled+' 题';
fillRunning=false; fillStop=false;
updateFillProg();
renderExam(panel.querySelector('#tp-body'));
}
// ═══════════════════════════════════
// COURSE PANEL
// ═══════════════════════════════════
var courseRunning = false;
var courseLogs = [];
// 学习模式: job(只刷任务点) | next(逐章全刷) | manually(手动)
var STUDY_MODE = load('studyMode', 'job');
var courseState = 'idle';
// OCS-style: 递归遍历文档树,收集所有 video/audio(含嵌套 iframe)
function findAllMedia(doc, visited){
doc = doc || document;
visited = visited || new Set();
if(visited.has(doc)) return [];
visited.add(doc);
var list = [];
doc.querySelectorAll('video, audio').forEach(function(v){ list.push(v); });
doc.querySelectorAll('iframe').forEach(function(iframe){
try {
var childDoc = iframe.contentDocument || iframe.contentWindow.document;
if(childDoc) list = list.concat(findAllMedia(childDoc, visited));
} catch(e){ /* 跨域 iframe,跳过 */ }
});
return list;
}
function renderCourse(body){
body.innerHTML = [
'