// ==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);
}
})();