// ==UserScript== // @name 物理实验助手 // @namespace http://tampermonkey.net/ // @version 1.2.0 // @description 完美解决乱序、空选项导致判断题错位的问题。自动提取隐藏域答案并勾选,支持自动答题记忆、禁用网页弹窗、面板自由拖动。 // @author 毫厘 // @match http://59.69.101.153/lab/Reports/* // @match http://59.69.103.147/Reports/* // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; // 1. 创建美化的 UI 面板 function createPanel() { if (document.getElementById('auto-helper-panel')) return; // 防止重复注入 const panel = document.createElement('div'); panel.id = 'auto-helper-panel'; panel.innerHTML = `
实验助手 v1.2
正在获取答案...
`; document.body.appendChild(panel); const style = document.createElement('style'); style.textContent = ` #auto-helper-panel { position: fixed; top: 20px; right: 20px; width: 230px; background: #ffffff; border-radius: 8px; z-index: 10000; box-shadow: 0 4px 20px rgba(0,0,0,0.15); font-family: sans-serif; overflow: hidden; border: 1px solid #e0e0e0; transition: height 0.3s ease; } #helper-header { background: #4CAF50; color: white; padding: 10px 15px; display: flex; justify-content: space-between; align-items: center; font-weight: bold; cursor: move; user-select: none; } #toggle-btn { background: rgba(255,255,255,0.2); border: none; color: white; cursor: pointer; border-radius: 4px; padding: 2px 8px; font-weight: bold; } #helper-body { padding: 15px; } #answer-list { margin-bottom: 12px; font-size: 13px; color: #333; line-height: 1.6; max-height: 250px; overflow-y: auto;} .answer-item { border-bottom: 1px dashed #eee; padding: 4px 0; } .answer-val { color: #e91e63; font-weight: bold; margin-left: 5px; } .auto-run-wrapper { display: flex; align-items: center; margin-bottom: 12px; font-size: 13px; color: #2c3e50; cursor: pointer; user-select: none; } .auto-run-wrapper input { margin-right: 6px; cursor: pointer; } #auto-fill-btn { width: 100%; background: #4CAF50; color: white; border: none; padding: 10px; border-radius: 5px; cursor: pointer; font-size: 14px; transition: background 0.2s; font-weight: bold; } #auto-fill-btn:hover { background: #45a049; } #helper-footer { font-size: 11px; color: #999; margin-top: 10px; text-align: center; } .collapsed #helper-body { display: none; } `; document.head.appendChild(style); // 面板折叠逻辑 document.getElementById('toggle-btn').onclick = (e) => { e.stopPropagation(); // 防止触发拖拽 panel.classList.toggle('collapsed'); document.getElementById('toggle-btn').textContent = panel.classList.contains('collapsed') ? '+' : '-'; }; // 面板拖动逻辑 makeDraggable(panel, document.getElementById('helper-header')); } // 实现拖拽功能的通用函数 function makeDraggable(panel, handle) { let isDragging = false, offsetX, offsetY; handle.addEventListener('mousedown', (e) => { if (e.target.id === 'toggle-btn') return; isDragging = true; const rect = panel.getBoundingClientRect(); // 将right定位转换为left定位,防止拖拽时跳动 panel.style.right = 'auto'; panel.style.left = rect.left + 'px'; panel.style.top = rect.top + 'px'; offsetX = e.clientX - rect.left; offsetY = e.clientY - rect.top; panel.style.transition = 'none'; // 拖动时取消动画避免迟钝 }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; let x = e.clientX - offsetX; let y = e.clientY - offsetY; // 防止拖出屏幕可视区域 x = Math.max(0, Math.min(x, window.innerWidth - panel.offsetWidth)); y = Math.max(0, Math.min(y, window.innerHeight - panel.offsetHeight)); panel.style.left = `${x}px`; panel.style.top = `${y}px`; }); document.addEventListener('mouseup', () => { if (isDragging) { isDragging = false; panel.style.transition = 'height 0.3s ease'; // 恢复动画 } }); } // 2. 完美提取数据(彻底解决乱序和空白选项问题) function getQuestionsData() { const data = []; const hiddenInputs = document.querySelectorAll('input[id^="result_refer_pre"]'); hiddenInputs.forEach((hiddenInput) => { const match = hiddenInput.id.match(/result_refer_pre(\d+)/); if (!match) return; const index = parseInt(match[1]); const value = hiddenInput.value; const selectedLetters = []; const elementsToClick =[]; // 获取该题目下所有带有真实文本(label)的有效选项 const validLabels = document.querySelectorAll(`label[for^="pre${index}_op"]`); const labelMap = {}; validLabels.forEach((lbl, idx) => { let forId = lbl.getAttribute('for'); labelMap[forId] = { text: lbl.innerText.trim(), visualIndex: idx // 该选项在可见选项里的实际排序 0->A, 1->B... }; }); // 遍历答案隐藏域,比如 "0010" for (let i = 0; i < value.length; i++) { if (value[i] === '1') { let targetId = `pre${index}_op${i}`; let targetCheckbox = document.querySelector(`#${targetId}`); if (targetCheckbox) { elementsToClick.push(targetCheckbox); let labelInfo = labelMap[targetId]; if (labelInfo) { // 优先尝试从 label 文本截取如 "A.正确" 中的 "A" let letterMatch = labelInfo.text.match(/^[A-G]/i); if (letterMatch) { selectedLetters.push(letterMatch[0].toUpperCase()); } else { // 兜底:如果文本没写A/B,按它在所有可见选项中的顺位映射 (0=A, 1=B) const optionsMap = ['A', 'B', 'C', 'D', 'E', 'F', 'G']; selectedLetters.push(optionsMap[labelInfo.visualIndex] || '?'); } } else { // 如果连 label 都没有,记作未知 ? selectedLetters.push('?'); } } } } data.push({ index: index, rawLetters: [...new Set(selectedLetters)].sort(), // 去重并按字母表排序(如 AC 而不会是 CA) elements: elementsToClick }); }); return data.sort((a, b) => a.index - b.index); // 确保按题号排序 } // 3. 更新面板显示 function updateAnswers(data) { let listHtml = ''; if (data.length === 0) { listHtml = '
未找到题目
请确认是否在预习页
'; } else { data.forEach((item, i) => { listHtml += `
第${i + 1}题:${item.rawLetters.join('') || '无'}
`; }); } document.getElementById('answer-list').innerHTML = listHtml; } // 4. 执行自动勾选逻辑 function selectAnswers(isAuto = false) { const data = getQuestionsData(); data.forEach(item => { // 先获取当前题目的所有选项,用于覆盖和取消原本勾错的选项 const allOptionsDom = document.querySelectorAll(`input[id^="pre${item.index}_op"]`); allOptionsDom.forEach(el => { // 如果当前复选框被禁用(例如已提交状态),跳过点击以免报错 if (el.disabled) return; let shouldBeChecked = item.elements.includes(el); // 如果当前状态与目标状态不一致,则触发点击 if (el.checked !== shouldBeChecked) { el.click(); // 触发页面本身的监听事件 if (el.checked !== shouldBeChecked) { el.checked = shouldBeChecked; // 强制兜底勾选 el.dispatchEvent(new Event('change', { bubbles: true })); } } }); }); // 按钮状态反馈 const btn = document.getElementById('auto-fill-btn'); btn.textContent = isAuto ? '已自动勾选完毕!' : '勾选完成!'; btn.style.background = '#2196F3'; setTimeout(() => { btn.textContent = '手动一键勾选'; btn.style.background = '#4CAF50'; }, 2000); } // 初始化脚本 window.addEventListener('load', () => { createPanel(); // 解析数据并渲染面板 const questionsData = getQuestionsData(); updateAnswers(questionsData); // 处理自动答题功能 const autoRunChk = document.getElementById('auto-run-chk'); const isAutoRun = localStorage.getItem('physics_helper_autorun') === 'true'; autoRunChk.checked = isAutoRun; // 勾选框事件 autoRunChk.addEventListener('change', (e) => { localStorage.setItem('physics_helper_autorun', e.target.checked); if (e.target.checked) selectAnswers(true); }); // 手动点击事件 document.getElementById('auto-fill-btn').onclick = () => selectAnswers(false); // 如果开启了自动答题,延迟500ms执行(等待DOM节点彻底渲染完毕) if (isAutoRun && questionsData.length > 0) { setTimeout(() => selectAnswers(true), 500); } }); })();