// ==UserScript== // @name 柠檬文才学堂全功能助手 // @namespace http://tampermonkey.net/ // @version 2.1 // @description 考试自动答题 + 答案提取 + 题库管理 // @author XCJY // @match *://*.wencaischool.net/* // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @grant GM_notification // @grant unsafeWindow // @run-at document-end // ==/UserScript== (function() { 'use strict'; // 全局配置 const CONFIG = { debug: true, autoDetectPageType: true, autoStart: true, showControlPanel: true, bypassSecurity: true, saveAnswers: true, questionBankKey: 'lemonysoft_question_bank_v2', answerHistoryKey: 'lemonysoft_answer_history_v2', panelCheckInterval: 1000, // 检查控制面板存在的间隔 maxRetryCount: 10, // 最大重试次数 waitForLoadDelay: 2000 // 等待页面加载的延迟 }; // 页面类型检测 const PageType = { UNKNOWN: 0, EXAM: 1, // 考试界面 REVIEW: 2, // 试卷回顾 LIST: 3, // 考试列表 LOGIN: 4 // 登录页面 }; // 单例模式管理器 class SingletonManager { constructor() { this.instance = null; this.isInitializing = false; this.initialized = false; } getInstance() { if (!this.instance && !this.isInitializing) { this.isInitializing = true; this.instance = new LemonysoftHelper(); this.instance.init().then(() => { this.initialized = true; this.isInitializing = false; console.log('🍋 柠檬助手初始化完成'); }).catch(error => { console.error('初始化失败:', error); this.isInitializing = false; this.instance = null; }); } return this.instance; } reset() { this.instance = null; this.initialized = false; this.isInitializing = false; } } // 防抖函数 function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } // 主控制器 class LemonysoftHelper { constructor() { this.pageType = PageType.UNKNOWN; this.examHelper = null; this.answerExtractor = null; this.questionBank = null; this.controlPanel = null; this.isInitialized = false; this.retryCount = 0; this.panelCheckTimer = null; this.observer = null; this.panelId = 'lemonysoft-helper-panel-' + Math.random().toString(36).substr(2, 9); } async init() { console.log('🍋 柠檬文才学堂助手启动 (修复版)'); // 等待页面稳定 await this.waitForPageStable(); // 检测页面类型 this.detectPageType(); // 加载题库 this.loadQuestionBank(); // 根据页面类型初始化相应功能 this.initializeForPageType(); // 添加控制面板(使用防抖避免重复添加) this.debouncedAddControlPanel = debounce(() => { this.addControlPanel(); }, 500); if (CONFIG.showControlPanel) { this.debouncedAddControlPanel(); } // 添加全局快捷键 this.addKeyboardShortcuts(); // 设置页面变化监控 this.setupPageObserver(); // 设置控制面板检查定时器 this.setupPanelChecker(); this.isInitialized = true; console.log(`页面类型: ${this.getPageTypeName()}`, 'success'); } // 等待页面稳定 waitForPageStable() { return new Promise(resolve => { // 如果页面已经加载完成 if (document.readyState === 'complete') { setTimeout(resolve, CONFIG.waitForLoadDelay); } else { // 等待页面加载完成 document.addEventListener('DOMContentLoaded', () => { setTimeout(resolve, CONFIG.waitForLoadDelay); }); } }); } // 检测页面类型 detectPageType() { const url = window.location.href; const html = document.body.innerHTML; // 考试界面特征 - 加强检测 const isExamPage = ( (url.includes('online-exam/exam') || url.includes('oe-web/online-exam/exam') || url.includes('exam/do_exam') || url.includes('exam/do_test')) || html.includes('正在答题') || html.includes('在线考试') || (html.includes('tblItem_') && !html.includes('参考答案:')) || (html.includes('lemonysoft_item_') && !html.includes('得分: { if (this.examHelper) { this.examHelper.extractQuestions(); this.examHelper.autoFillAnswers(); } }, 2500); } } // 初始化答案提取器 initAnswerExtractor() { if (this.answerExtractor) return; console.log('初始化答案提取器...'); this.answerExtractor = new AnswerExtractor(this); // 自动提取答案 if (CONFIG.autoStart) { setTimeout(() => { if (this.answerExtractor) { this.answerExtractor.extractAllAnswers(); } }, 1500); } } // 初始化考试列表助手 initExamListHelper() { console.log('检测到考试列表页面'); } // 初始化登录助手 initLoginHelper() { console.log('检测到登录页面'); } // 恢复键盘功能(绕过安全限制) restoreKeyboard() { console.log('恢复键盘功能...'); // 解除键盘限制 document.onkeydown = null; document.onkeyup = null; document.onkeypress = null; // 解除复制限制 document.onselectstart = null; document.oncopy = null; document.oncut = null; document.onpaste = null; // 恢复所有元素的复制功能 document.querySelectorAll('*').forEach(element => { element.onselectstart = null; element.oncopy = null; element.oncut = null; element.onpaste = null; }); // 添加CSS样式解除选择限制 this.addSecurityOverrideStyles(); } // 添加安全覆盖样式 addSecurityOverrideStyles() { const styleId = 'lemonysoft-security-override'; if (!document.getElementById(styleId)) { const style = document.createElement('style'); style.id = styleId; style.textContent = ` * { user-select: text !important; -webkit-user-select: text !important; -moz-user-select: text !important; -ms-user-select: text !important; } input, textarea, select { user-select: auto !important; } body * { -webkit-user-select: text !important; -moz-user-select: text !important; -ms-user-select: text !important; user-select: text !important; } `; document.head.appendChild(style); } } // 加载题库 loadQuestionBank() { try { const saved = GM_getValue(CONFIG.questionBankKey); if (saved) { this.questionBank = JSON.parse(saved); console.log(`题库已加载: ${this.questionBank.questions?.length || 0} 道题目`); return this.questionBank; } } catch (error) { console.error('加载题库失败:', error); } // 如果不存在,初始化空题库 this.questionBank = { platform: 'lemonysoft', course: '', examName: '', examId: '', totalQuestions: 0, totalScore: 0, createdDate: new Date().toISOString(), updatedDate: new Date().toISOString(), questions: [] }; return this.questionBank; } // 保存题库 saveQuestionBank() { try { this.questionBank.updatedDate = new Date().toISOString(); GM_setValue(CONFIG.questionBankKey, JSON.stringify(this.questionBank)); console.log(`题库已保存: ${this.questionBank.questions.length} 道题目`, 'success'); this.showNotification('题库保存成功', `已保存 ${this.questionBank.questions.length} 道题目`); return true; } catch (error) { console.error(`保存题库失败: ${error.message}`); return false; } } // 添加控制面板(修复版,防止重复添加) addControlPanel() { // 检查是否已经存在控制面板 const existingPanel = document.getElementById(this.panelId); if (existingPanel) { console.log('控制面板已存在,跳过添加'); this.controlPanel = existingPanel; this.updatePanelContent(); return; } // 检查是否有其他相似的控制面板 const similarPanels = document.querySelectorAll('[id^="lemonysoft-helper-panel"]'); similarPanels.forEach(panel => { if (panel.id !== this.panelId) { console.log('移除旧的控制面板:', panel.id); panel.remove(); } }); // 创建新的控制面板 this.createControlPanel(); } // 创建控制面板 createControlPanel() { const panel = document.createElement('div'); panel.id = this.panelId; panel.innerHTML = `
🍋 柠檬助手 ${this.getPageTypeName()}
📊 状态信息
加载中...
🎯 功能操作
🔍 题库搜索
⚙️ 设置
`; document.body.appendChild(panel); this.controlPanel = panel; // 添加事件监听 this.setupPanelEvents(); // 根据页面类型更新按钮 this.updatePanelButtons(); // 初始化面板拖动 this.initPanelDrag(); console.log('控制面板已添加'); } // 更新面板内容 updatePanelContent() { if (!this.controlPanel) return; // 更新页面类型显示 const titleElement = this.controlPanel.querySelector('.panel-title span:nth-child(2)'); if (titleElement) { titleElement.textContent = this.getPageTypeName(); } // 更新按钮 this.updatePanelButtons(); // 更新状态 this.updateStatus(); } // 更新面板按钮(根据页面类型) updatePanelButtons() { if (!this.controlPanel) return; const buttonContainer = this.controlPanel.querySelector('#function-buttons'); if (!buttonContainer) return; let buttons = ''; switch (this.pageType) { case PageType.EXAM: buttons = `
`; break; case PageType.REVIEW: buttons = `
`; break; default: buttons = ` `; } buttonContainer.innerHTML = buttons; // 重新绑定事件 this.bindFunctionButtons(); } // 设置面板事件 setupPanelEvents() { if (!this.controlPanel) return; const panel = this.controlPanel; // 关闭按钮 panel.querySelector('#close-panel').addEventListener('click', (e) => { e.stopPropagation(); this.hideControlPanel(); }); // 最小化按钮 panel.querySelector('#btn-minimize').addEventListener('click', (e) => { e.stopPropagation(); panel.classList.toggle('minimized'); const btn = panel.querySelector('#btn-minimize'); btn.textContent = panel.classList.contains('minimized') ? '展开' : '最小化'; }); // 搜索功能 const searchInput = panel.querySelector('#search-input'); const searchResults = panel.querySelector('#search-results'); if (searchInput && searchResults) { searchInput.addEventListener('input', (e) => { const keyword = e.target.value.trim(); if (keyword.length < 2) { searchResults.innerHTML = ''; return; } const results = this.searchQuestion(keyword); if (results.length > 0) { let html = ''; results.slice(0, 10).forEach(question => { html += `
${question.index || ''}题: ${question.text.substring(0, 50)}...
答案: ${question.answer}
`; }); searchResults.innerHTML = html; } else { searchResults.innerHTML = '
未找到相关题目
'; } }); } // 设置按钮 const settingsBtn = panel.querySelector('#btn-settings'); if (settingsBtn) { settingsBtn.addEventListener('click', (e) => { e.stopPropagation(); this.showSettingsDialog(); }); } // 帮助按钮 const helpBtn = panel.querySelector('#btn-help'); if (helpBtn) { helpBtn.addEventListener('click', (e) => { e.stopPropagation(); this.showHelpDialog(); }); } // 双击标题栏最小化 panel.querySelector('#panel-header').addEventListener('dblclick', (e) => { e.stopPropagation(); panel.classList.toggle('minimized'); const btn = panel.querySelector('#btn-minimize'); if (btn) { btn.textContent = panel.classList.contains('minimized') ? '展开' : '最小化'; } }); } // 绑定功能按钮事件 bindFunctionButtons() { if (!this.controlPanel) return; const panel = this.controlPanel; // 考试界面按钮 if (this.pageType === PageType.EXAM) { const extractBtn = panel.querySelector('#btn-extract'); if (extractBtn) { extractBtn.addEventListener('click', (e) => { e.stopPropagation(); if (this.examHelper) { this.examHelper.extractQuestions(); this.updateStatus(); } }); } const autoAnswerBtn = panel.querySelector('#btn-auto-answer'); if (autoAnswerBtn) { autoAnswerBtn.addEventListener('click', (e) => { e.stopPropagation(); if (this.examHelper) { this.examHelper.autoFillAnswers(); this.updateStatus(); } }); } const bypassBtn = panel.querySelector('#btn-bypass'); if (bypassBtn) { bypassBtn.addEventListener('click', (e) => { e.stopPropagation(); this.restoreKeyboard(); this.showNotification('安全限制已解除', '键盘和复制功能已恢复'); }); } const searchAnswerBtn = panel.querySelector('#btn-search-answer'); if (searchAnswerBtn) { searchAnswerBtn.addEventListener('click', (e) => { e.stopPropagation(); this.showSearchDialog(); }); } const submitBtn = panel.querySelector('#btn-submit'); if (submitBtn) { submitBtn.addEventListener('click', (e) => { e.stopPropagation(); if (this.examHelper) { this.examHelper.submitExam(); } }); } } // 回顾界面按钮 if (this.pageType === PageType.REVIEW) { const extractAnswersBtn = panel.querySelector('#btn-extract-answers'); if (extractAnswersBtn) { extractAnswersBtn.addEventListener('click', (e) => { e.stopPropagation(); if (this.answerExtractor) { this.answerExtractor.extractAllAnswers(); this.updateStatus(); } }); } const saveBankBtn = panel.querySelector('#btn-save-bank'); if (saveBankBtn) { saveBankBtn.addEventListener('click', (e) => { e.stopPropagation(); this.saveQuestionBank(); }); } const exportJsonBtn = panel.querySelector('#btn-export-json'); if (exportJsonBtn) { exportJsonBtn.addEventListener('click', (e) => { e.stopPropagation(); this.exportQuestionBank('json'); }); } const exportCsvBtn = panel.querySelector('#btn-export-csv'); if (exportCsvBtn) { exportCsvBtn.addEventListener('click', (e) => { e.stopPropagation(); this.exportQuestionBank('csv'); }); } const mergeBankBtn = panel.querySelector('#btn-merge-bank'); if (mergeBankBtn) { mergeBankBtn.addEventListener('click', (e) => { e.stopPropagation(); if (this.answerExtractor) { this.mergeQuestionBank(this.answerExtractor.questionBank?.questions || []); } }); } } // 通用按钮 const generalHelpBtn = panel.querySelector('#btn-general-help'); if (generalHelpBtn) { generalHelpBtn.addEventListener('click', (e) => { e.stopPropagation(); this.showHelpDialog(); }); } const manageBankBtn = panel.querySelector('#btn-manage-bank'); if (manageBankBtn) { manageBankBtn.addEventListener('click', (e) => { e.stopPropagation(); this.showQuestionBankManager(); }); } } // 初始化面板拖动 initPanelDrag() { if (!this.controlPanel) return; const panel = this.controlPanel; const header = panel.querySelector('#panel-header'); let isDragging = false; let offsetX, offsetY; header.addEventListener('mousedown', startDrag); function startDrag(e) { if (e.target.tagName === 'BUTTON' || e.target.tagName === 'INPUT') return; isDragging = true; offsetX = e.clientX - panel.offsetLeft; offsetY = e.clientY - panel.offsetTop; document.addEventListener('mousemove', drag); document.addEventListener('mouseup', stopDrag); panel.style.cursor = 'move'; } function drag(e) { if (!isDragging) return; const x = e.clientX - offsetX; const y = e.clientY - offsetY; // 限制在窗口范围内 const maxX = window.innerWidth - panel.offsetWidth; const maxY = window.innerHeight - panel.offsetHeight; panel.style.left = Math.max(0, Math.min(x, maxX)) + 'px'; panel.style.top = Math.max(0, Math.min(y, maxY)) + 'px'; panel.style.right = 'auto'; } function stopDrag() { isDragging = false; document.removeEventListener('mousemove', drag); document.removeEventListener('mouseup', stopDrag); panel.style.cursor = 'default'; } } // 隐藏控制面板 hideControlPanel() { if (this.controlPanel) { this.controlPanel.style.display = 'none'; } } // 显示控制面板 showControlPanel() { if (this.controlPanel) { this.controlPanel.style.display = 'block'; } } // 设置页面变化监控 setupPageObserver() { if (this.observer) { this.observer.disconnect(); } // 监控整个文档的变化 this.observer = new MutationObserver((mutations) => { let shouldUpdate = false; for (const mutation of mutations) { // 检查是否有新节点添加 if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { shouldUpdate = true; break; } // 检查URL变化 if (mutation.type === 'characterData' || mutation.type === 'attributes') { shouldUpdate = true; break; } } if (shouldUpdate) { this.handlePageChange(); } }); // 开始监控 this.observer.observe(document.body, { childList: true, subtree: true, attributes: true, characterData: true }); } // 处理页面变化 handlePageChange() { console.log('检测到页面变化,重新检测页面类型...'); // 防抖处理,避免频繁触发 if (this.pageChangeHandler) { clearTimeout(this.pageChangeHandler); } this.pageChangeHandler = setTimeout(() => { const oldPageType = this.pageType; this.detectPageType(); // 如果页面类型发生变化 if (oldPageType !== this.pageType) { console.log(`页面类型变化: ${this.getPageTypeName(oldPageType)} -> ${this.getPageTypeName()}`); // 重新初始化功能 this.initializeForPageType(); // 更新控制面板 if (this.controlPanel) { this.updatePanelContent(); } else if (CONFIG.showControlPanel) { this.debouncedAddControlPanel(); } } }, 1000); } // 设置控制面板检查定时器 setupPanelChecker() { if (this.panelCheckTimer) { clearInterval(this.panelCheckTimer); } this.panelCheckTimer = setInterval(() => { this.checkControlPanel(); }, CONFIG.panelCheckInterval); } // 检查控制面板状态 checkControlPanel() { // 检查控制面板是否存在 if (!this.controlPanel || !document.body.contains(this.controlPanel)) { console.log('控制面板丢失,重新创建...'); this.controlPanel = null; if (CONFIG.showControlPanel) { this.debouncedAddControlPanel(); } return; } // 检查是否有重复的控制面板 const panels = document.querySelectorAll('[id^="lemonysoft-helper-panel"]'); if (panels.length > 1) { console.log(`发现 ${panels.length} 个控制面板,清理多余的...`); // 保留当前控制面板,删除其他 panels.forEach(panel => { if (panel.id !== this.panelId) { panel.remove(); } }); } // 更新状态 this.updateStatus(); } // 更新状态显示 updateStatus() { if (!this.controlPanel) return; const statusElement = this.controlPanel.querySelector('#status-display'); const progressBar = this.controlPanel.querySelector('#progress-fill'); if (!statusElement) return; let statusHtml = ''; switch (this.pageType) { case PageType.EXAM: const examStats = this.examHelper?.getStats() || { total: 0, answered: 0 }; statusHtml = `
题目总数: ${examStats.total}
已答题目: ${examStats.answered}
答题进度: ${examStats.total ? Math.round(examStats.answered/examStats.total*100) : 0}%
`; if (progressBar && examStats.total > 0) { progressBar.style.width = `${examStats.answered/examStats.total*100}%`; } break; case PageType.REVIEW: const extractStats = this.answerExtractor?.getStats() || { total: 0, extracted: 0 }; statusHtml = `
提取题目: ${extractStats.extracted}/${extractStats.total}
题库总数: ${this.questionBank.questions.length}
最后更新: ${new Date(this.questionBank.updatedDate).toLocaleDateString()}
`; break; default: statusHtml = `
题库总数: ${this.questionBank.questions.length}
页面类型: ${this.getPageTypeName()}
`; } statusElement.innerHTML = statusHtml; } // 搜索题目 searchQuestion(keyword) { if (!keyword || !this.questionBank.questions.length) return []; keyword = keyword.toLowerCase(); return this.questionBank.questions.filter(question => question.text && question.text.toLowerCase().includes(keyword) ); } // 显示通知 showNotification(title, message, type = 'info') { // 创建自定义通知 const notification = document.createElement('div'); notification.style.cssText = ` position: fixed; top: 20px; right: 20px; background: ${type === 'success' ? '#27ae60' : type === 'error' ? '#e74c3c' : '#3498db'}; color: white; padding: 12px 20px; border-radius: 6px; z-index: 100001; box-shadow: 0 4px 12px rgba(0,0,0,0.2); max-width: 300px; animation: slideIn 0.3s ease; `; // 添加CSS动画 if (!document.querySelector('#notification-style')) { const style = document.createElement('style'); style.id = 'notification-style'; style.textContent = ` @keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } `; document.head.appendChild(style); } notification.innerHTML = `${title}
${message}`; document.body.appendChild(notification); setTimeout(() => { notification.style.opacity = '0'; notification.style.transform = 'translateX(100%)'; setTimeout(() => { if (notification.parentNode) { notification.parentNode.removeChild(notification); } }, 300); }, 3000); } // 添加全局快捷键 addKeyboardShortcuts() { document.addEventListener('keydown', (e) => { // Ctrl+Shift+L: 显示/隐藏控制面板 if (e.ctrlKey && e.shiftKey && e.key === 'L') { e.preventDefault(); if (this.controlPanel) { this.controlPanel.style.display = this.controlPanel.style.display === 'none' ? 'block' : 'none'; } else if (CONFIG.showControlPanel) { this.debouncedAddControlPanel(); } } // Ctrl+Shift+A: 自动答题(考试界面) if (e.ctrlKey && e.shiftKey && e.key === 'A') { e.preventDefault(); if (this.pageType === PageType.EXAM && this.examHelper) { this.examHelper.autoFillAnswers(); } } // Ctrl+Shift+S: 搜索题目 if (e.ctrlKey && e.shiftKey && e.key === 'S') { e.preventDefault(); this.showSearchDialog(); } }); } // 以下方法需要根据实际情况实现... showSettingsDialog() { this.showNotification('设置', '设置功能暂未实现'); } showHelpDialog() { this.showNotification('帮助', '帮助功能暂未实现'); } showSearchDialog() { this.showNotification('搜索', '搜索功能暂未实现'); } showQuestionBankManager() { this.showNotification('题库管理', `当前题库共有 ${this.questionBank.questions.length} 道题目`); } exportQuestionBank(format) { this.showNotification('导出', `导出${format.toUpperCase()}功能暂未实现`); } mergeQuestionBank(newQuestions) { this.showNotification('合并', '合并功能暂未实现'); } } // ==================== 考试助手模块 ==================== class ExamHelper { constructor(main) { this.main = main; this.questions = []; this.answers = {}; this.examData = { id: '', name: '', courseId: '', totalQuestions: 0, answeredQuestions: 0 }; } // 提取所有题目 extractQuestions() { this.questions = []; // 方法1: 从表格中提取 const questionTables = document.querySelectorAll('table[id^="tblItem_"]'); questionTables.forEach((table, index) => { if (table.getAttribute('IsLabel') !== '1') { const question = this.parseQuestionTable(table, index); if (question) { this.questions.push(question); } } }); this.examData.totalQuestions = this.questions.length; console.log(`提取了 ${this.questions.length} 道题目`); return this.questions; } // 解析题目表格 parseQuestionTable(table, index) { try { const questionId = table.id.replace('tblItem_', ''); const keyList = table.getAttribute('KeyList'); const keys = keyList ? keyList.split(',') : []; // 提取题目内容 let questionText = ''; const textElements = table.querySelectorAll('td'); textElements.forEach(td => { const text = td.textContent?.trim(); if (text && text.length > 10 && !questionText) { questionText = text; } }); // 提取选项 const options = []; keys.forEach(key => { const inputs = document.querySelectorAll(`input[name="${key}"]`); inputs.forEach((input, optIndex) => { const label = document.querySelector(`label[for="${input.id}"]`); const optionText = label ? label.textContent.trim() : `选项${String.fromCharCode(65 + optIndex)}`; options.push({ id: input.id, name: input.name, value: input.value, type: input.type, text: optionText, element: input }); }); }); // 判断题型 let questionType = 'unknown'; if (options.length > 0) { questionType = options[0].type === 'radio' ? 'single-choice' : 'multi-choice'; } const question = { id: questionId, index: index + 1, type: questionType, text: questionText, options: options, answer: null, keyList: keys, table: table }; return question; } catch (error) { console.error(`解析题目失败: ${error.message}`); return null; } } // 自动填写答案 async autoFillAnswers() { if (this.questions.length === 0) { this.extractQuestions(); } console.log('开始自动答题...'); // 从题库中查找答案 this.questions.forEach(question => { const answer = this.findAnswerFromBank(question); if (answer) { this.fillAnswer(question, answer); this.answers[question.id] = answer; } }); this.examData.answeredQuestions = Object.keys(this.answers).length; console.log(`自动答题完成: ${this.examData.answeredQuestions}/${this.examData.totalQuestions}`); // 显示进度通知 if (this.examData.answeredQuestions > 0) { this.main.showNotification('自动答题完成', `已填写 ${this.examData.answeredQuestions}/${this.examData.totalQuestions} 题`); } } // 从题库查找答案 findAnswerFromBank(question) { if (!this.main.questionBank.questions.length) return null; // 使用题目文本查找 const matchedQuestions = this.main.searchQuestion(question.text.substring(0, 50)); if (matchedQuestions.length > 0) { return matchedQuestions[0].answer; } return null; } // 填写答案 fillAnswer(question, answer) { if (!answer || !question.options.length) return; const answerValues = answer.split(''); question.options.forEach(option => { if (answerValues.includes(option.value)) { this.selectOption(option.element); } }); console.log(`第${question.index}题: 选择 ${answer}`); } // 选择选项 selectOption(element) { try { element.checked = true; // 触发事件 const changeEvent = new Event('change', { bubbles: true }); element.dispatchEvent(changeEvent); const clickEvent = new MouseEvent('click', { bubbles: true, cancelable: true, view: window }); element.dispatchEvent(clickEvent); return true; } catch (error) { console.error(`选择选项失败: ${error.message}`); return false; } } // 提交考试 submitExam() { console.log('准备提交考试...'); try { // 检查是否有提交函数 if (typeof doSubmit === 'function') { doSubmit(false); this.main.showNotification('考试提交', '正在提交考试...'); } else if (typeof submitDo === 'function') { submitDo(false); this.main.showNotification('考试提交', '正在提交考试...'); } else { // 查找提交按钮 const submitButtons = document.querySelectorAll('input[type="button"], button'); submitButtons.forEach(button => { if (button.value.includes('提交') || button.textContent.includes('提交')) { button.click(); this.main.showNotification('考试提交', '已点击提交按钮'); } }); } } catch (error) { console.error(`提交考试失败: ${error.message}`); } } // 获取统计信息 getStats() { return { total: this.examData.totalQuestions, answered: this.examData.answeredQuestions, progress: this.examData.totalQuestions ? Math.round(this.examData.answeredQuestions/this.examData.totalQuestions*100) : 0 }; } } // ==================== 答案提取器模块 ==================== class AnswerExtractor { constructor(main) { this.main = main; this.questionBank = { questions: [], extractedCount: 0 }; } // 提取所有答案 extractAllAnswers() { this.questionBank.questions = []; this.questionBank.extractedCount = 0; // 从页面提取题目和答案 this.extractFromPage(); console.log(`答案提取完成: ${this.questionBank.questions.length} 道题目`); if (this.questionBank.questions.length > 0) { this.main.showNotification('答案提取', `成功提取 ${this.questionBank.questions.length} 道题目`); } return this.questionBank.questions; } // 从页面提取 extractFromPage() { // 查找所有参考答案 const answerElements = document.querySelectorAll('div[style*="color:darkred"]'); answerElements.forEach((element, index) => { const question = this.extractQuestionFromElement(element, index); if (question) { this.questionBank.questions.push(question); this.questionBank.extractedCount++; } }); } // 从元素提取题目 extractQuestionFromElement(element, index) { try { const text = element.textContent || ''; // 提取答案 const answerMatch = text.match(/参考答案:([A-Z]+)/); if (!answerMatch) return null; const answer = answerMatch[1]; // 提取分值 const scoreMatch = text.match(/分值:(\d+)/); const score = scoreMatch ? parseInt(scoreMatch[1]) : 4; // 查找题目文本 let questionText = ''; let parent = element.parentElement; for (let i = 0; i < 5; i++) { if (!parent) break; // 查找前面的文本节点 const textNodes = []; const walker = document.createTreeWalker( parent, NodeFilter.SHOW_TEXT, null, false ); let node; while (node = walker.nextNode()) { if (node.textContent.trim().length > 20) { textNodes.push(node.textContent.trim()); } } if (textNodes.length > 0) { questionText = textNodes[textNodes.length - 1]; break; } parent = parent.previousElementSibling || parent.parentElement; } // 清理题目文本 questionText = this.cleanQuestionText(questionText); // 判断题型 const questionType = answer.length > 1 ? 'multi-choice' : 'single-choice'; return { index: index + 1, text: questionText, answer: answer, type: questionType, score: score, source: 'element-extraction' }; } catch (error) { console.error(`提取题目失败: ${error.message}`); return null; } } // 清理题目文本 cleanQuestionText(text) { if (!text) return ''; // 移除多余空格和换行 text = text.replace(/\s+/g, ' ').trim(); // 移除题号 text = text.replace(/^\d+[\.、]/, '').trim(); // 移除括号中的内容 text = text.replace(/\(.*?\)/g, '').trim(); return text; } // 获取统计信息 getStats() { return { total: this.questionBank.questions.length, extracted: this.questionBank.extractedCount }; } } // ==================== 主启动函数 ==================== function startLemonysoftHelper() { // 创建单例管理器 const singletonManager = new SingletonManager(); // 初始化助手 const initHelper = () => { try { const helper = singletonManager.getInstance(); if (helper) { // 检查助手是否已经初始化 if (!helper.isInitialized) { console.log('助手尚未初始化,等待初始化完成...'); setTimeout(initHelper, 1000); } } } catch (error) { console.error('初始化助手失败:', error); } }; // 页面加载完成后启动 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { setTimeout(initHelper, CONFIG.waitForLoadDelay); }); } else { setTimeout(initHelper, CONFIG.waitForLoadDelay); } // 监听页面可见性变化 document.addEventListener('visibilitychange', () => { if (!document.hidden) { // 页面重新可见时,检查助手状态 setTimeout(initHelper, 1000); } }); // 监听页面卸载 window.addEventListener('beforeunload', () => { const helper = singletonManager.instance; if (helper) { // 清理定时器 if (helper.panelCheckTimer) { clearInterval(helper.panelCheckTimer); } if (helper.observer) { helper.observer.disconnect(); } } }); } // 启动助手 startLemonysoftHelper(); })();