// ==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 = `
`;
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();
})();