您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
智学网辅助阅卷工具,支持完全自定义快捷键、悬浮窗控制和快速回评功能
// ==UserScript== // @name 智学网阅卷助手 - 快捷键版 // @namespace http://tampermonkey.net/ // @version 1.3 // @description 智学网辅助阅卷工具,支持完全自定义快捷键、悬浮窗控制和快速回评功能 // @author YourName // @match *://*.zhixue.com/* // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @grant unsafeWindow // @license Elegy挽歌 // ==/UserScript== (function() { 'use strict'; // 焦点控制标志 let isFocusLocked = false; // 默认配置 const defaultConfig = { scoreShortcuts: { '1': 0, // 数字键1对应0分 '2': 1, // 数字键2对应1分 '3': 2, // 数字键3对应2分 '4': 3, // 数字键4对应3分 '5': 4, // 数字键5对应4分 '6': 5, // 数字键6对应5分 '0': 0, // 0键对应0分 'q': 1, // Q键对应1分 'w': 2, // W键对应2分 'e': 3, // E键对应3分 'r': 4, // R键对应4分 't': 5, // T键对应5分 }, prevShortcut: 'Backspace', // 回评上一份试卷的快捷键 autoCheck: true, // 是否自动勾选 theme: 'dark', // 默认主题 focusLock: true // 焦点锁定 }; // 加载用户配置 let config = Object.assign({}, defaultConfig, GM_getValue('config', {})); // 添加全局样式 GM_addStyle(` #assistant-container { position: fixed; top: 20px; right: 20px; width: 320px; background: ${config.theme === 'dark' ? '#2d3748' : '#ffffff'}; color: ${config.theme === 'dark' ? '#e2e8f0' : '#2d3748'}; border-radius: 12px; box-shadow: 0 10px 25px rgba(0,0,0,0.2); z-index: 99999; overflow: hidden; transition: all 0.3s ease; font-family: 'Segoe UI', system-ui, sans-serif; border: 1px solid ${config.theme === 'dark' ? '#4a5568' : '#e2e8f0'}; } #assistant-header { background: ${config.theme === 'dark' ? '#1a202c' : '#f7fafc'}; padding: 15px; display: flex; justify-content: space-between; align-items: center; cursor: move; border-bottom: 1px solid ${config.theme === 'dark' ? '#4a5568' : '#e2e8f0'}; } #assistant-title { font-weight: 600; font-size: 16px; display: flex; align-items: center; gap: 8px; } #assistant-title svg { width: 20px; height: 20px; fill: ${config.theme === 'dark' ? '#63b3ed' : '#4299e1'}; } #assistant-controls { display: flex; gap: 10px; } .assistant-btn { background: none; border: none; width: 28px; height: 28px; border-radius: 6px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: ${config.theme === 'dark' ? '#cbd5e0' : '#718096'}; transition: all 0.2s; } .assistant-btn:hover { background: ${config.theme === 'dark' ? '#4a5568' : '#edf2f7'}; color: ${config.theme === 'dark' ? '#ffffff' : '#2d3748'}; } #assistant-content { padding: 15px; max-height: 500px; overflow-y: auto; } .section { margin-bottom: 20px; } .section-title { font-size: 14px; font-weight: 600; margin-bottom: 12px; display: flex; align-items: center; gap: 6px; } .section-title svg { width: 16px; height: 16px; fill: ${config.theme === 'dark' ? '#63b3ed' : '#4299e1'}; } .shortcut-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-bottom: 15px; } .shortcut-item { background: ${config.theme === 'dark' ? '#4a5568' : '#edf2f7'}; border-radius: 8px; padding: 10px; display: flex; flex-direction: column; align-items: center; transition: all 0.2s; position: relative; } .shortcut-item:hover { transform: translateY(-2px); box-shadow: 0 4px 6px rgba(0,0,0,0.1); } .shortcut-key { width: 36px; height: 36px; background: ${config.theme === 'dark' ? '#63b3ed' : '#4299e1'}; color: white; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 16px; margin-bottom: 8px; } .shortcut-value { font-size: 14px; } .shortcut-delete { position: absolute; top: -6px; right: -6px; width: 20px; height: 20px; background: #e53e3e; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: white; font-size: 12px; cursor: pointer; opacity: 0; transition: opacity 0.2s; } .shortcut-item:hover .shortcut-delete { opacity: 1; } .divider { height: 1px; background: ${config.theme === 'dark' ? '#4a5568' : '#e2e8f0'}; margin: 15px 0; } .action-item { display: flex; justify-content: space-between; align-items: center; padding: 10px; background: ${config.theme === 'dark' ? '#4a5568' : '#edf2f7'}; border-radius: 8px; margin-bottom: 10px; cursor: pointer; transition: all 0.2s; } .action-item:hover { background: ${config.theme === 'dark' ? '#5a6578' : '#e2e8f0'}; } .action-label { display: flex; align-items: center; gap: 8px; } .action-key { background: ${config.theme === 'dark' ? '#2d3748' : '#cbd5e0'}; color: ${config.theme === 'dark' ? '#e2e8f0' : '#2d3748'}; padding: 3px 8px; border-radius: 4px; font-size: 12px; } .toggle-switch { position: relative; display: inline-block; width: 40px; height: 22px; } .toggle-switch input { opacity: 0; width: 0; height: 0; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: .4s; border-radius: 34px; } .slider:before { position: absolute; content: ""; height: 16px; width: 16px; left: 3px; bottom: 3px; background-color: white; transition: .4s; border-radius: 50%; } input:checked + .slider { background-color: #4299e1; } input:checked + .slider:before { transform: translateX(18px); } .status-indicator { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-left: 8px; background-color: #48bb78; } .status-indicator.inactive { background-color: #e53e3e; } .theme-toggle { display: flex; justify-content: space-between; align-items: center; padding: 10px 0; } .theme-label { display: flex; align-items: center; gap: 8px; } .focus-notification { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background: #e53e3e; color: white; padding: 10px 20px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 100000; animation: fadeInOut 2.5s forwards; font-size: 14px; display: flex; align-items: center; gap: 8px; } @keyframes fadeInOut { 0% { opacity: 0; bottom: 10px; } 10% { opacity: 1; bottom: 20px; } 90% { opacity: 1; bottom: 20px; } 100% { opacity: 0; bottom: 30px; } } .custom-shortcut-form { display: flex; gap: 10px; margin-top: 15px; } .key-input { flex: 1; padding: 8px 12px; border-radius: 8px; border: 1px solid ${config.theme === 'dark' ? '#4a5568' : '#cbd5e0'}; background: ${config.theme === 'dark' ? '#1a202c' : '#f7fafc'}; color: ${config.theme === 'dark' ? '#e2e8f0' : '#2d3748'}; outline: none; } .score-input { width: 60px; padding: 8px 12px; border-radius: 8px; border: 1px solid ${config.theme === 'dark' ? '#4a5568' : '#cbd5e0'}; background: ${config.theme === 'dark' ? '#1a202c' : '#f7fafc'}; color: ${config.theme === 'dark' ? '#e2e8f0' : '#2d3748'}; outline: none; } .add-btn { padding: 8px 15px; background: #4299e1; color: white; border: none; border-radius: 8px; cursor: pointer; transition: all 0.2s; } .add-btn:hover { background: #3182ce; } .modal-backdrop { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 99998; display: flex; align-items: center; justify-content: center; } .key-modal { background: ${config.theme === 'dark' ? '#2d3748' : '#ffffff'}; border-radius: 12px; padding: 20px; width: 300px; box-shadow: 0 10px 25px rgba(0,0,0,0.2); } .modal-title { font-size: 18px; font-weight: 600; margin-bottom: 15px; text-align: center; } .key-input-large { width: 100%; padding: 12px; border-radius: 8px; border: 1px solid ${config.theme === 'dark' ? '#4a5568' : '#cbd5e0'}; background: ${config.theme === 'dark' ? '#1a202c' : '#f7fafc'}; color: ${config.theme === 'dark' ? '#e2e8f0' : '#2d3748'}; outline: none; font-size: 16px; text-align: center; margin-bottom: 15px; } .modal-buttons { display: flex; gap: 10px; } .modal-btn { flex: 1; padding: 10px; border-radius: 8px; border: none; cursor: pointer; font-weight: 500; } .confirm-btn { background: #4299e1; color: white; } .cancel-btn { background: ${config.theme === 'dark' ? '#4a5568' : '#e2e8f0'}; color: ${config.theme === 'dark' ? '#e2e8f0' : '#4a5568'}; } .shortcut-help { font-size: 12px; color: ${config.theme === 'dark' ? '#a0aec0' : '#718096'}; margin-top: 5px; text-align: center; } `); // 创建悬浮窗容器 const container = document.createElement('div'); container.id = 'assistant-container'; container.innerHTML = ` <div id="assistant-header"> <div id="assistant-title"> <svg viewBox="0 0 24 24"> <path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V5h14v14z"/> <path d="M7 10h10v2H7zm0 4h5v2H7z"/> </svg> 智学网阅卷助手By.挽歌 <span class="status-indicator"></span> </div> <div id="assistant-controls"> <button class="assistant-btn" id="minimize-btn"> <svg viewBox="0 0 24 24" width="16" height="16"> <path d="M19 13H5v-2h14v2z"/> </svg> </button> <button class="assistant-btn" id="close-btn"> <svg viewBox="0 0 24 24" width="16" height="16"> <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/> </svg> </button> </div> </div> <div id="assistant-content"> <div class="section"> <div class="section-title"> <svg viewBox="0 0 24 24"> <path d="M3 17v2h6v-2H3zM3 5v2h10V5H3zm10 16v-2h8v-2h-8v-2h-2v6h2zM7 9v2H3v2h4v2h2V9H7zm14 4v-2H11v2h10zm-6-4h2V7h4V5h-4V3h-2v6z"/> </svg> 评分快捷键配置 </div> <div class="shortcut-grid" id="shortcut-grid"></div> <div class="custom-shortcut-form"> <input type="text" class="key-input" id="new-key" placeholder="输入按键" readonly> <input type="number" class="score-input" id="new-score" min="0" max="100" placeholder="分数"> <button class="add-btn" id="add-shortcut-btn">添加</button> </div> <div class="shortcut-help">点击输入框后按任意键设置按键</div> </div> <div class="divider"></div> <div class="section"> <div class="section-title"> <svg viewBox="0 0 24 24"> <path d="M14 10H2v2h12v-2zm0-4H2v2h12V6zm4 8v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zM2 16h8v-2H2v2z"/> </svg> 功能快捷键 </div> <div class="action-item" id="prev-paper-action"> <div class="action-label"> <svg viewBox="0 0 24 24" width="18" height="18"> <path d="M14 7l-5 5 5 5V7z"/> </svg> 回评上一份试卷 </div> <div class="action-key" id="prev-key">${config.prevShortcut}</div> </div> <div class="action-item" id="set-prev-key"> <div class="action-label"> <svg viewBox="0 0 24 24" width="18" height="18"> <path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 12h-2v-2h2v2zm0-4h-2V6h2v4z"/> </svg> 设置回评快捷键 </div> <div class="action-key">点击设置</div> </div> </div> <div class="divider"></div> <div class="section"> <div class="section-title"> <svg viewBox="0 0 24 24"> <path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"/> </svg> 焦点与显示设置 </div> <div class="action-item"> <div class="action-label"> <svg viewBox="0 0 24 24" width="18" height="18"> <path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/> </svg> 焦点锁定功能 </div> <label class="toggle-switch"> <input type="checkbox" id="focus-lock-toggle" ${config.focusLock ? 'checked' : ''}> <span class="slider"></span> </label> </div> <div class="action-item"> <div class="action-label"> <svg viewBox="0 0 24 24" width="18" height="18"> <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/> </svg> 自动勾选阅卷辅助 </div> <label class="toggle-switch"> <input type="checkbox" id="auto-check-toggle" ${config.autoCheck ? 'checked' : ''}> <span class="slider"></span> </label> </div> <div class="theme-toggle"> <div class="theme-label"> <svg viewBox="0 0 24 24" width="18" height="18"> <path d="M20 8.69V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12 20 8.69zM12 18c-3.31 0-6-2.69-6-6s2.69-6 6-6 6 2.69 6 6-2.69 6-6 6zm0-10c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4z"/> </svg> 界面主题 </div> <div> <button class="theme-btn ${config.theme === 'light' ? 'active' : ''}" data-theme="light">浅色</button> <button class="theme-btn ${config.theme === 'dark' ? 'active' : ''}" data-theme="dark">深色</button> </div> </div> </div> <div class="divider"></div> <div class="section"> <div class="section-title"> <svg viewBox="0 0 24 24"> <path d="M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z"/> </svg> 使用说明 </div> <div style="font-size:13px; line-height:1.5; color: ${config.theme === 'dark' ? '#a0aec0' : '#718096'}"> <p>1. 使用自定义快捷键快速打分</p> <p>2. 按<span class="action-key">${config.prevShortcut}</span>回评上一份试卷</p> <p>3. 打分后自动进入下一份试卷</p> <p>4. 拖动顶部栏可移动悬浮窗</p> <p>5. 启用"焦点锁定"防止输入框抢占焦点</p> </div> </div> </div> `; document.body.appendChild(container); // 渲染快捷键网格 function renderShortcuts() { const shortcutGrid = container.querySelector('#shortcut-grid'); shortcutGrid.innerHTML = ''; for (let key in config.scoreShortcuts) { const score = config.scoreShortcuts[key]; const shortcutItem = document.createElement('div'); shortcutItem.className = 'shortcut-item'; shortcutItem.innerHTML = ` <div class="shortcut-key">${key}</div> <div class="shortcut-value">${score} 分</div> <div class="shortcut-delete" data-key="${key}">×</div> `; shortcutGrid.appendChild(shortcutItem); // 添加删除事件 shortcutItem.querySelector('.shortcut-delete').addEventListener('click', (e) => { e.stopPropagation(); delete config.scoreShortcuts[e.target.dataset.key]; saveConfig(); renderShortcuts(); showNotification(`已删除快捷键: ${e.target.dataset.key}`); }); } } // 初始渲染快捷键 renderShortcuts(); // 添加主题按钮样式 GM_addStyle(` .theme-btn { padding: 5px 12px; border: none; border-radius: 6px; background: ${config.theme === 'dark' ? '#4a5568' : '#e2e8f0'}; color: ${config.theme === 'dark' ? '#e2e8f0' : '#4a5568'}; cursor: pointer; font-size: 13px; margin-left: 8px; transition: all 0.2s; } .theme-btn.active { background: ${config.theme === 'dark' ? '#63b3ed' : '#4299e1'}; color: white; } .theme-btn:hover { opacity: 0.9; } `); // 拖拽功能 let isDragging = false; let offsetX, offsetY; const header = container.querySelector('#assistant-header'); header.addEventListener('mousedown', (e) => { isDragging = true; offsetX = e.clientX - container.getBoundingClientRect().left; offsetY = e.clientY - container.getBoundingClientRect().top; container.style.cursor = 'grabbing'; }); document.addEventListener('mousemove', (e) => { if (isDragging) { const x = e.clientX - offsetX; const y = e.clientY - offsetY; // 边界检查 const maxX = window.innerWidth - container.offsetWidth; const maxY = window.innerHeight - container.offsetHeight; container.style.left = Math.min(Math.max(x, 10), maxX - 10) + 'px'; container.style.top = Math.min(Math.max(y, 10), maxY - 10) + 'px'; } }); document.addEventListener('mouseup', () => { isDragging = false; container.style.cursor = 'default'; }); // 折叠功能 let isMinimized = false; const minimizeBtn = container.querySelector('#minimize-btn'); const content = container.querySelector('#assistant-content'); minimizeBtn.addEventListener('click', () => { isMinimized = !isMinimized; if (isMinimized) { content.style.display = 'none'; minimizeBtn.innerHTML = ` <svg viewBox="0 0 24 24" width="16" height="16"> <path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z"/> </svg> `; container.style.height = 'auto'; } else { content.style.display = 'block'; minimizeBtn.innerHTML = ` <svg viewBox="0 0 24 24" width="16" height="16"> <path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z"/> </svg> `; } }); // 关闭按钮 const closeBtn = container.querySelector('#close-btn'); closeBtn.addEventListener('click', () => { container.style.display = 'none'; }); // 自动勾选功能 const autoCheckToggle = container.querySelector('#auto-check-toggle'); autoCheckToggle.addEventListener('change', () => { config.autoCheck = autoCheckToggle.checked; saveConfig(); if (config.autoCheck) { checkElement(); } }); // 焦点锁定功能 const focusLockToggle = container.querySelector('#focus-lock-toggle'); focusLockToggle.addEventListener('change', () => { config.focusLock = focusLockToggle.checked; saveConfig(); if (config.focusLock) { showNotification('焦点锁定已启用'); lockFocus(); } else { showNotification('焦点锁定已禁用'); } }); // 主题切换 const themeButtons = container.querySelectorAll('.theme-btn'); themeButtons.forEach(btn => { btn.addEventListener('click', () => { const theme = btn.dataset.theme; config.theme = theme; saveConfig(); location.reload(); // 重新加载以应用新主题 }); }); // 保存配置 function saveConfig() { GM_setValue('config', config); } // 自动勾选目标元素 function checkElement() { const checkInterval = setInterval(() => { const targetElement = document.evaluate( '//*[@id="CalcPlattitle"]/span[2]/a', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue; if (targetElement) { targetElement.click(); clearInterval(checkInterval); } }, 500); } // 显示通知 function showNotification(message) { const existingNote = document.querySelector('.focus-notification'); if (existingNote) existingNote.remove(); const notification = document.createElement('div'); notification.className = 'focus-notification'; notification.innerHTML = ` <svg viewBox="0 0 24 24" width="18" height="18" fill="white"> <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/> </svg> ${message} `; document.body.appendChild(notification); setTimeout(() => { notification.remove(); }, 2500); } // 焦点锁定功能 function lockFocus() { // 监听焦点变化 document.addEventListener('focusin', (e) => { if (!config.focusLock) return; const input = document.getElementById('txt_marking_2'); if (input && e.target === input) { // 如果焦点被转移到输入框,立即移回body e.preventDefault(); document.body.focus(); showNotification('焦点已锁定到页面'); } }); // 初始设置焦点 document.body.focus(); } // 添加快捷键功能 const newKeyInput = container.querySelector('#new-key'); const newScoreInput = container.querySelector('#new-score'); const addShortcutBtn = container.querySelector('#add-shortcut-btn'); // 按键捕获功能 newKeyInput.addEventListener('focus', () => { newKeyInput.value = '按下按键...'; isFocusLocked = false; // 临时禁用焦点锁定 }); newKeyInput.addEventListener('keydown', (e) => { e.preventDefault(); // 忽略功能键 if (['Shift', 'Control', 'Alt', 'Meta', 'CapsLock'].includes(e.key)) { return; } const key = e.key.length === 1 ? e.key.toUpperCase() : e.key; newKeyInput.value = key; newScoreInput.focus(); isFocusLocked = config.focusLock; // 恢复焦点锁定状态 }); // 添加新快捷键 addShortcutBtn.addEventListener('click', () => { const key = newKeyInput.value; const score = parseInt(newScoreInput.value); if (!key || key === '按下按键...') { showNotification('请先设置按键'); return; } if (isNaN(score) || score < 0 || score > 100) { showNotification('请输入0-100之间的分数'); return; } // 添加或更新快捷键 config.scoreShortcuts[key] = score; saveConfig(); renderShortcuts(); showNotification(`已添加快捷键: ${key} → ${score}分`); // 清空表单 newKeyInput.value = ''; newScoreInput.value = ''; }); // 设置回评快捷键 const setPrevKeyBtn = container.querySelector('#set-prev-key'); let keyModal = null; setPrevKeyBtn.addEventListener('click', () => { // 创建模态框 const backdrop = document.createElement('div'); backdrop.className = 'modal-backdrop'; backdrop.innerHTML = ` <div class="key-modal"> <div class="modal-title">设置回评快捷键</div> <input type="text" class="key-input-large" id="modal-key-input" placeholder="按下按键..." readonly> <div class="shortcut-help">按下您想设置的快捷键</div> <div class="modal-buttons"> <button class="modal-btn cancel-btn" id="cancel-btn">取消</button> <button class="modal-btn confirm-btn" id="confirm-btn">确认</button> </div> </div> `; document.body.appendChild(backdrop); keyModal = backdrop; const keyInput = backdrop.querySelector('#modal-key-input'); keyInput.focus(); // 按键捕获 keyInput.addEventListener('keydown', (e) => { e.preventDefault(); // 忽略功能键 if (['Shift', 'Control', 'Alt', 'Meta', 'CapsLock'].includes(e.key)) { return; } const key = e.key.length === 1 ? e.key.toUpperCase() : e.key; keyInput.value = key; }); // 确认按钮 backdrop.querySelector('#confirm-btn').addEventListener('click', () => { const key = keyInput.value; if (!key || key === '按下按键...') { showNotification('请先设置按键'); return; } config.prevShortcut = key; saveConfig(); container.querySelector('#prev-key').textContent = key; showNotification(`回评快捷键已设置为: ${key}`); backdrop.remove(); }); // 取消按钮 backdrop.querySelector('#cancel-btn').addEventListener('click', () => { backdrop.remove(); }); }); // 初始化功能 if (config.autoCheck) { setTimeout(checkElement, 1000); } if (config.focusLock) { lockFocus(); } // 快捷键功能 document.addEventListener('keydown', function(e) { // 忽略在输入框中的按键(如果焦点锁定已禁用) if (!config.focusLock && (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA')) { return; } const key = e.key; // 检查是否为评分快捷键 if (config.scoreShortcuts.hasOwnProperty(key)) { const score = config.scoreShortcuts[key]; const scoreElement = document.evaluate( `//*[@id="platContent"]/a[${score + 1}]`, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue; if (scoreElement) { scoreElement.click(); // 保持焦点在页面上 setTimeout(() => { document.body.focus(); }, 100); } return; } // 检查是否为回评快捷键 if (key === config.prevShortcut) { const prevElement = document.evaluate( '//*[@id="app"]/div/div[1]/div/div[2]/div/div[1]/div[1]/div[1]/div[3]/span[9]/a', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue; if (prevElement) { prevElement.click(); // 保持焦点在页面上 setTimeout(() => { document.body.focus(); }, 100); } } }); // 状态指示器 const statusIndicator = container.querySelector('.status-indicator'); setInterval(() => { statusIndicator.classList.toggle('inactive'); setTimeout(() => { statusIndicator.classList.toggle('inactive'); }, 500); }, 2000); // 回评按钮点击事件 const prevPaperAction = container.querySelector('#prev-paper-action'); prevPaperAction.addEventListener('click', () => { const prevElement = document.evaluate( '//*[@id="app"]/div/div[1]/div/div[2]/div/div[1]/div[1]/div[1]/div[3]/span[9]/a', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue; if (prevElement) { prevElement.click(); } }); // 初始显示状态 container.style.display = 'block'; // 添加菜单命令 GM_registerMenuCommand("显示/隐藏悬浮窗", function() { if (container.style.display === 'none') { container.style.display = 'block'; showNotification('悬浮窗已显示'); } else { container.style.display = 'none'; showNotification('悬浮窗已隐藏'); } }); GM_registerMenuCommand("重新加载配置", function() { config = Object.assign({}, defaultConfig, GM_getValue('config', {})); location.reload(); }); GM_registerMenuCommand("重置为默认配置", function() { config = defaultConfig; saveConfig(); location.reload(); }); })();