// ==UserScript== // @name 创新创新-贤程教育 // @namespace https://www.example.com/ // @version 10.111 // @description 修复多选题逻辑,优化题目类型判断 // @author xixi // @match *://*.gdcxxy.net/* // @grant GM_setValue // @grant GM_getValue // ==/UserScript== (function() { 'use strict'; // 题库系统 let questionBank = {}; let currentCourse = 'CB030116'; // 固定课程编码 let logs = []; /** * 初始化题库 */ function initQuestionBank() { const savedBank = GM_getValue('localQuestionBank'); if (savedBank) { questionBank = savedBank; addLog(`已加载题库,总计 ${countQuestions()} 题`, 'success'); updateStats(); } else { addLog('未找到题库,请导入JSON文件', 'warning'); } } /** * 统计题目数量 */ function countQuestions() { let count = 0; for (const course in questionBank) { for (const chapter in questionBank[course].chapters) { count += questionBank[course].chapters[chapter].length; } } return count; } /** * 更新统计信息 */ function updateStats() { const totalQuestions = countQuestions(); let coursesCount = 0; let singleChoice = 0; let multiChoice = 0; let judgment = 0; let shortAnswer = 0; for (const course in questionBank) { coursesCount++; for (const chapter in questionBank[course].chapters) { questionBank[course].chapters[chapter].forEach(q => { if (q.type === '单选') singleChoice++; if (q.type === '多选') multiChoice++; if (q.type === '判断') judgment++; if (q.type === '简答') shortAnswer++; }); } } const statsDisplay = document.getElementById('statsDisplay'); if (statsDisplay) { statsDisplay.innerHTML = `
📊 题库统计
📚 总题目: ${totalQuestions} 题
🔘 单选题: ${singleChoice} 题
☑️ 多选题: ${multiChoice} 题
✅ 判断题: ${judgment} 题
📝 简答题: ${shortAnswer} 题
🎯 课程: ${coursesCount} 门
上次更新: ${new Date().toLocaleString()}
`; } } /** * 加载JSON题库文件(合并而不是覆盖) */ function loadQuestionBankFromFile(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = function(e) { try { const newBank = JSON.parse(e.target.result); // 验证数据结构 if (isValidQuestionBank(newBank)) { // 合并题库而不是覆盖 mergeQuestionBanks(newBank); GM_setValue('localQuestionBank', questionBank); updateStats(); const addedCount = countQuestionsInBank(newBank); addLog(`题库合并成功: 新增 ${addedCount} 题,总计 ${countQuestions()} 题`, 'success'); resolve(questionBank); } else { addLog('题库文件格式不正确', 'error'); reject(new Error('无效的题库格式')); } } catch (error) { addLog('解析题库文件失败: ' + error.message, 'error'); reject(error); } }; reader.onerror = function() { addLog('读取文件失败', 'error'); reject(new Error('文件读取失败')); }; reader.readAsText(file); }); } /** * 计算题库中的题目数量 */ function countQuestionsInBank(bank) { let count = 0; for (const course in bank) { for (const chapter in bank[course].chapters) { count += bank[course].chapters[chapter].length; } } return count; } /** * 合并两个题库 */ function mergeQuestionBanks(newBank) { const startCount = countQuestions(); for (const course in newBank) { if (!questionBank[course]) { // 新课程,直接添加 questionBank[course] = newBank[course]; continue; } // 现有课程,合并章节 for (const chapter in newBank[course].chapters) { if (!questionBank[course].chapters[chapter]) { // 新章节,直接添加 questionBank[course].chapters[chapter] = newBank[course].chapters[chapter]; continue; } // 现有章节,合并题目(去重) const existingQuestions = questionBank[course].chapters[chapter]; const newQuestions = newBank[course].chapters[chapter]; // 创建现有题目的哈希表用于快速查找 const existingQuestionMap = new Map(); existingQuestions.forEach(q => { const key = generateQuestionKey(q); existingQuestionMap.set(key, q); }); // 添加新题目(如果不存在) newQuestions.forEach(newQ => { const key = generateQuestionKey(newQ); if (!existingQuestionMap.has(key)) { existingQuestions.push(newQ); existingQuestionMap.set(key, newQ); } }); } } const endCount = countQuestions(); return endCount - startCount; } /** * 生成题目唯一标识键 */ function generateQuestionKey(question) { // 使用清理后的题目文本作为键 const cleanText = cleanQuestionText(question.question); return `${question.type}_${cleanText.substring(0, 100)}`; } /** * 验证题库数据结构 */ function isValidQuestionBank(data) { if (typeof data !== 'object' || data === null) return false; for (const course in data) { const courseData = data[course]; if (!courseData.course_name || !courseData.chapters) return false; if (typeof courseData.chapters !== 'object') return false; for (const chapter in courseData.chapters) { if (!Array.isArray(courseData.chapters[chapter])) return false; for (const question of courseData.chapters[chapter]) { if (!question.question || !question.type || question.answer === undefined) { console.warn('无效的题目:', question); return false; } } } } return true; } /** * 导出题库为JSON文件 */ function exportQuestionBank() { if (Object.keys(questionBank).length === 0) { addLog('题库为空,无法导出', 'warning'); return; } try { const dataStr = JSON.stringify(questionBank, null, 2); const dataBlob = new Blob([dataStr], {type: 'application/json'}); const downloadLink = document.createElement('a'); downloadLink.download = `题库备份_${new Date().toISOString().split('T')[0]}.json`; downloadLink.href = URL.createObjectURL(dataBlob); downloadLink.click(); addLog(`题库导出成功,共 ${countQuestions()} 题`, 'success'); } catch (error) { addLog(`导出失败: ${error.message}`, 'error'); } } /** * 清理题库(删除重复题目) */ function cleanQuestionBank() { const startCount = countQuestions(); for (const course in questionBank) { for (const chapter in questionBank[course].chapters) { const questions = questionBank[course].chapters[chapter]; const uniqueQuestions = []; const seenQuestions = new Set(); questions.forEach(q => { const key = generateQuestionKey(q); if (!seenQuestions.has(key)) { seenQuestions.add(key); uniqueQuestions.push(q); } }); questionBank[course].chapters[chapter] = uniqueQuestions; } } GM_setValue('localQuestionBank', questionBank); const endCount = countQuestions(); const removedCount = startCount - endCount; if (removedCount > 0) { addLog(`已清理 ${removedCount} 个重复题目,剩余 ${endCount} 题`, 'success'); } else { addLog('未发现重复题目', 'info'); } updateStats(); } /** * 智能搜索答案 */ function findAnswer(questionText, questionType) { // 清理题目文本 const cleanQuestion = cleanQuestionText(questionText); // 优先在当前课程中搜索相同类型的题目 if (questionBank[currentCourse]) { const answer = searchInCourse(cleanQuestion, currentCourse, questionType); if (answer) return answer; } // 如果没有,在所有课程中搜索相同类型的题目 for (const course in questionBank) { if (course === currentCourse) continue; const answer = searchInCourse(cleanQuestion, course, questionType); if (answer) return answer; } // 如果还是没有,放宽类型限制,搜索所有类型 for (const course in questionBank) { const answer = searchInCourse(cleanQuestion, course, null); // null表示不限制类型 if (answer) return answer; } return null; } /** * 在指定课程中搜索 */ function searchInCourse(questionText, course, targetType) { for (const chapter in questionBank[course].chapters) { for (const questionData of questionBank[course].chapters[chapter]) { const cleanBankQuestion = cleanQuestionText(questionData.question); // 如果指定了类型,先检查类型是否匹配 if (targetType && questionData.type !== targetType) { continue; } // 使用多种匹配策略 if (isQuestionMatch(questionText, cleanBankQuestion)) { return { ...questionData, source: `${questionBank[course].course_name} - ${chapter}` }; } } } return null; } /** * 判断题目是否匹配 */ function isQuestionMatch(q1, q2) { if (!q1 || !q2) return false; // 完全相同 if (q1 === q2) return true; // 相互包含 if (q1.includes(q2) || q2.includes(q1)) return true; // 长度大于5时,使用关键词匹配 if (q1.length > 5 && q2.length > 5) { const keywords1 = extractKeywords(q1); const keywords2 = extractKeywords(q2); if (keywords1.length > 0 && keywords2.length > 0) { const commonKeywords = keywords1.filter(k => keywords2.includes(k)); const similarity = commonKeywords.length / Math.max(keywords1.length, keywords2.length); return similarity > 0.4; } } return false; } /** * 清理题目文本 */ function cleanQuestionText(text) { if (!text) return ''; // 1. 移除HTML标签 let cleaned = text.replace(/<[^>]*>/g, ''); // 2. 移除题目类型标记(但保留类型信息供判断) // 先保存类型信息,再移除标记 const typeMatch = cleaned.match(/\[(.*?)\]/); if (typeMatch) { cleaned = cleaned.replace(/\[.*?\]/g, ''); } // 3. 移除题号前缀 cleaned = cleaned.replace(/^\d+[.\.]\s*/, ''); // 4. 移除特殊字符和多余空格 cleaned = cleaned.replace(/[,。;:()【】《》]/g, '') .replace(/\s+/g, ' ') .trim(); return cleaned.toLowerCase(); } /** * 提取关键词 */ function extractKeywords(text) { // 移除常见停用词 const stopWords = ['的', '了', '在', '是', '和', '与', '或', '及', '等', '对', '就', '都', '而', '且', '但', '也', '又', '再', '还', '已经']; return text.split(/[\s,,。.;;?!?!?]/) .filter(word => word.length > 1 && !stopWords.includes(word)) .map(word => word.toLowerCase()); } /** * 获取题目类型 */ function getQuestionType(questionText) { const text = questionText.toLowerCase(); if (text.includes('多选') || text.includes('多选题')) { return '多选'; } else if (text.includes('单选') || text.includes('单选题')) { return '单选'; } else if (text.includes('判断') || text.includes('判断题')) { return '判断'; } else if (text.includes('简答') || text.includes('简答题')) { return '简答'; } return '未知'; } /** * 处理单选题 */ async function handleSingleChoice(questionElement) { const questionText = getQuestionText(questionElement); const cleanQuestion = cleanQuestionText(questionText); addLog(`处理单选题: ${cleanQuestion.substring(0, 50)}...`, 'info'); const questionData = findAnswer(questionText, '单选'); if (!questionData) { addLog(`未找到答案`, 'warning'); return; } // 查找所有选项 const options = findSingleChoiceOptions(questionElement); if (options.length === 0) { addLog('未找到单选题选项', 'warning'); return; } addLog(`找到 ${options.length} 个单选题选项`, 'info'); // 匹配答案 await selectSingleChoiceOption(questionData, options); } /** * 查找单选题选项 */ function findSingleChoiceOptions(questionElement) { const options = []; // 找到题目容器 const questionContainer = questionElement.closest('.form-group.row'); if (!questionContainer) return options; // 查找后续的所有选项行 let currentRow = questionContainer.nextElementSibling; while (currentRow) { // 如果遇到下一个题目,停止查找 if (currentRow.querySelector('.form-material-success:has(b)')) { break; } // 查找单选按钮 const radios = currentRow.querySelectorAll('input[type="radio"]'); if (radios.length > 0) { radios.forEach(radio => { const label = radio.closest('label'); if (label) { const optionText = getOptionText(label); options.push({ radio: radio, value: radio.value, text: optionText }); } }); } currentRow = currentRow.nextElementSibling; } return options; } /** * 选择单选题选项 */ async function selectSingleChoiceOption(questionData, options) { const answer = questionData.answer.trim().toUpperCase(); // 策略1:根据答案字母匹配(A, B, C, D) let targetOption = null; // 查找以答案字母开头的选项 targetOption = options.find(opt => { const optText = opt.text.trim().toUpperCase(); return optText.startsWith(answer + '.') || optText.startsWith(answer + '.') || optText.startsWith(answer + ' '); }); // 策略2:根据选项值匹配 if (!targetOption) { const valueMap = { 'A': '0', 'B': '1', 'C': '2', 'D': '3' }; const targetValue = valueMap[answer]; if (targetValue) { targetOption = options.find(opt => opt.value === targetValue); } } // 策略3:如果题库有选项内容,尝试匹配 if (!targetOption && questionData.options && questionData.options.length > 0) { const answerIndex = answer.charCodeAt(0) - 65; if (answerIndex >= 0 && answerIndex < questionData.options.length) { const correctOptionText = questionData.options[answerIndex] || ''; if (correctOptionText) { const cleanCorrect = cleanQuestionText(correctOptionText); targetOption = options.find(opt => { const cleanOption = cleanQuestionText(opt.text); return cleanOption.includes(cleanCorrect) || cleanCorrect.includes(cleanOption); }); } } } if (targetOption) { if (!targetOption.radio.checked) { targetOption.radio.click(); targetOption.radio.dispatchEvent(new Event('change', { bubbles: true })); addLog(`单选题已选择: ${answer} (${targetOption.text.substring(0, 30)})`, 'success'); } else { addLog(`单选题选项 ${answer} 已选中`, 'info'); } } else { addLog(`无法匹配单选题选项,答案: ${answer}`, 'warning'); console.log('可用选项:', options.map(opt => ({text: opt.text, value: opt.value}))); } } /** * 处理多选题 */ async function handleMultiChoice(questionElement) { const questionText = getQuestionText(questionElement); const cleanQuestion = cleanQuestionText(questionText); addLog(`处理多选题: ${cleanQuestion.substring(0, 50)}...`, 'info'); const questionData = findAnswer(questionText, '多选'); if (!questionData) { addLog(`未找到多选题答案`, 'warning'); return; } // 查找所有选项 const options = findMultiChoiceOptions(questionElement); if (options.length === 0) { addLog('未找到多选题选项', 'warning'); return; } addLog(`找到 ${options.length} 个多选题选项`, 'info'); // 匹配答案 await selectMultiChoiceOptions(questionData, options); } /** * 查找多选题选项 */ function findMultiChoiceOptions(questionElement) { const options = []; // 找到题目容器 const questionContainer = questionElement.closest('.form-group.row'); if (!questionContainer) return options; // 查找后续的所有选项行 let currentRow = questionContainer.nextElementSibling; while (currentRow) { // 如果遇到下一个题目,停止查找 if (currentRow.querySelector('.form-material-success:has(b)')) { break; } // 查找复选框 const checkboxes = currentRow.querySelectorAll('input[type="checkbox"]'); if (checkboxes.length > 0) { checkboxes.forEach(checkbox => { const label = checkbox.closest('label'); if (label) { const optionText = getOptionText(label); options.push({ checkbox: checkbox, value: checkbox.value, text: optionText }); } }); } currentRow = currentRow.nextElementSibling; } return options; } /** * 选择多选题选项 */ async function selectMultiChoiceOptions(questionData, options) { const answer = questionData.answer.trim().toUpperCase(); // 多选题答案可能是多个字母,如"ABCD"、"AB"等 const selectedLetters = answer.split('').filter(letter => /[A-D]/.test(letter)); addLog(`多选题答案为: ${selectedLetters.join(',')}`, 'info'); if (selectedLetters.length === 0) { addLog('多选题答案格式错误', 'error'); return; } // 先取消所有已选中的选项 options.forEach(opt => { if (opt.checkbox.checked) { opt.checkbox.click(); // 先点击取消 } }); // 选中正确的选项 let selectedCount = 0; for (const letter of selectedLetters) { // 查找匹配的选项 const targetOption = options.find(opt => { const optText = opt.text.trim().toUpperCase(); return optText.startsWith(letter + '.') || optText.startsWith(letter + '.') || optText.startsWith(letter + ' '); }); if (targetOption) { if (!targetOption.checkbox.checked) { targetOption.checkbox.click(); targetOption.checkbox.dispatchEvent(new Event('change', { bubbles: true })); selectedCount++; addLog(`多选题已选择: ${letter}`, 'success'); } } else { addLog(`无法找到多选题选项: ${letter}`, 'warning'); } } if (selectedCount > 0) { addLog(`多选题已选择 ${selectedCount} 个选项`, 'success'); } } /** * 处理判断题 */ async function handleJudgment(questionElement) { const questionText = getQuestionText(questionElement); const cleanQuestion = cleanQuestionText(questionText); addLog(`处理判断题: ${cleanQuestion.substring(0, 50)}...`, 'info'); const questionData = findAnswer(questionText, '判断'); if (!questionData) { addLog(`未找到答案`, 'warning'); return; } // 查找选项 const options = findRadioOptions(questionElement); if (options.length === 0) { addLog('未找到判断题选项', 'warning'); return; } addLog(`找到 ${options.length} 个判断题选项`, 'info'); // 判断题答案标准化 const answer = questionData.answer.trim(); let targetOption = null; // 策略1:根据答案文本匹配选项 if (answer === '正确' || answer === '对' || answer === '是') { targetOption = options.find(opt => opt.text.includes('正确') || opt.text.includes('对') || opt.text.includes('是') ); } else if (answer === '错误' || answer === '错' || answer === '否') { targetOption = options.find(opt => opt.text.includes('错误') || opt.text.includes('错') || opt.text.includes('否') ); } // 策略2:根据value匹配 if (!targetOption) { if (answer === '正确' || answer === '对' || answer === '是') { targetOption = options.find(opt => opt.value === '1'); } else if (answer === '错误' || answer === '错' || answer === '否') { targetOption = options.find(opt => opt.value === '0'); } } // 策略3:根据选项顺序匹配 if (!targetOption && options.length >= 2) { if (answer === '正确' || answer === '对' || answer === '是') { targetOption = options[0]; } else if (answer === '错误' || answer === '错' || answer === '否') { targetOption = options[1]; } } if (targetOption) { if (!targetOption.radio.checked) { targetOption.radio.click(); targetOption.radio.dispatchEvent(new Event('change', { bubbles: true })); addLog(`判断题已选择: ${answer}`, 'success'); } } else { addLog(`无法匹配判断题选项,答案: ${answer}`, 'warning'); } } /** * 查找单选/判断题选项 */ function findRadioOptions(questionElement) { const options = []; // 查找当前题目所在容器的后续兄弟节点 let currentElement = questionElement.closest('.form-group.row'); while (currentElement) { const radios = currentElement.querySelectorAll('input[type="radio"]'); if (radios.length > 0) { radios.forEach(radio => { const label = radio.closest('label'); if (label) { const optionText = getOptionText(label); options.push({ radio: radio, value: radio.value, text: optionText }); } }); break; // 找到选项后就停止 } currentElement = currentElement.nextElementSibling; // 如果遇到下一个题目,停止查找 if (currentElement && currentElement.querySelector('.form-material-success:has(b)')) { break; } } return options; } /** * 处理简答题 */ async function handleShortAnswer(questionElement) { const questionText = getQuestionText(questionElement); const cleanQuestion = cleanQuestionText(questionText); addLog(`处理简答题: ${cleanQuestion.substring(0, 50)}...`, 'info'); const questionData = findAnswer(questionText, '简答'); if (!questionData) { addLog(`未找到答案`, 'warning'); return; } // 查找textarea - 简答题的输入框通常是textarea const questionRow = questionElement.closest('.form-group.row'); if (!questionRow) return; let currentRow = questionRow.nextElementSibling; let textarea = null; while (currentRow) { // 查找textarea textarea = currentRow.querySelector('textarea'); if (textarea) break; // 如果没有找到textarea,检查是否有文本输入框 const textInput = currentRow.querySelector('input[type="text"]'); if (textInput) { // 创建一个伪textarea对象 textarea = { value: '', set value(val) { textInput.value = val; this.value = val; }, dispatchEvent: (event) => textInput.dispatchEvent(event) }; break; } currentRow = currentRow.nextElementSibling; } if (!textarea) { addLog('未找到简答题输入框', 'warning'); return; } // 填入答案 textarea.value = questionData.answer; // 触发事件 textarea.dispatchEvent(new Event('input', { bubbles: true })); textarea.dispatchEvent(new Event('change', { bubbles: true })); addLog('简答题答案已填入', 'success'); } /** * 获取题目文本 */ function getQuestionText(element) { if (!element) return ''; // 复制元素以避免修改原DOM const clone = element.cloneNode(true); // 移除所有.luanma元素 clone.querySelectorAll('.luanma').forEach(el => el.remove()); // 获取文本并清理 let text = clone.textContent || clone.innerText || ''; return text.trim(); } /** * 获取选项文本 */ function getOptionText(label) { if (!label) return ''; // 复制元素以避免修改原DOM const clone = label.cloneNode(true); // 移除.luanma元素 clone.querySelectorAll('.luanma').forEach(el => el.remove()); let text = clone.textContent || clone.innerText || ''; return text.trim(); } /** * 自动答题主函数 */ async function autoAnswer() { addLog('=== 开始自动答题 ===', 'info'); if (Object.keys(questionBank).length === 0) { addLog('错误:请先导入题库文件', 'error'); return; } // 等待页面加载 await new Promise(resolve => setTimeout(resolve, 1000)); // 查找所有题目 const questionElements = document.querySelectorAll('.form-material-success:has(b)'); addLog(`找到 ${questionElements.length} 道题目`, 'info'); // 处理每道题 for (const questionElement of questionElements) { const questionText = getQuestionText(questionElement); const questionType = getQuestionType(questionText); addLog(`处理题目类型: ${questionType}`, 'info'); switch (questionType) { case '单选': await handleSingleChoice(questionElement); break; case '多选': await handleMultiChoice(questionElement); break; case '判断': await handleJudgment(questionElement); break; case '简答': await handleShortAnswer(questionElement); break; default: addLog(`未知题型: ${questionType}`, 'warning'); // 尝试作为简答题处理 await handleShortAnswer(questionElement); } // 每道题之间短暂延迟 await new Promise(resolve => setTimeout(resolve, 300)); } addLog('=== 答题完成 ===', 'success'); // 自动提交 setTimeout(autoSubmit, 2000); } /** * 自动提交 */ function autoSubmit() { const submitSelectors = [ '#submit', '.submit-btn', '[type="submit"]', '.btn-submit', '#btnSubmit', 'button:contains("提交")' ]; for (const selector of submitSelectors) { const submitBtn = document.querySelector(selector); if (submitBtn) { submitBtn.click(); addLog('已自动提交答案', 'success'); return; } } addLog('未找到提交按钮,请手动提交', 'warning'); } /** * 调试函数:显示所有题目和选项 */ function debugAllQuestions() { const questionElements = document.querySelectorAll('.form-material-success:has(b)'); console.log(`调试:找到 ${questionElements.length} 道题目`); questionElements.forEach((element, index) => { const questionText = getQuestionText(element); const questionType = getQuestionType(questionText); console.log(`题目${index+1} (${questionType}): ${questionText.substring(0, 60)}...`); if (questionType === '单选' || questionType === '判断') { const options = findRadioOptions(element); console.log(` 选项数: ${options.length}`); options.forEach((opt, optIndex) => { console.log(` 选项${optIndex+1}: value="${opt.value}", text="${opt.text}"`); }); } else if (questionType === '多选') { const options = findMultiChoiceOptions(element); console.log(` 选项数: ${options.length}`); options.forEach((opt, optIndex) => { console.log(` 选项${optIndex+1}: value="${opt.value}", text="${opt.text}"`); }); } console.log('---'); }); addLog('调试信息已在控制台输出', 'success'); } // 日志系统 function addLog(message, type = 'info') { const timestamp = new Date().toLocaleTimeString(); const logEntry = { time: timestamp, message: message, type: type }; logs.unshift(logEntry); if (logs.length > 100) logs.length = 100; updateLogDisplay(); } function updateLogDisplay() { const logList = document.getElementById('answerScriptLogs'); if (!logList) return; logList.innerHTML = ''; logs.forEach(log => { const logItem = document.createElement('div'); logItem.className = `log-item log-${log.type}`; logItem.innerHTML = `[${log.time}] ${log.message}`; logList.appendChild(logItem); }); } // 控制面板创建函数 function createControlPanel() { const panel = document.createElement('div'); panel.id = 'answerScriptPanel'; // 获取保存的位置 const savedPosition = GM_getValue('panelPosition') || { top: '20px', right: '20px' }; panel.style.cssText = ` position: fixed; top: ${savedPosition.top}; right: ${savedPosition.right}; width: 400px; max-height: 600px; background: white; border: 2px solid #4CAF50; border-radius: 10px; box-shadow: 0 10px 30px rgba(0,0,0,0.3); z-index: 9999; font-family: 'Microsoft YaHei', Arial, sans-serif; overflow: hidden; resize: both; `; panel.innerHTML = `
创新考试-贤程教育 v10.111
导入题库
请选择JSON题库文件(支持多个文件合并)
请导入题库文件...
操作日志
`; document.body.appendChild(panel); initPanelEvents(); makePanelDraggable(); } // 初始化面板事件 function initPanelEvents() { document.getElementById('autoAnswerBtn').addEventListener('click', () => { addLog('开始自动答题...', 'info'); autoAnswer(); }); document.getElementById('debugBtn').addEventListener('click', () => { debugAllQuestions(); }); document.getElementById('exportBtn').addEventListener('click', () => { exportQuestionBank(); }); document.getElementById('cleanBtn').addEventListener('click', () => { cleanQuestionBank(); }); document.getElementById('clearLogsBtn').addEventListener('click', () => { logs = []; updateLogDisplay(); addLog('日志已清空', 'info'); }); document.getElementById('importFile').addEventListener('change', async (e) => { const file = e.target.files[0]; if (!file) return; addLog(`正在导入: ${file.name}`, 'info'); try { await loadQuestionBankFromFile(file); e.target.value = ''; addLog('题库导入成功,可以开始答题', 'success'); } catch (error) { addLog(`导入失败: ${error.message}`, 'error'); } }); document.getElementById('minimizeBtn').addEventListener('click', () => { const panelBody = document.getElementById('panelBody'); const minimizeBtn = document.getElementById('minimizeBtn'); if (panelBody.style.display === 'none') { panelBody.style.display = 'block'; minimizeBtn.textContent = '−'; } else { panelBody.style.display = 'none'; minimizeBtn.textContent = '+'; } }); document.getElementById('closeBtn').addEventListener('click', () => { const panel = document.getElementById('answerScriptPanel'); if (panel) { panel.style.display = 'none'; addLog('控制面板已隐藏,刷新页面可重新显示', 'warning'); } }); } // 使面板可拖动 function makePanelDraggable() { const panel = document.getElementById('answerScriptPanel'); const header = panel.querySelector('div[style*="gradient"]'); let isDragging = false; let offsetX, offsetY; header.addEventListener('mousedown', startDrag); document.addEventListener('mousemove', drag); document.addEventListener('mouseup', stopDrag); function startDrag(e) { isDragging = true; const rect = panel.getBoundingClientRect(); offsetX = e.clientX - rect.left; offsetY = e.clientY - rect.top; header.style.cursor = 'grabbing'; } function drag(e) { if (!isDragging) return; e.preventDefault(); // 计算新位置 let newLeft = e.clientX - offsetX; let newTop = e.clientY - offsetY; // 限制在视窗内 const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; const panelWidth = panel.offsetWidth; const panelHeight = panel.offsetHeight; newLeft = Math.max(0, Math.min(newLeft, viewportWidth - panelWidth)); newTop = Math.max(0, Math.min(newTop, viewportHeight - panelHeight)); // 应用新位置 panel.style.left = newLeft + 'px'; panel.style.top = newTop + 'px'; panel.style.right = 'auto'; } function stopDrag() { if (!isDragging) return; isDragging = false; header.style.cursor = 'move'; // 保存位置 const position = { top: panel.style.top, left: panel.style.left }; GM_setValue('panelPosition', position); } } /** * 初始化脚本 */ async function init() { console.log('=== 创新考试自动答题脚本启动 v10.1 ==='); // 添加样式 addStyles(); // 创建控制面板 createControlPanel(); // 初始化题库 initQuestionBank(); addLog('脚本初始化完成', 'success'); addLog('请导入题库JSON文件,然后点击"自动答题"', 'info'); } function addStyles() { const style = document.createElement('style'); style.textContent = ` .log-item { padding: 4px 0; border-bottom: 1px solid #eee; font-family: 'Microsoft YaHei', Arial, sans-serif; font-size: 11px; line-height: 1.3; } .log-item:last-child { border-bottom: none; } .log-info { color: #2196F3; } .log-success { color: #4CAF50; font-weight: bold; } .log-error { color: #F44336; } .log-warning { color: #FF9800; } .log-time { color: #9E9E9E; font-size: 10px; margin-right: 5px; } /* 面板调整大小样式 */ #answerScriptPanel { resize: both; overflow: hidden; min-width: 350px; min-height: 200px; max-width: 90vw; max-height: 90vh; } #answerScriptPanel::-webkit-resizer { background-color: #4CAF50; padding: 5px; } `; document.head.appendChild(style); } // 添加Font Awesome图标 const faLink = document.createElement('link'); faLink.rel = 'stylesheet'; faLink.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css'; document.head.appendChild(faLink); // 页面加载完成后执行 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();