// ==UserScript== // @name hyw自动答题助手 // @namespace http://tampermonkey.net/ // @version 0.3.3 // @description hyw自动答题脚本 // @author 小马 // @license MIT // @match https://hyw.shixizhi.huawei.com/* // @grant GM_addStyle // @require https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js // @downloadURL none // ==/UserScript== (function () { 'use strict'; let questionBank = []; // 添加面板样式 GM_addStyle(` .answer-panel { position: fixed; top: 20px; right: 20px; background: white; padding: 15px; border: 1px solid #ccc; border-radius: 5px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); z-index: 2147483647; /* 最大z-index值 */ min-width: 200px; font-family: Arial, sans-serif; user-select: none; -webkit-user-select: none; -moz-user-select: none; } .answer-panel h3 { margin: 0 0 10px 0; padding: 0; font-size: 16px; color: #333; } .answer-panel select, .answer-panel input, .answer-panel button { margin: 5px 0; padding: 5px; width: 100%; box-sizing: border-box; } .answer-panel button { background: #007bff; color: white; border: none; border-radius: 3px; padding: 8px; margin: 5px 0; cursor: pointer; } .answer-panel button:hover { background: #0056b3; } #status { margin-top: 10px; color: #666; font-size: 14px; word-break: break-all; } /* 确保面板始终可见 */ .answer-panel * { display: block; visibility: visible !important; opacity: 1 !important; } `); // 创建控制面板 function createPanel() { try { // 先检查是否已存在面板 const existingPanel = document.querySelector('.answer-panel'); if (existingPanel) { existingPanel.remove(); } const panel = document.createElement('div'); panel.className = 'answer-panel'; panel.innerHTML = `

自动答题助手

等待上传题库...
`; // 确保面板被添加到 body 的最后 document.body.appendChild(panel); // 添加拖拽相关变量 let isDragging = false; let currentX; let currentY; let initialX; let initialY; let xOffset = 0; let yOffset = 0; // 拖拽开始 function dragStart(e) { // 如果点击的是select、input或button元素,不启动拖拽 if (e.target.tagName.toLowerCase() === 'select' || e.target.tagName.toLowerCase() === 'input' || e.target.tagName.toLowerCase() === 'button') { return; } if (e.type === "mousedown") { initialX = e.clientX - xOffset; initialY = e.clientY - yOffset; } else if (e.type === "touchstart") { initialX = e.touches[0].clientX - xOffset; initialY = e.touches[0].clientY - yOffset; } if (e.target === panel || panel.contains(e.target)) { isDragging = true; } } // 拖拽过程 function drag(e) { if (isDragging) { e.preventDefault(); if (e.type === "mousemove") { currentX = e.clientX - initialX; currentY = e.clientY - initialY; } else if (e.type === "touchmove") { currentX = e.touches[0].clientX - initialX; currentY = e.touches[0].clientY - initialY; } xOffset = currentX; yOffset = currentY; setTranslate(currentX, currentY, panel); } } // 设置面板位置 function setTranslate(xPos, yPos, el) { el.style.transform = `translate3d(${xPos}px, ${yPos}px, 0)`; } // 拖拽结束 function dragEnd() { initialX = currentX; initialY = currentY; isDragging = false; } // 添加拖拽事件监听 panel.addEventListener('mousedown', dragStart, false); document.addEventListener('mousemove', drag, false); document.addEventListener('mouseup', dragEnd, false); panel.addEventListener('touchstart', dragStart, false); document.addEventListener('touchmove', drag, false); document.addEventListener('touchend', dragEnd, false); // 阻止select的mousedown事件冒泡 document.getElementById('examType').addEventListener('mousedown', (e) => { e.stopPropagation(); }); // 原有的事件绑定 document.getElementById('fileInput').addEventListener('change', (e) => { const file = e.target.files[0]; if (file) processExcel(file); }); document.getElementById('startBtn').addEventListener('click', startAutoAnswer); document.getElementById('stopBtn').addEventListener('click', stopAutoAnswer); } catch (error) { console.error('创建控制面板失败:', error); // 可以尝试使用更简单的备用面板 try { const simplePanel = document.createElement('div'); simplePanel.className = 'answer-panel'; simplePanel.innerHTML = `

自动答题助手(简易版)

等待上传题库...
`; document.body.appendChild(simplePanel); } catch (backupError) { console.error('创建备用面板也失败:', backupError); } } } // 更新状态显示 function updateStatus(message) { document.getElementById('status').textContent = message; } let isRunning = false; // 停止自动答题 function stopAutoAnswer() { isRunning = false; updateStatus('已停止答题'); } // 开始自动答题 async function startAutoAnswer() { if (questionBank.length === 0) { updateStatus('请先上传题库!'); return; } isRunning = true; updateStatus('开始自动答题...'); while (isRunning) { try { const questionInfo = getCurrentQuestionInfo(); if (!questionInfo.question) { updateStatus('未检测到题目,可能已完成答题'); isRunning = false; break; } console.log('当前题目:', questionInfo.question); const answerInfo = findAnswer(questionInfo.question); if (answerInfo) { const selected = selectAnswer(answerInfo, questionInfo.isMultipleChoice); if (selected) { updateStatus(`已答题: ${questionInfo.question.substring(0, 20)}...`); // 减少答题后的等待时间为500ms await new Promise(resolve => setTimeout(resolve, 200)); if (!clickNext(true)) { updateStatus('无法找到下一题按钮,停止答题'); isRunning = false; break; } } else { updateStatus('答案选择失败,标记存疑'); if (!clickNext(false)) break; } } else { updateStatus('未找到匹配答案,标记存疑'); if (!clickNext(false)) break; } // 减少题目之间的等待时间为500ms await new Promise(resolve => setTimeout(resolve, 200)); } catch (error) { console.error('答题过程出错:', error); updateStatus('答题过程出错,已停止'); isRunning = false; break; } } } // 处理Excel文件上传 async function handleFileUpload(e) { const file = e.target.files[0]; const reader = new FileReader(); reader.onload = function (e) { const data = new Uint8Array(e.target.result); const workbook = XLSX.read(data, { type: 'array' }); const firstSheet = workbook.Sheets[workbook.SheetNames[0]]; questionBank = XLSX.utils.sheet_to_json(firstSheet); document.getElementById('status').innerText = `已加载 ${questionBank.length} 道题目`; }; reader.readAsArrayBuffer(file); } // 处理Excel数据结构 function processExcel(file) { const reader = new FileReader(); reader.onload = function (e) { const data = new Uint8Array(e.target.result); const workbook = XLSX.read(data, { type: 'array' }); const firstSheet = workbook.Sheets[workbook.SheetNames[0]]; const jsonData = XLSX.utils.sheet_to_json(firstSheet); // 获取当前选择的考试类型 const examType = document.getElementById('examType').value; // 根据不同的考试类型处理数据 if (examType === 'security') { // 保密考试题库格式 questionBank = jsonData.map(row => ({ sequence: row['序号'], type: row['试题类别'], questionId: row['试题类型'], question: row['试题题目'], options: row['选项'], answer: row['正确答案'] })); } else if (examType === 'functional') { // 职能考试题格式 questionBank = jsonData.map(row => ({ sequence: row['题库'], type: row['题型'], questionId: '', question: row['题目'], options: `${row['选项A']}\n${row['选项B']}\n${row['选项C']}\n${row['选项D']}\n${row['选项E'] || ''}\n${row['选项F'] || ''}\n${row['选项G'] || ''}\n${row['选项H'] || ''}`.trim(), answer: row['正确答案'] })); } updateStatus(`已导入 ${questionBank.length} 道题目`); }; reader.readAsArrayBuffer(file); } // 查找答案 function findAnswer(currentQuestion) { // 直接查找匹配的题目,不做文本清理 const matchedQuestion = questionBank.find(item => { return item.question.includes(currentQuestion) || currentQuestion.includes(item.question); }); console.log('匹配题目:', matchedQuestion); if (matchedQuestion) { return { answer: matchedQuestion.answer, type: matchedQuestion.type // 返回题目类型,用于判断单选/多选 }; } return null; } // 获取当前题目信息 function getCurrentQuestionInfo() { try { // 修改选择器以匹配实际DOM结构 const questionElement = document.querySelector('.main-title .content'); if (!questionElement) { console.log('未找到题目元素'); return { question: '', isMultipleChoice: false }; } const question = questionElement.textContent.trim(); // 判断是否为多选题 - 检查题类型标签 const typeElement = document.querySelector('.type-name'); const isMultipleChoice = typeElement && typeElement.textContent.includes('多选题'); return { question, isMultipleChoice }; } catch (error) { console.error('获取题目信息出错:', error); return { question: '', isMultipleChoice: false }; } } // 选择答案 function selectAnswer(answerInfo, isMultipleChoice) { try { if (!answerInfo) return false; const { answer } = answerInfo; const options = document.querySelectorAll('.option-list-item'); let selected = false; // 将答案字符串转换为字母数组 const answers = answer.toUpperCase().split(''); const optionLetters = ['A', 'B', 'C', 'D', 'E', 'F']; options.forEach((option, index) => { const currentLetter = optionLetters[index]; if (answers.includes(currentLetter)) { const input = isMultipleChoice ? option.querySelector('input[type="checkbox"]') : option.querySelector('input[type="radio"]'); if (input && !input.checked) { // 使用现代的事件触发方式 input.click(); selected = true; } } }); return selected; } catch (error) { console.error('选择答案出错:', error); return false; } } // 点击下一题 function clickNext(answered) { try { // 获取所有按钮 const buttons = document.querySelectorAll('.subject-btns .subject-btn'); let nextButton = null; // 遍历所有按钮找到"下一题"按钮 for (const button of buttons) { if (button.textContent.trim() === '下一题') { nextButton = button; break; } } if (nextButton) { nextButton.click(); return true; } return false; } catch (error) { console.error('点击下一题按钮出错:', error); return false; } } // 修改初始化部分 function init() { // 如果DOM已经加载完成 if (document.readyState === 'complete' || document.readyState === 'interactive') { createPanel(); } else { // 否则等待DOM加载完成 window.addEventListener('DOMContentLoaded', createPanel); } } // 移除原有的 MutationObserver 代码,改用以下方式 init(); })();