// ==UserScript== // @name 半自动量化评教器(天津农学院教务系统专用) // @namespace http://tampermonkey.net/ // @version 1.0.0 // @description 天津农学院教务系统量化评教半自动选择工具,支持评分选择、文本输入和元素点击 // @author NephrenRuqInsania-1582160745@qq.com; // @match *://jwxt.tjau.edu.cn/eams/homeExt.action* // @grant none // // @tag 天农 // @tag 天津农学院 // @tag 教务系统 // @tag 量化评教 // ==/UserScript== // ==== 量化评教配置 ==== const VALUE_CONFIG = { targetValues: [0, 1, 2, 3, 4], // 支持的评分等级 defaultValue: 0, // 默认选择的评分等级 selector: 'input.option-radio', // 基础选择器 evaluationTitle: '天津农学院量化评教系统', // 评教系统标题 evaluationDescription: '请根据教学质量选择相应评分等级', // 评教说明 defaultText: '无', // 默认文本内容 panelOpacity: 0.5, // 面板透明度 submitButtonId: 'sub' // 评教页内的提交按钮`input`元素的ID }; // ==== 评分等级按钮颜色 ==== function getButtonColor(value) { const colors = { 0: '#4CAF50', // 5分 - 绿色 1: '#8BC34A', // 4分 - 浅绿 2: '#FFC107', // 3分 - 黄色 3: '#FF9800', // 2分 - 橙色 4: '#F44336' // 1分 - 红色 }; return colors[value] || '#607D8B'; } // ==== CSS样式配置 ==== const CSS_CONFIG = { notificationCss: ` position: fixed; top: 20px; right: 20px; background: #4CAF50; color: white; padding: 15px 20px; border-radius: 5px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 10000; font-family: Arial, sans-serif; font-size: 14px; max-width: 350px; opacity: 0; transform: translateY(-10px); transition: opacity 0.3s, transform 0.3s; pointer-events: none; `, panelCss: ` position: fixed; bottom: 20px; right: 20px; background: rgba(51, 122, 183, ${VALUE_CONFIG.panelOpacity}); border-radius: 12px; padding: 15px; box-shadow: 0 4px 12px rgba(0,0,0,0.2); z-index: 10000; min-width: 200px; font-family: Arial, sans-serif; backdrop-filter: blur(5px); `, titleCss: ` color: white; font-weight: bold; text-align: center; margin-bottom: 10px; font-size: 16px; padding-bottom: 8px; border-bottom: 1px solid rgba(255,255,255,0.3); `, scoreTitleCss: ` color: rgba(255,255,255,0.8); font-size: 12px; margin-bottom: 8px; text-align: center; `, bottonsContainerCss: ` display: flex; flex-direction: column; gap: 8px; `, textTitleCss: ` color: rgba(255,255,255,0.8); font-size: 12px; margin-bottom: 8px; text-align: center; `, textInputCss: ` width: 100%; height: 50px; padding: 8px; border-radius: 4px; border: 1px solid #ccc; margin-bottom: 8px; resize: vertical; font-family: Arial, sans-serif; font-size: 12px; `, buttonCss(value) { return ` background: ${getButtonColor(value)}; color: white; border: none; border-radius: 6px; padding: 8px 12px; font-size: 12px; font-weight: bold; cursor: pointer; transition: all 0.3s; width: 100%; text-align: center; `}, fillButtonCss: ` background: #607D8B; color: white; border: none; border-radius: 6px; padding: 8px 12px; font-size: 12px; font-weight: bold; cursor: pointer; transition: all 0.3s; width: 100%; text-align: center; `, elementTitleCss: ` color: rgba(255,255,255,0.8); font-size: 12px; margin-bottom: 8px; text-align: center; `, clickInputButtonCss: ` background: #9C27B0; color: white; border: none; border-radius: 6px; padding: 8px 12px; font-size: 12px; font-weight: bold; cursor: pointer; transition: all 0.3s; width: 100%; text-align: center; `, }; // ==== 反向评分映射 ==== function mappingIdValueToScore(idValue) { const scoreMap = { 0: 5, 1: 4, 2: 3, 3: 2, 4: 1 }; return scoreMap[idValue] || 0; } (function() { 'use strict'; // ==== 评教页面元素查找 ==== function findTargetIframe() { const iframePaths = [ 'iframe#iframeMain', 'iframe.evaluation-frame', 'div.evaluation-container iframe', 'div#main-content iframe' ]; for (let path of iframePaths) { const iframe = document.querySelector(path); if (iframe) return iframe; } return document.querySelectorAll('iframe')[0] || null; } // ==== 主功能:自动选择指定评分的选项 ==== function autoSelectOptions(targetValue = VALUE_CONFIG.defaultValue) { const displayScore = mappingIdValueToScore(targetValue); console.log(`开始自动选择评分等级=${targetValue}(显示为${displayScore}分)的选项...`); // 查找iframe元素 const iframe = findTargetIframe(); if (!iframe) { console.log('未找到评教iframe'); showNotification('未找到评教页面,请检查是否在评教界面'); return; } try { // 获取iframe内的评教文档 const iframeDoc = getIframeDocument(iframe); if (!iframeDoc) { console.log('无法访问评教内容'); showNotification('无法访问评教内容,可能是跨域限制'); return; } // 在评教页面内部查找目标选项 const selector = `${VALUE_CONFIG.selector}[value="${targetValue}"]`; const targetOptions = iframeDoc.querySelectorAll(selector); if (targetOptions.length === 0) { console.log(`评教页面内未找到评分等级为${targetValue}的选项`); showNotification(`未找到评分等级${displayScore}分的选项`); return; } // 选择所有找到的评分选项 let selectedCount = 0; targetOptions.forEach(option => { if (option.offsetParent !== null && !option.disabled) { option.checked = true; option.dispatchEvent(new Event('change', { bubbles: true })); option.dispatchEvent(new Event('click', { bubbles: true })); selectedCount++; } }); console.log(`已自动选择 ${selectedCount} 个评分等级=${targetValue}(显示为${displayScore}分)的选项`); showNotification(`已选择 ${selectedCount} 个${displayScore}分选项`); } catch (error) { console.error('处理评教内容时出错:', error); showNotification('评教处理出错: ' + error.message); } } // ==== 文本输入功能 ==== function fillTextAreas() { const customText = document.getElementById('customTextInput').value; if (!customText) { showNotification('请输入要填充的文本内容'); return; } const iframe = findTargetIframe(); if (!iframe) { showNotification('未找到评教页面'); return; } try { const iframeDoc = getIframeDocument(iframe); if (!iframeDoc) { showNotification('无法访问评教内容'); return; } const textAreas = iframeDoc.querySelectorAll('textarea.answer.answer-textarea'); if (textAreas.length === 0) { showNotification('未找到需要填写的文本框'); return; } let filledCount = 0; textAreas.forEach(textarea => { if (textarea.offsetParent !== null && !textarea.disabled) { textarea.value = customText; textarea.dispatchEvent(new Event('input', { bubbles: true })); textarea.dispatchEvent(new Event('change', { bubbles: true })); filledCount++; } }); showNotification(`已填充 ${filledCount} 个文本框`); } catch (error) { console.error('填充文本框时出错:', error); showNotification('填充文本框出错: ' + error.message); } } // ==== 获取并点击指定提交按钮 ==== function clickTargetInput() { const iframe = findTargetIframe(); if (!iframe) { showNotification('未找到评教页面'); return; } try { const iframeDoc = getIframeDocument(iframe); if (!iframeDoc) { showNotification('无法访问评教内容'); return; } const targetInput = iframeDoc.getElementById(VALUE_CONFIG.submitButtonId); if (!targetInput) { showNotification(`未找到ID为${VALUE_CONFIG.submitButtonId}的input元素`); return; } console.log('找到目标input元素:', targetInput); // 检查元素是否可见和可点击 if (targetInput.offsetParent === null || targetInput.disabled) { showNotification(`找到的input元素不可点击`); return; } // 创建并触发鼠标点击事件 const clickEvent = new MouseEvent('click', { view: window, bubbles: true, cancelable: true }); targetInput.dispatchEvent(clickEvent); showNotification(`已触发ID为${VALUE_CONFIG.submitButtonId}的input点击事件`); } catch (error) { console.error('处理input元素时出错:', error); showNotification('处理input元素出错: ' + error.message); } } // ==== 安全获取评教内容 ==== function getIframeDocument(iframe) { try { return iframe.contentDocument || iframe.contentWindow?.document || iframe.document; } catch (error) { console.error('无法访问评教iframe文档:', error); return null; } } // ==== 评教操作通知 ==== function showNotification(message) { const existingNotification = document.getElementById('evaluationNotification'); if (existingNotification) { existingNotification.remove(); } const notification = document.createElement('div'); notification.id = 'evaluationNotification'; notification.style.cssText = CSS_CONFIG.textInputCss; notification.innerHTML = ` ${VALUE_CONFIG.evaluationTitle}
${message} `; document.body.appendChild(notification); // 显示通知 setTimeout(() => { notification.style.opacity = '1'; notification.style.transform = 'translateY(0)'; }, 10); // 自动淡出并移除 setTimeout(() => { notification.style.opacity = '0'; notification.style.transform = 'translateY(-10px)'; setTimeout(() => { if (notification.parentNode) { notification.remove(); } }, 300); }, 3000); } // ==== 创建评教控制面板 ==== function createEvaluationPanel() { const existingPanel = document.getElementById('evaluationControlPanel'); if (existingPanel) { existingPanel.remove(); } const panel = document.createElement('div'); panel.id = 'evaluationControlPanel'; panel.style.cssText = CSS_CONFIG.panelCss; // 评教面板标题 const title = document.createElement('div'); title.textContent = VALUE_CONFIG.evaluationTitle; title.style.cssText = CSS_CONFIG.titleCss; panel.appendChild(title); // 评分选择部分 const scoreSection = document.createElement('div'); scoreSection.style.marginBottom = '15px'; const scoreTitle = document.createElement('div'); scoreTitle.textContent = '评分选择 (5分最高)'; scoreTitle.style.cssText = CSS_CONFIG.scoreTitleCss; scoreSection.appendChild(scoreTitle); // 评分等级按钮容器 const buttonsContainer = document.createElement('div'); buttonsContainer.style.cssText = CSS_CONFIG.bottonsContainerCss; // 创建每个评分等级的按钮 VALUE_CONFIG.targetValues.forEach(value => { const displayScore = mappingIdValueToScore(value); const button = document.createElement('button'); button.textContent = `选择 ${displayScore} 分`; button.title = `选择所有评分等级为 ${displayScore} 分的选项`; button.style.cssText = CSS_CONFIG.buttonCss(value); // 按钮交互效果 button.addEventListener('mouseenter', function() { this.style.transform = 'translateY(-1px)'; this.style.boxShadow = '0 2px 8px rgba(0,0,0,0.3)'; this.style.filter = 'brightness(1.1)'; }); button.addEventListener('mouseleave', function() { this.style.transform = 'translateY(0)'; this.style.boxShadow = 'none'; this.style.filter = 'brightness(1)'; }); button.addEventListener('click', () => autoSelectOptions(value)); buttonsContainer.appendChild(button); }); scoreSection.appendChild(buttonsContainer); panel.appendChild(scoreSection); // 文本输入部分 const textSection = document.createElement('div'); const textTitle = document.createElement('div'); textTitle.textContent = '文本输入'; textTitle.style.cssText = CSS_CONFIG.textTitleCss; textSection.appendChild(textTitle); // 创建文本输入框 const textInput = document.createElement('textarea'); textInput.id = 'customTextInput'; textInput.value = VALUE_CONFIG.defaultText; textInput.placeholder = '输入要填充的文本内容...'; textInput.style.cssText = CSS_CONFIG.textInputCss; textSection.appendChild(textInput); // 创建填充按钮 const fillButton = document.createElement('button'); fillButton.textContent = '填充所有文本框'; fillButton.style.cssText = CSS_CONFIG.fillButtonCss; fillButton.addEventListener('mouseenter', function() { this.style.transform = 'translateY(-1px)'; this.style.boxShadow = '0 2px 8px rgba(0,0,0,0.3)'; this.style.filter = 'brightness(1.1)'; }); fillButton.addEventListener('mouseleave', function() { this.style.transform = 'translateY(0)'; this.style.boxShadow = 'none'; this.style.filter = 'brightness(1)'; }); fillButton.addEventListener('click', fillTextAreas); textSection.appendChild(fillButton); panel.appendChild(textSection); // 元素获取部分 const elementSection = document.createElement('div'); elementSection.style.marginTop = '15px'; const elementTitle = document.createElement('div'); elementTitle.textContent = '元素操作'; elementTitle.style.cssText = CSS_CONFIG.elementTitleCss; elementSection.appendChild(elementTitle); // 创建点击input按钮 const clickInputButton = document.createElement('button'); clickInputButton.textContent = `点击提交`; clickInputButton.style.cssText = CSS_CONFIG.clickInputButtonCss; clickInputButton.addEventListener('mouseenter', function() { this.style.transform = 'translateY(-1px)'; this.style.boxShadow = '0 2px 8px rgba(0,0,0,0.3)'; this.style.filter = 'brightness(1.1)'; }); clickInputButton.addEventListener('mouseleave', function() { this.style.transform = 'translateY(0)'; this.style.boxShadow = 'none'; this.style.filter = 'brightness(1)'; }); clickInputButton.addEventListener('click', clickTargetInput); elementSection.appendChild(clickInputButton); panel.appendChild(elementSection); document.body.appendChild(panel); } // ==== 初始化评教工具 ==== function initEvaluationTool() { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function() { setTimeout(createEvaluationPanel, 1000); }); } else { setTimeout(createEvaluationPanel, 1000); } } // ==== 启动量化评教工具 ==== initEvaluationTool(); })();