您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
优化表单识别逻辑,支持更多表格结构类型 - 增强版本
// ==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); })();