// ==UserScript== // @name 重庆移通学院评教助手 // @namespace http://tampermonkey.net/ // @version 2.1.2 // @description 重庆移通学院评教助手,更好的服务师生,节约彼此的时间。 // @author 1654538841@qq.com // @match https://http-10-252-6-31-80.vpn.cqytxy.edu.cn/jwglxt/xspjgl/xspj_cxXspjIndex.html* // @grant none // ==/UserScript== (function() { 'use strict'; // 创建控制面板 function createPanel() { if (document.getElementById('eval-panel')) return; const panel = document.createElement('div'); panel.id = 'eval-panel'; panel.style.cssText = ` position: fixed !important; top: 20px !important; right: 20px !important; background: #fff !important; border: 2px solid #007cba !important; border-radius: 8px !important; padding: 15px !important; box-shadow: 0 4px 12px rgba(0,0,0,0.2) !important; z-index: 999999 !important; font-family: Arial, sans-serif !important; width: 200px !important; `; panel.innerHTML = `
重庆移通学院评教助手

一键完成
就绪
`; document.body.appendChild(panel); // 绑定事件 document.getElementById('excellent-btn').onclick = () => setScore(90, 100); document.getElementById('good-btn').onclick = () => setScore(80, 100); document.getElementById('pass-btn').onclick = () => setScore(70, 100); document.getElementById('comment-btn').onclick = fillComment; // 一键完成功能 document.getElementById('auto-excellent-btn').onclick = () => autoComplete(90, 100); document.getElementById('auto-good-btn').onclick = () => autoComplete(80, 100); document.getElementById('auto-pass-btn').onclick = () => autoComplete(70, 100); } // 设置评分 function setScore(minScore, maxScore) { const status = document.getElementById('status'); status.innerHTML = '正在设置评分...'; console.log(`🎯 开始设置评分: ${minScore}-${maxScore}分`); // 查找评分选项 - 优先查找带有radio-pjf类的选项 let radios = document.querySelectorAll('input.radio-pjf[type="radio"][data-dyf]'); if (radios.length === 0) { radios = document.querySelectorAll('input[type="radio"][data-dyf]'); } if (radios.length === 0) { radios = document.querySelectorAll('div.radio-inline.input-xspj input[type="radio"]'); } console.log(`📊 找到 ${radios.length} 个评分选项`); if (radios.length === 0) { status.innerHTML = '未找到评分选项'; return; } // 按name分组 const groups = {}; radios.forEach((radio, index) => { const name = radio.getAttribute('name'); let score = parseInt(radio.getAttribute('data-dyf')); if (isNaN(score)) { score = parseInt(radio.value); } console.log(`选项${index + 1}: name=${name?.substring(0, 20)}..., score=${score}`); if (name && !isNaN(score)) { if (!groups[name]) groups[name] = []; // 确保创建正确的选项对象,使用深拷贝确保数据完整性 const optionObj = { element: radio, score: parseInt(score) // 确保是数字类型 }; groups[name].push(optionObj); // 调试:验证刚创建的对象 if (index < 3) { console.log(`✅ 创建选项对象: score=${optionObj.score}, typeof=${typeof optionObj.score}, element=${optionObj.element ? 'exists' : 'missing'}`); } } else { console.log(`❌ 跳过选项${index + 1}: name=${name}, score=${score}, isNaN=${isNaN(score)}`); } }); console.log(`📋 分组结果: ${Object.keys(groups).length} 个组`); let selectedCount = 0; const selectedScores = []; // 为每个组选择评分 Object.keys(groups).forEach((groupName, groupIndex) => { const group = groups[groupName]; const availableScores = group.map(item => item.score).sort((a, b) => b - a); console.log(`🔄 处理第${groupIndex + 1}组: 可用分数 [${availableScores.join(', ')}]`); let selectedOption = null; if (minScore === maxScore) { // 固定分数模式 console.log(`🔍 固定分数模式: 查找 ${minScore} 分`); selectedOption = group.find(option => option.score === minScore); if (!selectedOption) { // 选择最高分 group.sort((a, b) => b.score - a.score); selectedOption = group[0]; console.log(`⚠️ 未找到 ${minScore} 分,使用最高分 ${selectedOption.score}`); } } else { // 随机分数模式 console.log(`🎲 随机模式: 范围 ${minScore}-${maxScore} 分`); // 调试:显示组内选项的分数 const groupScores = group.map(option => option.score); console.log(`🔍 组内选项分数: [${groupScores.join(', ')}]`); // 调试:检查group中每个选项的结构 group.forEach((option, idx) => { console.log(`组内选项${idx}: score=${option.score}, element=${option.element ? 'exists' : 'missing'}, typeof score=${typeof option.score}, option类型=${typeof option}`); }); // 创建一个新的数组来避免引用问题 const rangeOptions = []; for (let i = 0; i < group.length; i++) { const option = group[i]; console.log(`处理选项${i}: option=${typeof option}, score=${option?.score}`); if (option && typeof option === 'object' && typeof option.score === 'number') { const score = option.score; const inRange = score >= minScore && score <= maxScore; console.log(`检查选项${i}: score=${score}, minScore=${minScore}, maxScore=${maxScore}, inRange=${inRange}`); if (inRange) { rangeOptions.push(option); } } else { console.log(`❌ 无效选项${i}: option类型=${typeof option}, score=${option?.score}`); } } console.log(`🎯 范围内找到 ${rangeOptions.length} 个选项: [${rangeOptions.map(o => o.score).join(', ')}]`); if (rangeOptions.length > 0) { const randomIndex = Math.floor(Math.random() * rangeOptions.length); selectedOption = rangeOptions[randomIndex]; console.log(`🎲 随机选择: 索引${randomIndex}, 分数${selectedOption.score}`); } else { group.sort((a, b) => b.score - a.score); selectedOption = group[0]; console.log(`⚠️ 范围内无选项,使用最高分: ${selectedOption.score}`); } } if (selectedOption) { // 清除该组所有选择 group.forEach(option => option.element.checked = false); // 选择目标选项 selectedOption.element.checked = true; selectedOption.element.dispatchEvent(new Event('change', {bubbles: true})); selectedOption.element.click(); selectedCount++; selectedScores.push(selectedOption.score); console.log(`✅ 第${groupIndex + 1}组已选择: ${selectedOption.score}分`); } }); const avgScore = selectedScores.length > 0 ? (selectedScores.reduce((a, b) => a + b, 0) / selectedScores.length).toFixed(1) : 0; status.innerHTML = `已设置${selectedCount}个评分项 (平均${avgScore}分)`; console.log(`✅ 评分设置完成: ${selectedCount}项, 平均分${avgScore}, 选择的分数: [${selectedScores.join(', ')}]`); } // 填写评语 function fillComment() { const status = document.getElementById('status'); status.innerHTML = '正在填写评语...'; // 查找所有评语文本框 let textareas = []; // 优先查找 name="py" 的文本框 const pyTextareas = document.querySelectorAll('textarea[name="py"]'); textareas.push(...pyTextareas); // 查找 id 包含 "_py" 的文本框 const idPyTextareas = document.querySelectorAll('textarea[id*="_py"]'); idPyTextareas.forEach(ta => { if (!textareas.includes(ta)) { textareas.push(ta); } }); // 查找 id 包含 "py" 的文本框 const idContainsPyTextareas = document.querySelectorAll('textarea[id*="py"]'); idContainsPyTextareas.forEach(ta => { if (!textareas.includes(ta)) { textareas.push(ta); } }); // 如果还是没找到,查找所有 textarea if (textareas.length === 0) { const allTextareas = document.querySelectorAll('textarea'); textareas.push(...allTextareas); } if (textareas.length === 0) { status.innerHTML = '未找到评语框'; return; } console.log(`📝 找到 ${textareas.length} 个评语框`); // 评语库 const comments = [ "老师讲课认真负责,教学内容丰富,授课方式灵活多样,能够很好地与学生互动,课堂氛围活跃。", "老师教学态度严谨认真,讲解清晰,重点突出,让我对课程内容有了更深入的理解。", "课程设计合理,老师教学经验丰富,能够深入浅出地讲解复杂概念,让学生容易理解和掌握。", "老师对待教学工作一丝不苟,备课充分,讲解透彻,能够关注每位学生的学习情况。", "老师教学风格亲切自然,能够激发学生的学习兴趣,课堂气氛轻松活跃。" ]; // 为每个评语框填写评语 let filledCount = 0; textareas.forEach((textarea, index) => { if (textarea.value.trim() === '') { // 只填写空的评语框 const selectedComment = comments[Math.floor(Math.random() * comments.length)]; textarea.value = selectedComment; textarea.dispatchEvent(new Event('input', {bubbles: true})); textarea.dispatchEvent(new Event('change', {bubbles: true})); filledCount++; console.log(`✅ 已填写第${index + 1}个评语框: ${textarea.id || textarea.name || 'unnamed'}`); } else { console.log(`⏭️ 跳过第${index + 1}个评语框(已有内容): ${textarea.id || textarea.name || 'unnamed'}`); } }); status.innerHTML = `已填写${filledCount}个评语框`; } // 一键完成功能(评分+评语) function autoComplete(minScore, maxScore) { const status = document.getElementById('status'); status.innerHTML = '正在一键完成...'; console.log(`🚀 开始一键完成: ${minScore}-${maxScore}分 + 评语`); // 先设置评分 setScore(minScore, maxScore); // 延迟填写评语,确保评分设置完成 setTimeout(() => { fillComment(); status.innerHTML = `一键完成 (${minScore}-${maxScore}分)`; console.log(`✅ 一键完成: 评分和评语已设置`); }, 500); } // 初始化插件 createPanel(); // 延迟创建面板(确保页面加载完成) setTimeout(createPanel, 1000); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', createPanel); } })();