// ==UserScript== // @name YOOC易班助手 // @namespace http://tampermonkey.net/ // @version 1.0 // @description 彻底修复跳题BUG(DOM渲染探测)、加入骨架级纯净文本匹配(抗一切标点干扰)、完善题库ID与TXT排版。 // @author 毫厘 // @match *://*.yooc.me/* // @grant none // @run-at document-start // ==/UserScript== (function() { 'use strict'; const injectCode = ` (function() { window.__yooc = { params: { token: '', yibanId: '', examuserId: '', examId: '' }, currentPaper: [], isHoneypot: false, harvested: {}, solving: false, currentViewExam: null, examNames: {}, dict: { 'EHOQnmIlFTWj4w/KduiYhA==': ['0'], 'rpEySfwpHRpZ2e63UNBznQ==': ['1'], 'GDq/oTf9hSo5WnREQUwIUA==': ['2'], 'X1yuE+WZgBTLj8HheQY4hA==': ['3'], 'AVAmpoTedb8redjJKEL0nQ==': ['0', '1'], 'xJOq/yEqHuZ3sAikzvJYnQ==': ['0', '2'], 'uorBHjvuhl1ZcgpGbktEBw==': ['1', '2'], 'YfPgy8DC6iwWF9XM0WK7kg==': ['0', '1', '2'], '+z0GgEWd2u7XnlBRKv6i1g==': ['0', '2', '3'], 'itQk2tSqzl3TTlYLAvJbQA==': ['1', '2', '3'], 'Z2NpcmomFRvndsT6LF0rh5E0tgszOUVM9h9JBtBTbWo=': ['0', '1', '2', '3'] } }; // --- 全局样式注入 --- function injectCSS() { if(document.getElementById('yooc-modern-css')) return; const style = document.createElement('style'); style.id = 'yooc-modern-css'; style.innerHTML = \` #yooc-sniffer-panel { font-family: system-ui, -apple-system, sans-serif; box-sizing: border-box; } #yooc-sniffer-panel * { box-sizing: inherit; } .yooc-btn { transition: all 0.2s ease; display: inline-flex; align-items: center; justify-content: center; font-weight: 600; cursor: pointer; outline: none; border: none; } .yooc-btn:hover { transform: translateY(-1px); filter: brightness(1.1); } .yooc-btn:active { transform: translateY(1px); } .yooc-tabs { display: flex; border-bottom: 1px solid #334155; background: #0f172a; } .yooc-tab { flex: 1; padding: 10px 0; text-align: center; color: #94a3b8; cursor: pointer; font-size: 13px; font-weight: bold; transition: color 0.3s; } .yooc-tab:hover { color: #f8fafc; background: rgba(255,255,255,0.05); } .yooc-tab.active { color: #38bdf8; border-bottom: 2px solid #38bdf8; background: rgba(56, 189, 248, 0.1); } .yooc-scroll { overflow-y: auto; overflow-x: hidden; scroll-behavior: smooth; } .yooc-scroll::-webkit-scrollbar { width: 6px; } .yooc-scroll::-webkit-scrollbar-track { background: rgba(0,0,0,0.2); border-radius: 4px; margin: 4px 0; } .yooc-scroll::-webkit-scrollbar-thumb { background: #475569; border-radius: 4px; } .yooc-scroll::-webkit-scrollbar-thumb:hover { background: #64748b; } .yooc-card { background: #1e293b; border: 1px solid #334155; border-radius: 8px; padding: 12px; margin-bottom: 12px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); } .yooc-q-title { color: #f8fafc; font-size: 14px; font-weight: bold; margin-bottom: 10px; line-height: 1.5; } .yooc-opt { font-size: 13px; margin-bottom: 6px; padding: 6px 10px; border-radius: 6px; display: flex; align-items: flex-start; line-height: 1.4; } .yooc-opt-correct { background: rgba(16, 185, 129, 0.1); border: 1px solid rgba(16, 185, 129, 0.3); color: #10b981; } .yooc-opt-wrong { background: rgba(255, 255, 255, 0.03); color: #94a3b8; } .yooc-input { width: 100%; padding: 8px 12px; border-radius: 6px; border: 1px solid #475569; background: #0f172a; color: #f8fafc; outline: none; font-size: 13px; transition: border-color 0.2s; } .yooc-input:focus { border-color: #38bdf8; } \`; document.head.appendChild(style); } // --- 无感 Toast 提示 --- window.__yoocToast = function(msg, duration = 3000) { let box = document.getElementById('yooc-toast-box'); if (!box) { box = document.createElement('div'); box.id = 'yooc-toast-box'; box.style.cssText = 'position:fixed; top:20px; left:50%; transform:translateX(-50%); z-index:9999999; display:flex; flex-direction:column; gap:10px; pointer-events:none;'; document.body.appendChild(box); } const el = document.createElement('div'); el.style.cssText = 'background:rgba(15,23,42,0.9); color:#fff; padding:12px 24px; border-radius:8px; font-size:14px; box-shadow:0 10px 25px rgba(0,0,0,0.2); border:1px solid #38bdf8; opacity:0; transition:opacity 0.3s, transform 0.3s; transform:translateY(-20px); font-weight:bold; text-align:center; backdrop-filter:blur(4px);'; el.innerText = msg; box.appendChild(el); setTimeout(() => { el.style.opacity = '1'; el.style.transform = 'translateY(0)'; }, 10); setTimeout(() => { el.style.opacity = '0'; el.style.transform = 'translateY(-20px)'; setTimeout(() => el.remove(), 300); }, duration); }; // --- 题库存储模块 --- function loadBank() { try { return JSON.parse(localStorage.getItem('yooc_text_bank_v7')) || {}; } catch(e) { return {}; } } function saveBank(bank) { localStorage.setItem('yooc_text_bank_v7', JSON.stringify(bank)); window.__yoocRenderOverview(); } function getRandAllow() { return localStorage.getItem('yooc_allow_random') !== 'false'; } function setRandAllow(val) { localStorage.setItem('yooc_allow_random', val); } function handleExamList(responseData) { if (!responseData || !Array.isArray(responseData.data)) return; let updated = false; const bank = loadBank(); responseData.data.forEach(exam => { if (exam.examId && exam.name) { const eId = exam.examId.toString(); window.__yooc.examNames[eId] = exam.name; if (bank[eId] && bank[eId].name !== exam.name) { bank[eId].name = exam.name; updated = true; } } }); if (updated) { saveBank(bank); if(document.getElementById('yooc-tab-bank').style.display === 'flex' && !window.__yooc.currentViewExam && !window.__yooc.isViewingCurrent) { window.__yoocRenderExamList(); } } } // --- 核心:动态全景收割引擎 --- function harvestKnowledge(sourceData, answerArray) { if (!sourceData) return; const pData = sourceData.data || sourceData || []; if (!Array.isArray(pData) || pData.length === 0) return; let currentExamId = window.__yooc.params.examId; if (!currentExamId && sourceData.data && sourceData.data[0] && sourceData.data[0].examId) { currentExamId = sourceData.data[0].examId.toString(); } if (!currentExamId) currentExamId = '未知试卷_' + new Date().getTime().toString().slice(-6); const bank = loadBank(); const realExamName = window.__yooc.examNames[currentExamId] || ('试卷 ID: ' + currentExamId); if (!bank[currentExamId]) { bank[currentExamId] = { name: realExamName, questions: {} }; } else if (bank[currentExamId].name !== realExamName) { bank[currentExamId].name = realExamName; } let newCount = 0; const subjectMap = {}; const cipherSet = new Set(); pData.forEach(sec => sec.subjects.forEach(sub => { if (sub.answer) cipherSet.add(sub.answer); })); const isCurrentDataHoneypot = cipherSet.size <= 2; pData.forEach(sec => { sec.subjects.forEach(sub => { const title = sub.title.join('').trim(); const options = sub.option.map(o => o[0] ? o[0].trim() : o.join('').trim()); subjectMap[sub.subjectId] = { id: sub.subjectId, title: title, options: options }; if (sub.answer && window.__yooc.dict[sub.answer] && !isCurrentDataHoneypot) { const correctTexts = window.__yooc.dict[sub.answer].map(idx => options[parseInt(idx)]).filter(Boolean); if (correctTexts.length > 0) { if (!bank[currentExamId].questions[title] || JSON.stringify(bank[currentExamId].questions[title].correct) !== JSON.stringify(correctTexts)) { bank[currentExamId].questions[title] = { id: sub.subjectId, options: options, correct: correctTexts }; newCount++; } } } }); }); if (answerArray && Array.isArray(answerArray)) { answerArray.forEach(item => { let subjId, correctIndexes; if (item.id && item.a) { subjId = item.id; correctIndexes = item.a; } else { subjId = Object.keys(item)[0]; if (item[subjId] && item[subjId][1] === 1) correctIndexes = Object.values(item[subjId][0])[0]; } if (subjId && correctIndexes && subjectMap[subjId]) { const { id, title, options } = subjectMap[subjId]; const correctTexts = correctIndexes.map(idx => options[parseInt(idx)]).filter(Boolean); if (correctTexts.length > 0) { if (!bank[currentExamId].questions[title] || JSON.stringify(bank[currentExamId].questions[title].correct) !== JSON.stringify(correctTexts)) { bank[currentExamId].questions[title] = { id: id, options: options, correct: correctTexts }; newCount++; } } } }); } if (newCount > 0) { saveBank(bank); window.__yoocToast(\`🎉 成功收割 \${newCount} 道新题!\`); } } function activeFetchHarvest() { const p = window.__yooc.params; if (!p.token || !p.yibanId || !p.examuserId || window.__yooc.harvested[p.examuserId]) return; window.__yooc.harvested[p.examuserId] = true; window.__yoocRenderOverview(); const fetchOpts = { headers: { 'Accept': '*/*', 'Origin': 'https://exam.yooc.me' } }; window.fetch('https://exambackend.yooc.me/api/exam/answer/get?examuserId=' + p.examuserId + '&token=' + p.token + '&yibanId=' + p.yibanId, fetchOpts) .then(r => r.json()) .then(data => { harvestKnowledge(data, data.answers || data.s_answers); window.__yoocRenderOverview(); }).catch(()=>{}); } function cachePaper(data) { if (!data || !data.data) return; window.__yooc.currentPaper = data.data; const cipherSet = new Set(); data.data.forEach(sec => { sec.subjects.forEach(sub => { if (sub.answer) cipherSet.add(sub.answer); }); }); window.__yooc.isHoneypot = cipherSet.size <= 2; window.__yoocRenderOverview(); if (window.__yooc.isViewingCurrent) window.__yoocViewCurrentPaper(); } // --- 网络拦截 --- function checkUrlAndParams(urlStr, responseData) { let updated = false; if (urlStr && typeof urlStr === 'string') { try { const urlObj = new URL(urlStr, window.location.origin); ['token', 'yibanId', 'examuserId', 'examId'].forEach(key => { const val = urlObj.searchParams.get(key); if (val && window.__yooc.params[key] !== val) { window.__yooc.params[key] = val; updated = true; } }); } catch (e) {} } if (responseData && responseData.data && typeof responseData.data === 'object' && !Array.isArray(responseData.data)) { if (responseData.data.examuserId && window.__yooc.params.examuserId !== responseData.data.examuserId.toString()) { window.__yooc.params.examuserId = responseData.data.examuserId.toString(); updated = true; } if (responseData.data.examId && window.__yooc.params.examId !== responseData.data.examId.toString()) { window.__yooc.params.examId = responseData.data.examId.toString(); updated = true; } } if (updated) window.__yoocRenderOverview(); } const originFetch = window.fetch; window.fetch = function(...args) { const url = (typeof args[0] === 'string') ? args[0] : (args[0] && args[0].url); checkUrlAndParams(url, null); return originFetch.apply(this, args).then(res => { try { res.clone().json().then(data => { checkUrlAndParams(url, data); if (url.includes('/api/exam/list/get')) { handleExamList(data); } if (url.includes('/api/exam/paper/get')) { cachePaper(data); harvestKnowledge(data, null); } if (url.includes('/api/exam/submit/action')) { harvestKnowledge({data: window.__yooc.currentPaper}, data.s_answers || data.answers); } if (url.includes('/api/exam/answer/get')) { harvestKnowledge(data, data.s_answers || data.answers); } if (url.includes('/api/exam/result/get')) { activeFetchHarvest(); } }).catch(()=>{}); } catch(e) {} return res; }); }; const originOpen = XMLHttpRequest.prototype.open; const originSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.open = function(method, url) { this._url = url; checkUrlAndParams(url, null); return originOpen.apply(this, arguments); }; XMLHttpRequest.prototype.send = function(...args) { this.addEventListener('load', function() { try { const data = JSON.parse(this.responseText); checkUrlAndParams(this._url, data); if (this._url.includes('/api/exam/list/get')) { handleExamList(data); } if (this._url.includes('/api/exam/paper/get')) { cachePaper(data); harvestKnowledge(data, null); } if (this._url.includes('/api/exam/submit/action')) { harvestKnowledge({data: window.__yooc.currentPaper}, data.s_answers || data.answers); } if (this._url.includes('/api/exam/answer/get')) { harvestKnowledge(data, data.s_answers || data.answers); } if (this._url.includes('/api/exam/result/get')) { activeFetchHarvest(); } } catch (e) {} }); return originSend.apply(this, args); }; // --- 底层翻页作答引擎 (极致稳定版) --- window.__yoocToggleRandom = function(e) { setRandAllow(e.checked); }; window.__yoocAutoSolve = async function() { if (window.__yooc.solving) return; window.__yooc.solving = true; const allowRandom = getRandAllow(); const btn = document.getElementById('yooc-solve-btn'); btn.innerHTML = '🔄 正在自动作答... 请勿触碰页面'; btn.style.background = '#f59e0b'; window.__yoocToast('🚀 作答引擎已启动,正在跨卷匹配题库...'); const rawBank = loadBank(); const flatBank = {}; Object.values(rawBank).forEach(exam => { if (exam.questions) Object.assign(flatBank, exam.questions); }); const { currentPaper, isHoneypot, dict } = window.__yooc; // 【革命性优化】骨架级提取:彻底去除所有中英文标点、空格、特殊符号,只留汉字字母数字进行比对。 const coreTxt = s => (s||'').replace(/[^\\u4e00-\\u9fa5a-zA-Z0-9]/g, ''); // 选项清洗:先去 A. 前缀,再提骨架 const optTxt = s => (s||'').replace(/^[A-Z][.、.\\s]*/, '').replace(/[^\\u4e00-\\u9fa5a-zA-Z0-9]/g, ''); const delay = ms => new Promise(r => setTimeout(r, ms)); let totalSolved = 0, totalGuessed = 0, totalSkipped = 0; while (window.__yooc.solving) { const oldPageText = document.body.innerText; // 记录当前页面的文本,用于比对翻页 let labels = Array.from(document.querySelectorAll('label, li, .option-item, .yiban-option, .exam-option-item')).filter(el => el.textContent.trim().length > 0); if (labels.length === 0) { document.querySelectorAll('input[type=\"radio\"], input[type=\"checkbox\"]').forEach(inp => { const p = inp.closest('label, li, div'); if (p && p.textContent.trim().length > 0 && !labels.includes(p)) labels.push(p); }); } if (labels.length > 0) { const pageCoreText = coreTxt(document.body.innerText); let activeSubs = []; if (currentPaper && currentPaper.length > 0) { activeSubs = currentPaper.flatMap(sec => sec.subjects).filter(sub => { const titleCore = coreTxt(sub.title.join('')); // 【修复跳题】仅提取前12个骨架字符进行匹配,无视截断和标点错乱 const matchStr = titleCore.length > 12 ? titleCore.substring(0, 12) : titleCore; return pageCoreText.includes(matchStr) && matchStr.length > 0; }); } if (activeSubs.length > 0) { activeSubs.forEach(sub => { const origTitle = sub.title.join('').trim(); const optionsTexts = sub.option.map(o => (o[0] ? o[0] : o.join(''))); let targets = []; let hasDefinitive = false; let alreadyCheckedAny = false; const subNodes = []; optionsTexts.forEach(opt => { const targetCore = optTxt(opt); const node = labels.find(l => optTxt(l.textContent) === targetCore && targetCore.length > 0); if (node) { subNodes.push({ opt: opt, node: node }); const inp = node.querySelector('input'); if ((inp && inp.checked) || node.className.includes('active') || node.className.includes('checked') || node.getAttribute('aria-checked') === 'true') { alreadyCheckedAny = true; } } }); if (flatBank[origTitle] && flatBank[origTitle].correct) { targets = flatBank[origTitle].correct; hasDefinitive = true; totalSolved++; } else if (!isHoneypot && dict[sub.answer]) { targets = dict[sub.answer].map(idx => optionsTexts[parseInt(idx)]); hasDefinitive = true; totalSolved++; } else if (allowRandom) { if (alreadyCheckedAny) { totalSkipped++; } else if (optionsTexts.length > 0) { targets = [optionsTexts[0]]; totalGuessed++; } } else { totalSkipped++; } subNodes.forEach(sn => { const isTarget = targets.includes(sn.opt); const inp = sn.node.querySelector('input'); const isChecked = (inp && inp.checked) || sn.node.className.includes('active') || sn.node.className.includes('checked') || sn.node.getAttribute('aria-checked') === 'true'; if (hasDefinitive) { if (isTarget && !isChecked) { if (inp) inp.click(); else sn.node.click(); } else if (!isTarget && isChecked) { if (inp) inp.click(); else sn.node.click(); } } else if (targets.length > 0) { if (isTarget && !isChecked) { if (inp) inp.click(); else sn.node.click(); } } }); }); } else { // 备用 DOM 匹配,同样应用骨架逻辑 let foundInBank = false; let anyChecked = false; let optionNodes = []; labels.forEach(node => { const txt = node.textContent.trim(); if (/^[A-D][.、\\s]/.test(txt) || node.querySelector('input')) { optionNodes.push(node); const inp = node.querySelector('input'); if ((inp && inp.checked) || node.className.includes('active') || node.className.includes('checked') || node.getAttribute('aria-checked') === 'true') { anyChecked = true; } } }); for (let qTitle in flatBank) { const titleCore = coreTxt(qTitle); const matchStr = titleCore.length > 12 ? titleCore.substring(0, 12) : titleCore; if (pageCoreText.includes(matchStr) && flatBank[qTitle].correct) { flatBank[qTitle].correct.forEach(tgt => { const tgtCore = optTxt(tgt); const node = labels.find(l => optTxt(l.textContent) === tgtCore && tgtCore.length > 0); if (node) { foundInBank = true; const inp = node.querySelector('input'); const isChecked = (inp && inp.checked) || node.className.includes('active') || node.className.includes('checked') || node.getAttribute('aria-checked') === 'true'; if (!isChecked) { if (inp) inp.click(); else node.click(); } } }); } } if (!foundInBank && allowRandom) { if (anyChecked) totalSkipped++; else if (optionNodes.length > 0) { optionNodes[0].click(); totalGuessed++; } } else if (!foundInBank) { totalSkipped++; } } } // 【修复跳题】基于 DOM 文本变更探测,确保页面真的刷新了再进入下一次循环 const nextBtn = Array.from(document.querySelectorAll('button, div, span, a')).find(el => (el.textContent.trim() === '下一题' || el.textContent.trim() === '下一页') && el.offsetParent !== null && !el.disabled && !el.className.includes('disabled') ); if (nextBtn) { nextBtn.click(); let waited = 0; // 等待直到页面文本改变,或超时 3000ms while(document.body.innerText === oldPageText && waited < 3000) { await delay(100); waited += 100; } await delay(300); // 额外缓冲,确保选项渲染完成 } else { break; } } const submitEle = Array.from(document.querySelectorAll('button, div, span, a')).find(el => (el.textContent.trim() === '交卷' || el.textContent.trim() === '提交') && el.offsetParent !== null ); if (submitEle) { submitEle.click(); await delay(500); const confirmBtn = Array.from(document.querySelectorAll('button, div, span, a')).find(el => (el.textContent.trim() === '确定' || el.textContent.trim() === '确认交卷') && el.offsetParent !== null ); if (confirmBtn) confirmBtn.click(); } window.__yooc.solving = false; btn.innerHTML = '🚀 重新扫描并作答'; btn.style.background = '#0ea5e9'; window.__yoocToast(\`✅ 答卷完毕!命中:\${totalSolved} | 兜底A:\${totalGuessed} | 跳过:\${totalSkipped}\`, 6000); }; // --- 现代化 UI 与题库分卷渲染 --- window.__yoocSwitchTab = function(tabId) { document.querySelectorAll('.yooc-tab-content').forEach(el => el.style.display = 'none'); document.querySelectorAll('.yooc-tab').forEach(el => el.classList.remove('active')); document.getElementById(tabId).style.display = 'flex'; document.querySelector(\`[data-target="\${tabId}"]\`).classList.add('active'); window.__yooc.isViewingCurrent = false; if(tabId === 'yooc-tab-bank') window.__yoocRenderExamList(); }; window.__yoocRenderExamList = function() { const bank = loadBank(); const container = document.getElementById('yooc-bank-content'); if(!container) return; let html = ''; // 实时考试面板入口 if (window.__yooc.currentPaper && window.__yooc.currentPaper.length > 0) { html += \`
✨ 正在进行的考试 (实时小抄)
当前屏幕试卷分析
点击查看所有题目与已知答案
📝
\`; } const examIds = Object.keys(bank); if(examIds.length === 0) { html += '
暂无本地收割记录,请进入考试获取。
'; container.innerHTML = html; return; } html += '
已收录以下试卷题库,点击查看:
'; examIds.forEach(eid => { const exam = bank[eid]; const qCount = Object.keys(exam.questions).length; html += \`
\${exam.name}
收录题数:\${qCount} | 试卷ID: \${eid}
👉
\`; }); container.innerHTML = html; }; // --- 实时小抄视图 --- window.__yoocViewCurrentPaper = function() { window.__yooc.isViewingCurrent = true; const bank = loadBank(); const flatBank = {}; Object.values(bank).forEach(exam => { if (exam.questions) Object.assign(flatBank, exam.questions); }); const { currentPaper, isHoneypot, dict } = window.__yooc; const container = document.getElementById('yooc-bank-content'); let html = \`
✨ 当前试卷实时小抄
\`; if (!currentPaper || currentPaper.length === 0) { html += '
未获取到当前试卷,请刷新页面重试。
'; } else { let qIdx = 1; currentPaper.forEach(sec => { sec.subjects.forEach(sub => { const title = sub.title.join('').trim(); const optionsTexts = sub.option.map(o => (o[0] ? o[0] : o.join(''))); let targets = []; let hasAnswer = false; if (flatBank[title] && flatBank[title].correct) { targets = flatBank[title].correct; hasAnswer = true; } else if (!isHoneypot && dict[sub.answer]) { targets = dict[sub.answer].map(idx => optionsTexts[parseInt(idx)]); hasAnswer = true; } const displayId = sub.subjectId ? \` [ID: \${sub.subjectId}]\` : ''; html += \`
\${qIdx}. \${title}\${displayId}
\`; if (optionsTexts.length > 0) { optionsTexts.forEach((opt, idx) => { const isCorrect = targets.includes(opt); const cls = isCorrect ? 'yooc-opt-correct' : (hasAnswer ? 'yooc-opt-wrong' : ''); const icon = isCorrect ? '✔️' : (hasAnswer ? '❌' : '⚪'); html += \`
\${icon} \${String.fromCharCode(65+idx)}. \${opt}
\`; }); } if (!hasAnswer) { html += '
⏳ 暂无已知答案,请手动填写或盲选
'; } html += '
'; qIdx++; }); }); } container.innerHTML = html; }; window.__yoocViewExam = function(examId) { window.__yooc.currentViewExam = examId; window.__yoocRenderQList(); }; window.__yoocBackToExams = function() { window.__yooc.currentViewExam = null; window.__yooc.isViewingCurrent = false; document.getElementById('yooc-q-search').value = ''; window.__yoocRenderExamList(); }; window.__yoocSearchQ = function(val) { window.__yoocRenderQList(val.trim()); }; window.__yoocRenderQList = function(searchTerm = '') { const bank = loadBank(); const examId = window.__yooc.currentViewExam; if(!examId || !bank[examId]) return; const questions = bank[examId].questions; const keys = Object.keys(questions).filter(k => k.includes(searchTerm)); const container = document.getElementById('yooc-bank-content'); let html = \`
\`; if(keys.length === 0) { html += '
未找到匹配题目
'; } else { keys.forEach((q, i) => { const qData = questions[q]; const displayId = qData.id ? \` [ID: \${qData.id}]\` : ''; html += \`
\${i+1}. \${q}\${displayId}
\`; if (qData.options && qData.options.length > 0) { qData.options.forEach((opt, idx) => { const isCorrect = qData.correct.includes(opt); const cls = isCorrect ? 'yooc-opt-correct' : 'yooc-opt-wrong'; const icon = isCorrect ? '✔️' : '❌'; html += \`
\${icon} \${String.fromCharCode(65+idx)}. \${opt}
\`; }); } else { html += \`
✔️ \${(qData.correct || qData).join(' | ')}
\`; } html += '
'; }); } container.innerHTML = html; }; // --- 导入与导出 (完美排版版) --- window.__yoocExport = function(type) { const bank = loadBank(); let content = '', filename = ''; if (type === 'json') { content = JSON.stringify(bank, null, 2); filename = 'yooc_分卷题库备份_v7.json'; } else { Object.keys(bank).forEach(eid => { const exam = bank[eid]; content += '======================================\\n'; content += '【试卷】' + exam.name + ' (ID: ' + eid + ')\\n'; content += '======================================\\n\\n'; let qIdx = 1; Object.keys(exam.questions).forEach(q => { const qData = exam.questions[q]; const idStr = qData.id ? ' [ID: ' + qData.id + ']' : ''; content += qIdx + '. ' + q + idStr + '\\n'; if(qData.options && qData.options.length > 0) { qData.options.forEach((opt, i) => { content += ' ' + String.fromCharCode(65+i) + '. ' + opt + '\\n'; }); let correctLetters = []; if(qData.correct) { qData.correct.forEach(c => { let idx = qData.options.indexOf(c); if(idx !== -1) correctLetters.push(String.fromCharCode(65+idx) + '. ' + c); else correctLetters.push(c); }); } content += '✅ 正确答案: ' + correctLetters.join(' | ') + '\\n\\n'; } else { content += '✅ 正确答案: ' + (qData.correct || qData).join(' | ') + '\\n\\n'; } qIdx++; }); }); filename = 'yooc_全景题库大全.txt'; } const blob = new Blob([content], {type: 'text/plain;charset=utf-8'}); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = filename; a.click(); window.__yoocToast('✅ 题库导出成功!', 2000); }; window.__yoocImport = function() { const input = document.createElement('input'); input.type = 'file'; input.accept = '.json'; input.onchange = e => { const file = e.target.files[0]; const reader = new FileReader(); reader.onload = ev => { try { const imported = JSON.parse(ev.target.result); const bank = loadBank(); Object.assign(bank, imported); saveBank(bank); window.__yoocToast('✅ 导入成功!已更新本地题库。'); } catch(err) { window.__yoocToast('❌ 格式错误,导入失败!'); } }; reader.readAsText(file); }; input.click(); }; window.__yoocClearData = function(btn) { if (btn.dataset.confirm === '1') { localStorage.removeItem('yooc_text_bank_v7'); window.__yoocToast('🗑️ 已清空所有本地题库数据!'); btn.dataset.confirm = '0'; btn.innerHTML = '🗑️ 清空本地题库'; window.__yoocRenderOverview(); if(document.getElementById('yooc-tab-bank').style.display !== 'none') window.__yoocSwitchTab('yooc-tab-home'); } else { btn.dataset.confirm = '1'; btn.innerHTML = '⚠️ 再次点击确认清空'; setTimeout(() => { if (btn.dataset.confirm === '1') { btn.dataset.confirm = '0'; btn.innerHTML = '🗑️ 清空本地题库'; } }, 3000); } }; window.__yoocRenderOverview = function() { const bank = loadBank(); let examCount = Object.keys(bank).length; let qCount = 0; Object.values(bank).forEach(e => { qCount += Object.keys(e.questions).length; }); const honeypotStatus = window.__yooc.currentPaper.length > 0 ? (window.__yooc.isHoneypot ? '🚨 蜜罐激活' : '🟢 密文安全') : '等待发卷'; const p = window.__yooc.params; const activeStatus = (p.examuserId && window.__yooc.harvested[p.examuserId]) ? '✔️ 成功' : '待触发'; const el = document.getElementById('yooc-overview-content'); if(el) { el.innerHTML = \`
题库规模 \${examCount} 卷 / \${qCount} 题
密文雷达 \${honeypotStatus}
上帝视角提取 \${activeStatus}
\`; } const badge = document.getElementById('yooc-badge-count'); if(badge) badge.innerText = qCount; }; window.__yoocTogglePanel = function() { const wrap = document.getElementById('yooc-wrapper'); const btn = document.getElementById('yooc-toggle-btn'); if (wrap.style.display === 'none') { wrap.style.display = 'flex'; btn.innerText = '➖'; } else { wrap.style.display = 'none'; btn.innerText = '➕'; } }; window.__yoocClosePanel = function() { document.getElementById('yooc-sniffer-panel').style.display = 'none'; }; function initPanel() { if (document.getElementById('yooc-sniffer-panel')) return; injectCSS(); const panel = document.createElement('div'); panel.id = 'yooc-sniffer-panel'; panel.style.cssText = 'position: fixed; top: 120px; right: 20px; width: 320px; background: rgba(15, 23, 42, 0.95); color: #f8fafc; border-radius: 12px; box-shadow: 0 15px 35px rgba(0,0,0,0.5); z-index: 9999999; border: 1px solid #334155; backdrop-filter: blur(10px); overflow: hidden; display: flex; flex-direction: column;'; const randChecked = getRandAllow() ? 'checked' : ''; panel.innerHTML = \`
🤖

YOOC易班助手 v1.0

📊 运行中心
📚 题库 0
⚙️ 设置
\`; document.body.appendChild(panel); const header = document.getElementById('yooc-header'); let isDragging = false; let offsetX = 0; let offsetY = 0; header.addEventListener('mousedown', function(e) { if(e.target.tagName.toLowerCase() === 'span') return; e.preventDefault(); isDragging = true; const rect = panel.getBoundingClientRect(); offsetX = e.clientX - rect.left; offsetY = e.clientY - rect.top; panel.style.right = 'auto'; panel.style.bottom = 'auto'; }); document.addEventListener('mousemove', function(e) { if (!isDragging) return; let x = e.clientX - offsetX; let y = e.clientY - offsetY; x = Math.max(0, Math.min(x, window.innerWidth - panel.offsetWidth)); y = Math.max(0, Math.min(y, window.innerHeight - panel.offsetHeight)); panel.style.left = x + 'px'; panel.style.top = y + 'px'; }); document.addEventListener('mouseup', function() { isDragging = false; }); window.__yoocRenderOverview(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initPanel); } else { initPanel(); } })(); `; const scriptNode = document.createElement('script'); scriptNode.textContent = injectCode; (document.head || document.documentElement).appendChild(scriptNode); scriptNode.remove(); })();