// ==UserScript==
// @name 上海第二工业大学教师评教自动填写(优化版)
// @license All rights reserved
// @namespace http://tampermonkey.net/
// @version 4.0-Enhanced
// @description 优化表单识别逻辑,支持更多表格结构类型 - 增强版本
// @author Assistant
// @match https://jx.sspu.edu.cn/eams/evaluateStd*
// @match https://jx.sspu.edu.cn/eams/*
// @include https://jx.sspu.edu.cn/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// 智能选项识别配置
const BEST_OPTIONS = {
// 最佳选项关键词(按优先级排序)
positive: [
'非常符合', '完全符合', '非常同意', '完全同意', '非常满意', '完全满意',
'非常愿意', '完全愿意', '非常好', '优秀', '很好', '满意',
'比较符合', '比较同意', '比较满意', '比较愿意', '愿意', '好'
],
// 需要避免的选项关键词
negative: [
'非常不符合', '完全不符合', '非常不同意', '完全不同意', '非常不满意',
'非常不愿意', '完全不愿意', '很差', '差', '不满意', '不愿意',
'比较不符合', '比较不同意', '比较不满意', '不确定', '一般'
]
};
// 等待页面加载完成
window.addEventListener('load', function() {
setTimeout(() => {
addAutoFillButton();
}, 2000);
});
function addAutoFillButton() {
// 避免重复添加按钮
if (document.getElementById('auto-fill-btn')) {
return;
}
const button = document.createElement('button');
button.id = 'auto-fill-btn';
button.innerHTML = '🤖 智能评教';
button.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
z-index: 99999;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 15px 25px;
border-radius: 30px;
cursor: pointer;
font-size: 16px;
font-weight: bold;
box-shadow: 0 8px 32px rgba(102, 126, 234, 0.3);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
backdrop-filter: blur(10px);
`;
// 添加悬停效果
button.addEventListener('mouseenter', () => {
button.style.transform = 'translateY(-3px) scale(1.05)';
button.style.boxShadow = '0 12px 40px rgba(102, 126, 234, 0.4)';
});
button.addEventListener('mouseleave', () => {
button.style.transform = 'translateY(0) scale(1)';
button.style.boxShadow = '0 8px 32px rgba(102, 126, 234, 0.3)';
});
button.onclick = intelligentAutoFill;
document.body.appendChild(button);
}
function intelligentAutoFill() {
console.log('🤖 启动智能评教填写...');
// 显示加载提示
showLoadingToast();
setTimeout(() => {
const result = performIntelligentFill();
hideLoadingToast();
showResult(result);
}, 500);
}
function performIntelligentFill() {
// 增强版查找所有单选按钮组
const radioGroups = findAllRadioGroupsEnhanced();
console.log(`📊 找到 ${Object.keys(radioGroups).length} 个问题组`);
// 打印调试信息
for (let [groupName, radios] of Object.entries(radioGroups)) {
console.log(`🔍 问题组 ${groupName}:`);
radios.forEach((option, index) => {
console.log(` ${index + 1}. "${option.text}" (value: ${option.value})`);
});
}
let successCount = 0;
let totalGroups = Object.keys(radioGroups).length;
let analysisLog = [];
for (let [groupName, radios] of Object.entries(radioGroups)) {
const bestOption = findBestOptionEnhanced(radios);
if (bestOption) {
bestOption.radio.checked = true;
// 触发多种事件确保兼容性
['change', 'click', 'input'].forEach(eventType => {
const event = new Event(eventType, { bubbles: true });
bestOption.radio.dispatchEvent(event);
});
successCount++;
analysisLog.push({
group: groupName,
selected: bestOption.text,
reason: bestOption.reason
});
console.log(`✅ ${groupName}: 选择 "${bestOption.text}" (${bestOption.reason})`);
} else {
console.log(`❌ ${groupName}: 未找到合适选项`);
analysisLog.push({
group: groupName,
selected: '未选择',
reason: '未找到合适选项'
});
}
}
return {
success: successCount,
total: totalGroups,
log: analysisLog
};
}
function findAllRadioGroupsEnhanced() {
const radioGroups = {};
const allRadios = document.querySelectorAll('input[type="radio"]');
console.log(`🔍 页面中找到 ${allRadios.length} 个单选按钮`);
allRadios.forEach((radio, index) => {
const name = radio.name;
if (name) {
if (!radioGroups[name]) {
radioGroups[name] = [];
}
// 增强版选项文本识别
let labelText = getRadioLabelTextEnhanced(radio);
// 清理文本,移除多余的空白字符和
labelText = labelText.replace(/ /g, ' ').replace(/\s+/g, ' ').trim();
console.log(`📝 单选按钮 ${index + 1}: name="${name}", value="${radio.value}", text="${labelText}"`);
radioGroups[name].push({
radio: radio,
text: labelText,
value: radio.value
});
}
});
return radioGroups;
}
function getRadioLabelTextEnhanced(radio) {
let labelText = '';
// 方法1: 通过for属性查找对应的label
if (radio.id) {
const label = document.querySelector(`label[for="${radio.id}"]`);
if (label) {
labelText = label.textContent.trim();
console.log(`🏷️ 方法1找到标签: "${labelText}"`);
return labelText;
}
}
// 方法2: 查找紧邻的label元素
const nextLabel = radio.nextElementSibling;
if (nextLabel && nextLabel.tagName === 'LABEL') {
labelText = nextLabel.textContent.trim();
console.log(`🏷️ 方法2找到标签: "${labelText}"`);
return labelText;
}
// 方法3: 查找前一个label元素
const prevLabel = radio.previousElementSibling;
if (prevLabel && prevLabel.tagName === 'LABEL') {
labelText = prevLabel.textContent.trim();
console.log(`🏷️ 方法3找到标签: "${labelText}"`);
return labelText;
}
// 方法4: 从父元素中查找包含该radio的label
let parent = radio.parentElement;
while (parent && parent.tagName !== 'BODY') {
const labels = parent.querySelectorAll('label');
for (let label of labels) {
if (label.getAttribute('for') === radio.id || label.contains(radio)) {
labelText = label.textContent.trim();
console.log(`🏷️ 方法4找到标签: "${labelText}"`);
return labelText;
}
}
parent = parent.parentElement;
}
// 方法5: 从父元素的文本内容中提取(针对表格结构)
const parentTd = radio.closest('td');
if (parentTd) {
// 创建临时元素来分析HTML结构
const tempDiv = document.createElement('div');
tempDiv.innerHTML = parentTd.innerHTML;
// 移除所有input元素,只保留label文本
const inputs = tempDiv.querySelectorAll('input');
inputs.forEach(input => input.remove());
// 查找与当前radio相关的label
const labels = tempDiv.querySelectorAll('label');
for (let label of labels) {
if (label.getAttribute('for') === radio.id) {
labelText = label.textContent.trim();
console.log(`🏷️ 方法5找到标签: "${labelText}"`);
return labelText;
}
}
}
// 方法6: 根据value推断文本(最后的备用方案)
if (!labelText && radio.value) {
// 常见的评价选项映射
const valueTextMap = {
'174': '非常符合',
'173': '比较符合',
'172': '不确定',
'171': '比较不符合',
'170': '非常不符合',
'169': '非常同意',
'168': '比较同意',
'167': '不确定',
'166': '比较不同意',
'165': '非常不同意',
'179': '非常愿意',
'178': '愿意',
'177': '一般',
'176': '不愿意',
'175': '非常不愿意'
};
labelText = valueTextMap[radio.value] || `选项${radio.value}`;
console.log(`🏷️ 方法6推断标签: "${labelText}"`);
}
return labelText;
}
function findBestOptionEnhanced(options) {
console.log(`🎯 分析选项组,共 ${options.length} 个选项`);
// 按优先级查找最佳选项
for (let keyword of BEST_OPTIONS.positive) {
for (let option of options) {
if (option.text.includes(keyword)) {
console.log(`✨ 找到最佳选项: "${option.text}" (关键词: ${keyword})`);
return {
radio: option.radio,
text: option.text,
reason: `匹配关键词: ${keyword}`
};
}
}
}
// 如果没有找到明确的正面选项,尝试数值分析
const numericOptions = options.filter(opt => /^\d+$/.test(opt.value));
if (numericOptions.length > 0) {
// 选择数值最大的选项(通常最高分是最好的)
const maxValueOption = numericOptions.reduce((max, current) =>
parseInt(current.value) > parseInt(max.value) ? current : max
);
console.log(`🔢 选择最高数值选项: "${maxValueOption.text}" (值: ${maxValueOption.value})`);
return {
radio: maxValueOption.radio,
text: maxValueOption.text,
reason: `选择最高数值选项 (${maxValueOption.value})`
};
}
// 位置分析:通常第一个选项是最好的
if (options.length > 0) {
const firstOption = options[0];
// 确保不是明显的负面选项
const isNegative = BEST_OPTIONS.negative.some(neg =>
firstOption.text.includes(neg)
);
if (!isNegative) {
console.log(`📍 选择第一个选项: "${firstOption.text}"`);
return {
radio: firstOption.radio,
text: firstOption.text,
reason: '选择第一个选项(通常为最佳)'
};
}
}
console.log(`❌ 未找到合适的选项`);
return null;
}
function showLoadingToast() {
const toast = document.createElement('div');
toast.id = 'loading-toast';
toast.innerHTML = `
<div style="display: flex; align-items: center; gap: 10px;">
<div class="spinner"></div>
<span>智能分析中...</span>
</div>
`;
toast.style.cssText = `
position: fixed;
top: 80px;
right: 20px;
z-index: 99998;
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 15px 20px;
border-radius: 10px;
font-size: 14px;
backdrop-filter: blur(10px);
`;
// 添加旋转动画样式
const style = document.createElement('style');
style.textContent = `
.spinner {
width: 20px;
height: 20px;
border: 2px solid #ffffff30;
border-top: 2px solid #ffffff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
`;
document.head.appendChild(style);
document.body.appendChild(toast);
}
function hideLoadingToast() {
const toast = document.getElementById('loading-toast');
if (toast) {
toast.remove();
}
}
function showResult(result) {
const { success, total, log } = result;
let message = `🎉 智能评教完成!\n\n`;
message += `📊 填写统计: ${success}/${total} 个问题\n`;
message += `✅ 成功率: ${total > 0 ? Math.round(success/total*100) : 0}%\n\n`;
if (success > 0) {
message += `🔍 智能分析结果:\n`;
const successLog = log.filter(item => item.selected !== '未选择');
const samples = successLog.slice(0, 3); // 显示前3个样例
samples.forEach((item, index) => {
message += `${index + 1}. ${item.selected} (${item.reason})\n`;
});
if (successLog.length > 3) {
message += `... 还有 ${successLog.length - 3} 个问题已智能填写\n`;
}
message += `\n💡 提示: 请检查填写结果后再提交`;
} else {
message += `❌ 未找到可识别的评教表单\n`;
message += `🔧 调试信息:\n`;
message += `- 页面中单选按钮总数: ${document.querySelectorAll('input[type="radio"]').length}\n`;
message += `- 建议: 请确保页面完全加载后再使用脚本\n`;
message += `- 如果问题持续,请联系开发者更新脚本`;
}
alert(message);
// 滚动到页面底部
if (success > 0) {
setTimeout(() => {
window.scrollTo({
top: document.body.scrollHeight,
behavior: 'smooth'
});
}, 1000);
}
}
// 增强版页面变化监听
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type === 'childList') {
const hasRadios = document.querySelector('input[type="radio"]');
if (hasRadios && !document.getElementById('auto-fill-btn')) {
console.log('🔄 检测到新的单选按钮,准备添加自动填写按钮');
setTimeout(addAutoFillButton, 1000);
}
}
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
console.log('🤖 上海第二工业大学增强版评教脚本已加载');
console.log('📝 当前页面单选按钮数量:', document.querySelectorAll('input[type="radio"]').length);
})();