// ==UserScript==
// @name 柠檬文才学堂全功能助手
// @namespace http://tampermonkey.net/
// @version 3.0
// @description 考试自动答题 + 答案提取 + 题库管理
// @author Your Name
// @match *://*.wencaischool.net/*
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_notification
// @grant GM_xmlhttpRequest
// @grant GM_download
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant unsafeWindow
// @require https://code.jquery.com/jquery-3.6.0.min.js
// @run-at document-idle
// ==/UserScript==
(function() {
'use strict';
// 全局配置
const CONFIG = {
debug: true,
autoDetectPageType: true,
autoStart: true,
showControlPanel: true,
bypassSecurity: true,
saveAnswers: true,
questionBankKey: 'lemonysoft_question_bank',
answerHistoryKey: 'lemonysoft_answer_history'
};
// 页面类型检测
const PageType = {
UNKNOWN: 0,
EXAM: 1, // 考试界面
REVIEW: 2, // 试卷回顾
LIST: 3, // 考试列表
LOGIN: 4 // 登录页面
};
// 主控制器
class LemonysoftHelper {
constructor() {
this.pageType = PageType.UNKNOWN;
this.examHelper = null;
this.answerExtractor = null;
this.questionBank = null;
this.controlPanel = null;
this.isInitialized = false;
this.init();
}
init() {
console.log('🍋 柠檬文才学堂助手启动');
// 检测页面类型
this.detectPageType();
// 加载题库
this.loadQuestionBank();
// 根据页面类型初始化相应功能
this.initializeForPageType();
// 添加控制面板
if (CONFIG.showControlPanel) {
this.addControlPanel();
}
// 添加全局快捷键
this.addKeyboardShortcuts();
this.isInitialized = true;
this.log(`页面类型: ${this.getPageTypeName()}`, 'success');
}
// 检测页面类型
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') ||
html.includes('正在答题') ||
html.includes('在线考试') ||
html.includes('tblItem_') ||
html.includes('lemonysoft_item_')
) && !html.includes('参考答案:');
// 试卷回顾特征
const isReviewPage = (
url.includes('review') ||
url.includes('查看考卷') ||
html.includes('参考答案:') ||
html.includes('当前得分:') ||
html.includes('得分: {
this.examHelper.extractQuestions();
this.examHelper.autoFillAnswers();
}, 2000);
}
}
// 初始化答案提取器
initAnswerExtractor() {
if (this.answerExtractor) return;
this.log('初始化答案提取器...');
this.answerExtractor = new AnswerExtractor(this);
// 自动提取答案
if (CONFIG.autoStart) {
setTimeout(() => {
this.answerExtractor.extractAllAnswers();
}, 1500);
}
}
// 初始化考试列表助手
initExamListHelper() {
this.log('检测到考试列表页面');
// 可以在这里添加自动跳转、批量处理等功能
}
// 初始化登录助手
initLoginHelper() {
this.log('检测到登录页面');
// 可以在这里添加自动登录、密码保存等功能
}
// 恢复键盘功能(绕过安全限制)
restoreKeyboard() {
this.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样式解除选择限制
GM_addStyle(`
* {
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;
}
`);
}
// 加载题库
loadQuestionBank() {
try {
const saved = GM_getValue(CONFIG.questionBankKey);
if (saved) {
this.questionBank = JSON.parse(saved);
this.log(`题库已加载: ${this.questionBank.questions?.length || 0} 道题目`);
return this.questionBank;
}
} catch (error) {
this.log('加载题库失败', '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));
this.log(`题库已保存: ${this.questionBank.questions.length} 道题目`, 'success');
return true;
} catch (error) {
this.log(`保存题库失败: ${error.message}`, 'error');
return false;
}
}
// 合并题库
mergeQuestionBank(newQuestions) {
if (!newQuestions || !Array.isArray(newQuestions)) return;
let addedCount = 0;
let updatedCount = 0;
newQuestions.forEach(newQuestion => {
// 查找是否已存在相同题目
const existingIndex = this.questionBank.questions.findIndex(q =>
q.text === newQuestion.text ||
q.id === newQuestion.id
);
if (existingIndex === -1) {
// 添加新题目
this.questionBank.questions.push(newQuestion);
addedCount++;
} else {
// 更新现有题目
this.questionBank.questions[existingIndex] = {
...this.questionBank.questions[existingIndex],
...newQuestion,
updated: new Date().toISOString()
};
updatedCount++;
}
});
this.questionBank.totalQuestions = this.questionBank.questions.length;
if (addedCount > 0 || updatedCount > 0) {
this.saveQuestionBank();
this.log(`题库合并完成: 新增 ${addedCount} 题, 更新 ${updatedCount} 题`, 'success');
}
return { added: addedCount, updated: updatedCount };
}
// 搜索题目
searchQuestion(keyword) {
if (!keyword || !this.questionBank.questions.length) return [];
keyword = keyword.toLowerCase();
return this.questionBank.questions.filter(question =>
question.text.toLowerCase().includes(keyword) ||
(question.options && question.options.some(opt =>
opt.text.toLowerCase().includes(keyword)
))
);
}
// 获取题目答案
getQuestionAnswer(questionText) {
if (!questionText || !this.questionBank.questions.length) return null;
const question = this.questionBank.questions.find(q =>
q.text.includes(questionText) ||
questionText.includes(q.text)
);
return question ? question.answer : null;
}
// 添加控制面板
addControlPanel() {
if (this.controlPanel) return;
const panel = document.createElement('div');
panel.id = 'lemonysoft-helper-panel';
panel.innerHTML = `
`;
document.body.appendChild(panel);
this.controlPanel = panel;
// 添加事件监听
this.setupPanelEvents();
// 根据页面类型更新按钮
this.updatePanelButtons();
// 初始化面板拖动
this.initPanelDrag();
this.log('控制面板已添加');
}
// 设置面板事件
setupPanelEvents() {
const panel = this.controlPanel;
// 关闭按钮
panel.querySelector('#close-panel').addEventListener('click', () => {
panel.style.display = 'none';
});
// 搜索功能
const searchInput = panel.querySelector('#search-input');
const searchResults = panel.querySelector('#search-results');
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 = '未找到相关题目
';
}
});
// 设置按钮
panel.querySelector('#btn-settings').addEventListener('click', () => {
this.showSettingsDialog();
});
// 帮助按钮
panel.querySelector('#btn-help').addEventListener('click', () => {
this.showHelpDialog();
});
// 双击标题栏最小化
panel.querySelector('#panel-header').addEventListener('dblclick', () => {
const body = panel.querySelector('.panel-body');
body.style.display = body.style.display === 'none' ? 'block' : 'none';
});
}
// 更新面板按钮(根据页面类型)
updatePanelButtons() {
const buttonContainer = this.controlPanel.querySelector('#function-buttons');
let buttons = '';
switch (this.pageType) {
case PageType.EXAM:
buttons = `
`;
break;
case PageType.REVIEW:
buttons = `
`;
break;
default:
buttons = `
`;
}
buttonContainer.innerHTML = buttons;
// 重新绑定事件
this.bindFunctionButtons();
}
// 绑定功能按钮事件
bindFunctionButtons() {
const panel = this.controlPanel;
// 考试界面按钮
if (this.pageType === PageType.EXAM) {
if (panel.querySelector('#btn-extract')) {
panel.querySelector('#btn-extract').addEventListener('click', () => {
if (this.examHelper) {
this.examHelper.extractQuestions();
}
});
}
if (panel.querySelector('#btn-auto-answer')) {
panel.querySelector('#btn-auto-answer').addEventListener('click', () => {
if (this.examHelper) {
this.examHelper.autoFillAnswers();
}
});
}
if (panel.querySelector('#btn-bypass')) {
panel.querySelector('#btn-bypass').addEventListener('click', () => {
this.restoreKeyboard();
this.showNotification('安全限制已解除', '键盘和复制功能已恢复');
});
}
if (panel.querySelector('#btn-search-answer')) {
panel.querySelector('#btn-search-answer').addEventListener('click', () => {
this.showSearchDialog();
});
}
if (panel.querySelector('#btn-submit')) {
panel.querySelector('#btn-submit').addEventListener('click', () => {
if (this.examHelper) {
this.examHelper.submitExam();
}
});
}
}
// 回顾界面按钮
if (this.pageType === PageType.REVIEW) {
if (panel.querySelector('#btn-extract-answers')) {
panel.querySelector('#btn-extract-answers').addEventListener('click', () => {
if (this.answerExtractor) {
this.answerExtractor.extractAllAnswers();
}
});
}
if (panel.querySelector('#btn-save-bank')) {
panel.querySelector('#btn-save-bank').addEventListener('click', () => {
this.saveQuestionBank();
});
}
if (panel.querySelector('#btn-export-json')) {
panel.querySelector('#btn-export-json').addEventListener('click', () => {
this.exportQuestionBank('json');
});
}
if (panel.querySelector('#btn-export-csv')) {
panel.querySelector('#btn-export-csv').addEventListener('click', () => {
this.exportQuestionBank('csv');
});
}
if (panel.querySelector('#btn-merge-bank')) {
panel.querySelector('#btn-merge-bank').addEventListener('click', () => {
this.mergeQuestionBank(this.answerExtractor?.questionBank?.questions || []);
});
}
}
// 通用按钮
if (panel.querySelector('#btn-general-help')) {
panel.querySelector('#btn-general-help').addEventListener('click', () => {
this.showHelpDialog();
});
}
if (panel.querySelector('#btn-manage-bank')) {
panel.querySelector('#btn-manage-bank').addEventListener('click', () => {
this.showQuestionBankManager();
});
}
}
// 初始化面板拖动
initPanelDrag() {
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';
}
}
// 更新状态显示
updateStatus() {
const statusElement = this.controlPanel?.querySelector('#status-display');
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}%
`;
// 更新进度条
const progressBar = this.controlPanel.querySelector('#progress-fill');
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;
}
// 显示设置对话框
showSettingsDialog() {
// 创建设置对话框
const dialog = document.createElement('div');
dialog.style.cssText = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
border: 2px solid #3498db;
border-radius: 10px;
padding: 20px;
z-index: 100000;
min-width: 300px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
`;
dialog.innerHTML = `
⚙️ 助手设置
`;
document.body.appendChild(dialog);
// 添加事件监听
dialog.querySelector('#settings-save').addEventListener('click', () => {
CONFIG.debug = dialog.querySelector('#setting-debug').checked;
CONFIG.autoStart = dialog.querySelector('#setting-auto-start').checked;
CONFIG.bypassSecurity = dialog.querySelector('#setting-bypass').checked;
CONFIG.saveAnswers = dialog.querySelector('#setting-save-answers').checked;
this.log('设置已保存', 'success');
dialog.remove();
});
dialog.querySelector('#settings-cancel').addEventListener('click', () => {
dialog.remove();
});
// 点击背景关闭
dialog.addEventListener('click', (e) => {
if (e.target === dialog) {
dialog.remove();
}
});
}
// 显示帮助对话框
showHelpDialog() {
const helpText = `
🍋 柠檬文才学堂助手使用说明
📝 主要功能:
- 考试界面:自动答题、题目提取、绕过安全限制
- 回顾界面:答案提取、题库构建、数据导出
- 题库管理:题目搜索、答案匹配、数据合并
🎯 使用方法:
- 在考试界面点击"自动答题"开始自动填写答案
- 在回顾界面点击"提取答案"保存正确答案到题库
- 使用搜索框查找题库中的题目和答案
- 导出题库数据用于复习或备份
⚠️ 注意事项:
- 请遵守学校规定,仅用于学习目的
- 定期备份题库数据
- 答案准确性需要自行验证
📱 快捷键:
- Ctrl+Shift+L: 显示/隐藏控制面板
- Ctrl+Shift+A: 自动答题
- Ctrl+Shift+S: 搜索题目
`;
const dialog = document.createElement('div');
dialog.style.cssText = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
border: 2px solid #3498db;
border-radius: 10px;
padding: 20px;
z-index: 100000;
max-width: 500px;
max-height: 80vh;
overflow-y: auto;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
`;
dialog.innerHTML = helpText + `
`;
document.body.appendChild(dialog);
dialog.querySelector('#help-close').addEventListener('click', () => {
dialog.remove();
});
// 点击背景关闭
dialog.addEventListener('click', (e) => {
if (e.target === dialog) {
dialog.remove();
}
});
}
// 显示搜索对话框
showSearchDialog() {
const dialog = document.createElement('div');
dialog.style.cssText = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
border: 2px solid #3498db;
border-radius: 10px;
padding: 20px;
z-index: 100000;
width: 400px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
`;
dialog.innerHTML = `
🔍 题库搜索
`;
document.body.appendChild(dialog);
const searchInput = dialog.querySelector('#dialog-search');
const resultsDiv = dialog.querySelector('#dialog-results');
searchInput.focus();
searchInput.addEventListener('input', (e) => {
const keyword = e.target.value.trim();
if (keyword.length < 2) {
resultsDiv.innerHTML = '请输入至少2个字符
';
return;
}
const results = this.searchQuestion(keyword);
if (results.length > 0) {
let html = '';
results.slice(0, 20).forEach(question => {
html += `
${question.text.substring(0, 80)}...
答案: ${question.answer}
${question.score ? `
分值: ${question.score}
` : ''}
`;
});
resultsDiv.innerHTML = html;
} else {
resultsDiv.innerHTML = '未找到相关题目
';
}
});
dialog.querySelector('#search-close').addEventListener('click', () => {
dialog.remove();
});
// 点击背景关闭
dialog.addEventListener('click', (e) => {
if (e.target === dialog) {
dialog.remove();
}
});
}
// 显示题库管理器
showQuestionBankManager() {
// 这里可以添加更复杂的题库管理功能
this.showNotification('题库管理', `当前题库共有 ${this.questionBank.questions.length} 道题目`);
}
// 导出题库
exportQuestionBank(format) {
let content = '';
let filename = '';
switch (format) {
case 'json':
content = JSON.stringify(this.questionBank, null, 2);
filename = `题库_${this.questionBank.examName || '未命名'}_${Date.now()}.json`;
break;
case 'csv':
content = this.convertToCSV();
filename = `题库_${this.questionBank.examName || '未命名'}_${Date.now()}.csv`;
break;
}
// 下载文件
this.downloadFile(content, filename, format === 'json' ? 'application/json' : 'text/csv');
this.log(`题库已导出为 ${format.toUpperCase()} 格式`, 'success');
}
// 转换为CSV格式
convertToCSV() {
let csv = '序号,题型,题目,答案,分值\n';
this.questionBank.questions.forEach(question => {
const row = [
question.index || '',
question.type === 'single-choice' ? '单选题' : '多选题',
`"${(question.text || '').replace(/"/g, '""')}"`,
question.answer || '',
question.score || ''
].join(',');
csv += row + '\n';
});
return csv;
}
// 下载文件
downloadFile(content, filename, mimeType = 'text/plain') {
const blob = new Blob([content], { type: `${mimeType};charset=utf-8` });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}
// 添加全局快捷键
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';
}
}
// 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();
}
});
}
// 显示通知
showNotification(title, message, type = 'info') {
if (typeof GM_notification === 'function') {
GM_notification({
title: title,
text: message,
timeout: 3000
});
} else {
// 使用自定义通知
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: 100000;
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);
}
}
// 日志函数
log(message, level = 'info', data = null) {
if (!CONFIG.debug) return;
const timestamp = new Date().toLocaleTimeString();
const prefix = `[LemonyHelper ${timestamp}]`;
switch (level) {
case 'error':
console.error(prefix, message, data || '');
break;
case 'warn':
console.warn(prefix, message, data || '');
break;
case 'success':
console.log(`%c${prefix} ${message}`, 'color: #27ae60', data || '');
break;
default:
console.log(prefix, message, data || '');
}
}
}
// ==================== 考试助手模块 ====================
class ExamHelper {
constructor(main) {
this.main = main;
this.questions = [];
this.answers = {};
this.examData = {
id: '',
name: '',
courseId: '',
totalQuestions: 0,
answeredQuestions: 0
};
this.init();
}
init() {
this.log('考试助手初始化');
// 提取考试信息
this.extractExamInfo();
// 监听页面变化
this.setupObservers();
}
// 提取考试信息
extractExamInfo() {
// 从URL提取考试ID
const urlParams = new URLSearchParams(window.location.search);
this.examData.id = urlParams.get('exam_id') || '';
// 从页面提取考试名称
const titleElements = document.querySelectorAll('div.fnt_lrg_b, h1, h2');
titleElements.forEach(el => {
if (el.textContent && el.textContent.trim()) {
this.examData.name = el.textContent.trim();
}
});
this.log(`考试信息: ${this.examData.name} (ID: ${this.examData.id})`);
}
// 提取所有题目
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);
}
}
});
// 方法2: 从题目ID数组中提取(如果存在)
if (typeof aItemId !== 'undefined' && Array.isArray(aItemId)) {
aItemId.forEach((itemId, index) => {
if (itemId) {
const table = document.getElementById(`tblItem_${itemId}`);
if (table && table.getAttribute('IsLabel') !== '1') {
const question = this.parseQuestionTable(table, index);
if (question && !this.questions.find(q => q.id === itemId)) {
this.questions.push(question);
}
}
}
});
}
this.examData.totalQuestions = this.questions.length;
this.log(`提取了 ${this.questions.length} 道题目`);
// 更新主控状态
this.main.updateStatus();
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) {
this.log(`解析题目失败: ${error.message}`, 'error');
return null;
}
}
// 自动填写答案
async autoFillAnswers() {
if (this.questions.length === 0) {
this.extractQuestions();
}
this.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;
this.main.updateStatus();
this.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 this.smartGuessAnswer(question);
}
// 智能推测答案(简单规则)
smartGuessAnswer(question) {
// 这里可以添加一些简单的答题规则
// 例如:如果题目包含"错误"、"不正确"等词,选择看起来最不可能的选项
const text = question.text.toLowerCase();
if (question.type === 'single-choice') {
// 单选题:默认选择C
return 'C';
} else if (question.type === 'multi-choice') {
// 多选题:默认选择AB
return 'AB';
}
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);
}
});
this.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) {
this.log(`选择选项失败: ${error.message}`, 'error');
return false;
}
}
// 提交考试
submitExam() {
this.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) {
this.log(`提交考试失败: ${error.message}`, 'error');
}
}
// 获取统计信息
getStats() {
return {
total: this.examData.totalQuestions,
answered: this.examData.answeredQuestions,
progress: this.examData.totalQuestions ?
Math.round(this.examData.answeredQuestions/this.examData.totalQuestions*100) : 0
};
}
// 设置页面变化监听
setupObservers() {
const observer = new MutationObserver(() => {
// 检查是否有新题目加载
const currentCount = document.querySelectorAll('table[id^="tblItem_"]').length;
if (currentCount > this.questions.length) {
this.log('检测到新题目,重新提取...');
setTimeout(() => this.extractQuestions(), 1000);
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
log(message, level = 'info') {
this.main.log(`[ExamHelper] ${message}`, level);
}
}
// ==================== 答案提取器模块 ====================
class AnswerExtractor {
constructor(main) {
this.main = main;
this.questionBank = {
questions: [],
extractedCount: 0
};
this.init();
}
init() {
this.log('答案提取器初始化');
}
// 提取所有答案
extractAllAnswers() {
this.questionBank.questions = [];
this.questionBank.extractedCount = 0;
// 从页面提取题目和答案
this.extractFromPage();
// 更新统计信息
this.main.updateStatus();
this.log(`答案提取完成: ${this.questionBank.questions.length} 道题目`);
if (this.questionBank.questions.length > 0) {
this.main.showNotification('答案提取',
`成功提取 ${this.questionBank.questions.length} 道题目`);
}
return this.questionBank.questions;
}
// 从页面提取
extractFromPage() {
// 方法1: 查找所有参考答案
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++;
}
});
// 方法2: 从题目行提取
if (this.questionBank.questions.length === 0) {
const questionRows = document.querySelectorAll('tr[id^="trScore_"]');
questionRows.forEach((row, index) => {
const question = this.extractQuestionFromRow(row, 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 walker = document.createTreeWalker(
parent,
NodeFilter.SHOW_TEXT,
null,
false
);
let node;
let texts = [];
while (node = walker.nextNode()) {
if (node.textContent.trim().length > 20) {
texts.push(node.textContent.trim());
}
}
if (texts.length > 0) {
questionText = texts[texts.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) {
this.log(`提取题目失败: ${error.message}`, 'error');
return null;
}
}
// 从行提取题目
extractQuestionFromRow(row, index) {
try {
const cells = row.querySelectorAll('td');
if (cells.length < 2) return null;
// 提取题目内容
let questionText = '';
const contentCell = cells[1];
// 查找题目文本
const textElements = contentCell.querySelectorAll('table td');
textElements.forEach(td => {
const text = td.textContent?.trim();
if (text && text.length > 20 && !questionText) {
questionText = text;
}
});
// 提取答案
let answer = '';
const answerDiv = contentCell.querySelector('div[style*="color:darkred"]');
if (answerDiv) {
const answerMatch = answerDiv.textContent.match(/参考答案:([A-Z]+)/);
if (answerMatch) {
answer = answerMatch[1];
}
}
if (!answer) return null;
// 提取分值
let score = 4;
if (answerDiv) {
const scoreMatch = answerDiv.textContent.match(/分值:(\d+)/);
if (scoreMatch) {
score = parseInt(scoreMatch[1]);
}
}
// 清理题目文本
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: 'row-extraction'
};
} catch (error) {
this.log(`提取题目行失败: ${error.message}`, 'error');
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
};
}
log(message, level = 'info') {
this.main.log(`[AnswerExtractor] ${message}`, level);
}
}
// ==================== 主启动函数 ====================
function startLemonysoftHelper() {
// 等待页面加载完成
const checkReady = () => {
if (document.readyState === 'complete') {
// 延迟启动,确保页面完全加载
setTimeout(() => {
// 检查是否已经存在实例
if (!window.lemonysoftHelper) {
window.lemonysoftHelper = new LemonysoftHelper();
// 定期更新状态
setInterval(() => {
if (window.lemonysoftHelper && window.lemonysoftHelper.controlPanel) {
window.lemonysoftHelper.updateStatus();
}
}, 2000);
}
}, 1500);
} else {
setTimeout(checkReady, 500);
}
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', checkReady);
} else {
checkReady();
}
}
// 启动助手
startLemonysoftHelper();
})();