您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
集成抢课功能与教学评估功能,一体化教务助手
// ==UserScript== // @name 齐大教务系统全能助手 // @namespace https://greasyforks.org/users/737539 // @version 2.2.2 // @description 集成抢课功能与教学评估功能,一体化教务助手 // @author 忘忧 // @icon https://xyh.qqhru.edu.cn/favicon.ico // @license MIT // @match http://111.43.36.164/student/courseSelect/courseSelect/* // @match http://111.43.36.164/student/teachingEvaluation/evaluation/* // @match http://172.20.139.153:7700/student/teachingEvaluation/evaluation/* // @match http://172.20.139.153:7700/student/courseSelect/courseSelect/* // @match https://172-20-139-153-7700.webvpn.qqhru.edu.cn/student/teachingEvaluation/evaluation/* // @match https://172-20-139-153-7700.webvpn.qqhru.edu.cn/student/courseSelect/courseSelect/* // @grant none // ==/UserScript== (function () { 'use strict'; /** * 齐大教务助手主模块 * 模块化结构,将不同功能划分为独立模块 */ const EducationHelper = { // 系统配置 Config: { // 全局状态 state: { targetCourses: [], matchedCourses: [], timer: null, autoMode: false, autoClickEvaluationEnabled: false, selectedOption: "A", autoSubmitEnabled: true, debugMode: false, uiFollowPage: true, }, // 页面类型 pageType: { currentPageUrl: window.location.href, isCoursePage: false, isEvaluationPage: false, isEvaluationListPage: false }, // 时间设置 timers: { autoClickEvaluationDelay: 10000, // 延迟10秒执行自动点击 autoSubmitDelay: 120000, // 自动提交延迟,默认2分钟 }, // 内容设置 content: { evaluationComment: "上课有热情,积极解决学生问题,很好的老师!!", // 默认评价内容 }, // 初始化配置 init: function() { // 检测页面类型 this.pageType.isCoursePage = this.pageType.currentPageUrl.includes('courseSelect'); this.pageType.isEvaluationPage = this.pageType.currentPageUrl.includes('teachingEvaluation/evaluationPage'); this.pageType.isEvaluationListPage = this.pageType.currentPageUrl.includes('teachingEvaluation/teachingEvaluation/index') || this.pageType.currentPageUrl.includes('teachingEvaluation/evaluation/index'); // 从localStorage读取持久化设置 this.loadSavedSettings(); return this; }, // 保存设置到localStorage saveSettings: function() { try { localStorage.setItem('autoMode', this.state.autoMode.toString()); localStorage.setItem('evaluationComment', this.content.evaluationComment); localStorage.setItem('selectedOption', this.state.selectedOption); console.log('[设置] 已保存设置到localStorage'); } catch (e) { console.warn("[警告] 保存设置到localStorage失败:", e); } }, // 从localStorage加载设置 loadSavedSettings: function() { try { const storedAutoMode = localStorage.getItem('autoMode'); if (storedAutoMode === 'true') { this.state.autoMode = true; console.log('[检测] 从localStorage检测到全自动模式已启用'); } const storedComment = localStorage.getItem('evaluationComment'); if (storedComment) { this.content.evaluationComment = storedComment; } const storedOption = localStorage.getItem('selectedOption'); if (storedOption) { this.state.selectedOption = storedOption; } } catch (e) { console.warn("[警告] 读取localStorage失败:", e); } } }, // 日志模块 Logger: { // 调试日志 debug: function(message, data) { if (EducationHelper.Config.state.debugMode) { console.log(`[调试] ${message}`, data || ''); const debugContent = document.getElementById('debugContent'); if (debugContent) { const logItem = document.createElement('div'); logItem.style.borderBottom = '1px dashed #eee'; logItem.style.paddingBottom = '3px'; logItem.style.marginBottom = '3px'; let logText = message; if (data) { if (typeof data === 'object') { try { logText += ` ${JSON.stringify(data)}`; } catch (e) { logText += ` [复杂对象]`; } } else { logText += ` ${data}`; } } logItem.textContent = logText; debugContent.appendChild(logItem); debugContent.scrollTop = debugContent.scrollHeight; // 自动滚动到底部 } } }, // 信息日志 info: function(message) { console.log(`[信息] ${message}`); }, // 操作日志 action: function(message) { console.log(`[操作] ${message}`); }, // 成功日志 success: function(message) { console.log(`[成功] ${message}`); }, // 警告日志 warn: function(message) { console.warn(`[警告] ${message}`); }, // 错误日志 error: function(message, error) { if (error) { console.error(`[错误] ${message}`, error); } else { console.error(`[错误] ${message}`); } } }, // UI模块 UI: { // UI元素 elements: { container: null, dragBar: null, content: null, }, // UI样式 styles: { // 将在初始化时添加 cssRules: ` .ui-button { background: linear-gradient(135deg, #1e88e5, #0d47a1); color: white; border: none; padding: 10px; cursor: pointer; width: 100%; margin-bottom: 10px; border-radius: 4px; transition: all 0.3s; font-weight: bold; } .ui-button:hover { background: linear-gradient(135deg, #0d47a1, #1565c0); transform: translateY(-2px); box-shadow: 0 2px 5px rgba(0,0,0,0.2); } .ui-button:active { transform: scale(0.98); } .ui-button:disabled { background: #cccccc; cursor: not-allowed; transform: none; box-shadow: none; } .ui-input { width: 100%; padding: 8px; margin-bottom: 10px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; } .ui-label { display: block; margin-bottom: 5px; font-weight: bold; color: #333; } .ui-panel { border: 1px solid #ddd; border-radius: 4px; padding: 10px; margin-bottom: 10px; background-color: white; max-height: 120px; overflow-y: auto; } .ui-panel-title { font-weight: bold; margin-bottom: 5px; color: #0d47a1; } .ui-tabs { display: flex; margin-bottom: 10px; border-bottom: 1px solid #ddd; } .ui-tab { padding: 8px 15px; cursor: pointer; background-color: #f5f5f5; border: 1px solid #ddd; border-bottom: none; border-radius: 4px 4px 0 0; margin-right: 5px; } .ui-tab.active { background-color: white; border-bottom: 1px solid white; margin-bottom: -1px; font-weight: bold; } .ui-tab-content { display: none; } .ui-tab-content.active { display: block; } .delete-btn { background-color: #f44336; color: white; border: none; border-radius: 3px; cursor: pointer; padding: 2px 5px; } .delete-btn:hover { background-color: #d32f2f; } .course-item { display: flex; justify-content: space-between; padding: 3px 0; border-bottom: 1px solid #eee; } .course-item:last-child { border-bottom: none; } .ui-checkbox-container { display: flex; align-items: center; margin-bottom: 10px; } .ui-checkbox { margin-right: 8px; } .option-container { margin-bottom: 10px; } .option-row { margin-bottom: 5px; } .radio-label { display: flex; align-items: center; cursor: pointer; } .radio-label input { margin-right: 8px; } .timer-display { background-color: #e3f2fd; padding: 5px 10px; border-radius: 4px; text-align: center; margin-bottom: 10px; font-weight: bold; display: none; } `, // 添加CSS样式到页面 addStyles: function() { const style = document.createElement('style'); style.innerHTML = this.cssRules; document.head.appendChild(style); } }, // 创建UI界面 create: function() { EducationHelper.Logger.action('正在创建UI...'); // 添加样式 this.styles.addStyles(); // 创建主容器 this.elements.container = document.createElement('div'); this.elements.container.id = 'qqhruHelperUI'; this.elements.container.style.position = EducationHelper.Config.state.uiFollowPage ? 'fixed' : 'absolute'; this.elements.container.style.top = '10px'; this.elements.container.style.right = '10px'; this.elements.container.style.width = '300px'; this.elements.container.style.backgroundColor = '#f4f4f4'; this.elements.container.style.border = '1px solid #ccc'; this.elements.container.style.padding = '0'; this.elements.container.style.zIndex = '9999'; this.elements.container.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)'; this.elements.container.style.borderRadius = '5px'; this.elements.container.style.fontFamily = 'Arial, sans-serif'; // 标题和内容区域HTML this.elements.container.innerHTML = ` <div id="dragBar" style="background: linear-gradient(135deg, #1e88e5, #0d47a1); color: white; padding: 10px; text-align: center; cursor: grab; border-radius: 5px 5px 0 0; font-weight: bold; display: flex; justify-content: space-between; align-items: center;"> <span>齐大教务助手</span> <div> <button id="minimizeBtn" style="background: none; border: none; color: white; cursor: pointer; font-size: 16px; margin-right: 5px;">−</button> <button id="closeBtn" style="background: none; border: none; color: white; cursor: pointer; font-size: 16px;">×</button> </div> </div> <div id="uiContent" style="padding: 15px;"> <!-- 内容将根据页面类型动态生成 --> </div> `; document.body.appendChild(this.elements.container); // 保存元素引用 this.elements.dragBar = document.getElementById('dragBar'); this.elements.content = document.getElementById('uiContent'); // 根据页面类型生成内容 this.generateContent(); // 实现拖动功能 this.makeDraggable(); // 添加按钮事件 document.getElementById('minimizeBtn').addEventListener('click', this.toggleMinimize.bind(this)); document.getElementById('closeBtn').addEventListener('click', () => { this.elements.container.style.display = 'none'; }); EducationHelper.Logger.success('UI创建完成'); return this; }, // 根据页面类型生成内容 generateContent: function() { // 将在后续实现 EducationHelper.Logger.action('生成页面内容'); }, // 使UI可拖动 makeDraggable: function() { let offsetX = 0; let offsetY = 0; let isDragging = false; this.elements.dragBar.addEventListener('mousedown', (e) => { isDragging = true; offsetX = e.clientX - this.elements.container.getBoundingClientRect().left; offsetY = e.clientY - this.elements.container.getBoundingClientRect().top; this.elements.dragBar.style.cursor = 'grabbing'; document.body.style.userSelect = 'none'; }); document.addEventListener('mousemove', (e) => { if (isDragging) { let newX = e.clientX - offsetX; let newY = e.clientY - offsetY; // 限制UI在页面内 const maxX = window.innerWidth - this.elements.container.offsetWidth; const maxY = window.innerHeight - this.elements.container.offsetHeight; if (newX < 0) newX = 0; if (newY < 0) newY = 0; if (newX > maxX) newX = maxX; if (newY > maxY) newY = maxY; this.elements.container.style.left = `${newX}px`; this.elements.container.style.top = `${newY}px`; } }); document.addEventListener('mouseup', () => { isDragging = false; this.elements.dragBar.style.cursor = 'grab'; document.body.style.userSelect = ''; }); }, // 切换最小化状态 toggleMinimize: function() { if (this.elements.content.style.display === 'none') { this.elements.content.style.display = 'block'; document.getElementById('minimizeBtn').textContent = '−'; } else { this.elements.content.style.display = 'none'; document.getElementById('minimizeBtn').textContent = '+'; } }, // 显示状态消息 showMessage: function(message, type = 'info', duration = 3000) { const msgElement = document.createElement('div'); msgElement.style = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 15px 20px; border-radius: 8px; z-index: 10000; text-align: center; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3); color: white; font-weight: bold; `; // 根据类型设置样式 switch(type) { case 'success': msgElement.style.background = 'rgba(76, 175, 80, 0.9)'; break; case 'error': msgElement.style.background = 'rgba(244, 67, 54, 0.9)'; break; case 'warning': msgElement.style.background = 'rgba(255, 152, 0, 0.9)'; break; default: msgElement.style.background = 'rgba(33, 150, 243, 0.9)'; } msgElement.innerHTML = message; document.body.appendChild(msgElement); setTimeout(() => { if (msgElement && document.contains(msgElement)) { msgElement.remove(); } }, duration); return msgElement; } }, /** * 其他模块将在后续添加 */ // 抢课模块 CourseGrabber: { // 课程列表操作 courseList: { // 添加课程 add: function(courseCode) { if (!courseCode) return false; const courses = courseCode.split('\n').map(code => code.trim()); courses.forEach(course => { if (course && !EducationHelper.Config.state.targetCourses.includes(course)) { EducationHelper.Config.state.targetCourses.push(course); } }); this.updateUI(); EducationHelper.Logger.success(`已添加课程: ${courses.join(', ')}`); return true; }, // 移除课程 remove: function(index) { if (index >= 0 && index < EducationHelper.Config.state.targetCourses.length) { const removedCourse = EducationHelper.Config.state.targetCourses.splice(index, 1)[0]; this.updateUI(); EducationHelper.Logger.success(`已移除课程: ${removedCourse}`); return true; } return false; }, // 更新课程列表UI updateUI: function() { const courseListDiv = document.getElementById('courseList'); if (!courseListDiv) return; courseListDiv.innerHTML = ''; if (EducationHelper.Config.state.targetCourses.length === 0) { courseListDiv.innerHTML = '<p style="margin: 0; color: #666;">暂无课程</p>'; } else { EducationHelper.Config.state.targetCourses.forEach((course, index) => { const courseItem = document.createElement('div'); courseItem.className = 'course-item'; courseItem.innerHTML = ` <span>${course}</span> <button class="delete-btn" data-index="${index}">删除</button> `; courseListDiv.appendChild(courseItem); }); // 添加删除按钮事件 courseListDiv.querySelectorAll('.delete-btn').forEach(btn => { btn.addEventListener('click', (e) => { const idx = parseInt(e.target.getAttribute('data-index')); this.remove(idx); }); }); } } }, // 匹配成功课程操作 matchedCourses: { // 添加匹配成功的课程 add: function(courseCode) { if (courseCode && !EducationHelper.Config.state.matchedCourses.includes(courseCode)) { EducationHelper.Config.state.matchedCourses.push(courseCode); this.updateUI(); EducationHelper.Logger.success(`已添加匹配成功课程: ${courseCode}`); return true; } return false; }, // 更新匹配成功课程UI updateUI: function() { const matchedCoursesDiv = document.getElementById('matchedCourses'); if (!matchedCoursesDiv) return; matchedCoursesDiv.innerHTML = ''; if (EducationHelper.Config.state.matchedCourses.length === 0) { matchedCoursesDiv.innerHTML = '<p style="margin: 0; color: #666;">暂无匹配成功的课程</p>'; } else { EducationHelper.Config.state.matchedCourses.forEach(course => { const courseItem = document.createElement('div'); courseItem.className = 'course-item'; courseItem.innerHTML = `<span>${course}</span>`; matchedCoursesDiv.appendChild(courseItem); }); } } }, // 抢课过程控制 control: { // 启动抢课 start: function() { if (EducationHelper.Config.state.targetCourses.length === 0) { EducationHelper.UI.showMessage('请先添加课程', 'error'); return false; } // 设置按钮状态 document.getElementById('startScript').disabled = true; document.getElementById('stopScript').disabled = false; // 启动定时器 EducationHelper.Config.state.timer = setInterval(this.checkAndSelectCourses.bind(this), 1000); EducationHelper.Logger.action('抢课脚本已启动'); return true; }, // 停止抢课 stop: function() { if (EducationHelper.Config.state.timer) { clearInterval(EducationHelper.Config.state.timer); EducationHelper.Config.state.timer = null; // 设置按钮状态 document.getElementById('startScript').disabled = false; document.getElementById('stopScript').disabled = true; EducationHelper.Logger.action('抢课脚本已停止'); return true; } return false; }, // 检查并选择课程 checkAndSelectCourses: function() { EducationHelper.Logger.action('开始检查课程...'); const iframeDoc = document.querySelector('#ifra')?.contentDocument; if (!iframeDoc) { EducationHelper.Logger.error('无法获取 iframe 文档'); return; } if (EducationHelper.Config.state.targetCourses.length === 0) { EducationHelper.Logger.action('所有课程已处理,尝试提交...'); this.clickSubmitButton(); this.stop(); return; } const courseCode = EducationHelper.Config.state.targetCourses[0]; const rows = iframeDoc.querySelectorAll('tr'); EducationHelper.Logger.debug(`正在匹配课程代码: ${courseCode},总共找到 ${rows.length} 行课程数据`); let matched = false; rows.forEach((row) => { const courseCells = row.querySelectorAll('td[rowspan]'); courseCells.forEach((courseCell) => { const cellText = courseCell.textContent.trim(); const cellNumber = cellText.match(/\d+/g)?.join('') || ''; EducationHelper.Logger.debug(`检查单元格内容: ${cellText}, 提取的数字: ${cellNumber}`); if (cellNumber === courseCode) { matched = true; EducationHelper.Logger.success(`匹配成功 - 课程代码: ${courseCode}, 单元格内容: ${cellText}`); const checkbox = row.querySelector(`input[type="checkbox"]`); if (checkbox && !checkbox.checked) { checkbox.click(); EducationHelper.Logger.success(`已勾选课程: ${courseCode}`); } } }); }); if (matched) { EducationHelper.Logger.action(`已处理课程: ${courseCode}`); EducationHelper.CourseGrabber.matchedCourses.add(courseCode); EducationHelper.Config.state.targetCourses.shift(); } else { EducationHelper.Logger.warn(`未匹配到课程代码: ${courseCode}`); } }, // 点击提交按钮 clickSubmitButton: function() { const button = document.querySelector('#submitButton'); if (button) { EducationHelper.Logger.action('找到提交按钮,正在尝试提交...'); const event = new MouseEvent('click', { bubbles: true, cancelable: true, view: window }); button.dispatchEvent(event); EducationHelper.Logger.success('已提交选课请求'); return true; } else { EducationHelper.Logger.warn('未找到提交按钮,请检查页面结构'); return false; } } }, // UI内容生成 generateUI: function() { return ` <div class="ui-tabs"> <div class="ui-tab active" data-tab="courseTab">抢课功能</div> </div> <div class="ui-tab-content active" id="courseTab"> <label class="ui-label">课程代码:</label> <textarea id="courseCode" class="ui-input" style="height: 60px;" placeholder="输入多个课程代码,一行一个"></textarea> <button class="ui-button" id="addCourses">添加课程</button> <div class="ui-panel"> <div class="ui-panel-title">课程列表</div> <div id="courseList"> <p style="margin: 0; color: #666;">暂无课程</p> </div> </div> <button class="ui-button" id="startScript">启动抢课</button> <button class="ui-button" id="stopScript" disabled>停止抢课</button> <div class="ui-panel"> <div class="ui-panel-title">匹配成功的课程</div> <div id="matchedCourses"> <p style="margin: 0; color: #666;">暂无匹配成功的课程</p> </div> </div> </div> `; }, // 注册(不可用)事件监听 bindEvents: function() { document.getElementById('addCourses').addEventListener('click', () => { const courseCodesInput = document.getElementById('courseCode').value.trim(); if (this.courseList.add(courseCodesInput)) { document.getElementById('courseCode').value = ''; } }); document.getElementById('startScript').addEventListener('click', () => { this.control.start(); }); document.getElementById('stopScript').addEventListener('click', () => { this.control.stop(); }); }, // 初始化抢课模块 init: function() { // 只在课程选择页面初始化 if (!EducationHelper.Config.pageType.isCoursePage) return; EducationHelper.Logger.action('初始化抢课模块...'); // 其他初始化操作 return this; } }, // 评估模块 - 处理单个评估页面 Evaluator: { // 选项选择功能 optionSelector: { // 根据所选字母选择选项 selectByLetter: function(letter) { EducationHelper.Logger.action(`正在选择${letter}选项...`); // 更新配置中的选择 EducationHelper.Config.state.selectedOption = letter; try { // 使用jQuery选择选项 $(".ace").each(function() { var self = $(this); var text = $(this).next().next().html(); if (text && text.indexOf(`(${letter})`) !== -1) { self.click(); } }); EducationHelper.Logger.success(`已全选${letter}选项`); return true; } catch (error) { EducationHelper.Logger.error(`选择${letter}选项时出错`, error); return false; } } }, // 评价内容填写 contentFiller: { // 填写评价内容 fillContent: function(content) { content = content || EducationHelper.Config.content.evaluationComment; EducationHelper.Logger.action('正在填写评价内容...'); try { // 尝试多种选择器找到文本区域 let filled = false; // 1. 通过name属性查找 const mainTextarea = document.querySelector('textarea[name="zgpj"]'); if (mainTextarea) { mainTextarea.value = content; // 触发change事件 const event = new Event('input', { bubbles: true }); mainTextarea.dispatchEvent(event); EducationHelper.Logger.success("已通过name='zgpj'找到并填写主观评价文本框"); filled = true; } // 2. 查找所有文本区域 if (!filled) { const textareas = document.querySelectorAll('textarea.form-control'); if (textareas.length > 0) { for (const textarea of textareas) { textarea.value = content; const event = new Event('input', { bubbles: true }); textarea.dispatchEvent(event); } EducationHelper.Logger.success("已填写所有文本框"); filled = true; } } // 3. 使用jQuery选择器 if (!filled) { const jqTextarea = $("#page-content-template > div > div > div.widget-content > form > div > table > tbody > tr:nth-child(25) > td > div > textarea"); if (jqTextarea.length > 0) { jqTextarea.val(content); EducationHelper.Logger.success("已使用jQuery选择器填写评价内容"); filled = true; } } // 4. 最后尝试任何文本区域 if (!filled) { const allTextareas = document.querySelectorAll('textarea'); if (allTextareas.length > 0) { for (const textarea of allTextareas) { textarea.value = content; const event = new Event('input', { bubbles: true }); textarea.dispatchEvent(event); } EducationHelper.Logger.success("已填写所有找到的文本区域"); filled = true; } } return filled; } catch (error) { EducationHelper.Logger.error("填写评价内容时出错", error); return false; } } }, // 评价提交处理 submitter: { // 倒计时组件 countdown: { timer: null, seconds: 0, // 开始倒计时 start: function(duration, onComplete) { // 停止现有倒计时 this.stop(); // 设置初始秒数 this.seconds = duration || EducationHelper.Config.timers.autoSubmitDelay / 1000; // 确保倒计时显示元素存在且可见 this.ensureDisplayExists(); // 更新显示 this.updateDisplay(); // 开始倒计时 this.timer = setInterval(() => { this.seconds--; this.updateDisplay(); if (this.seconds <= 0) { this.stop(); if (typeof onComplete === 'function') { onComplete(); } } }, 1000); return this; }, // 停止倒计时 stop: function() { if (this.timer) { clearInterval(this.timer); this.timer = null; } return this; }, // 确保倒计时显示元素存在 ensureDisplayExists: function() { // 检查是否已存在倒计时显示 let timerDisplay = document.getElementById('timerDisplay'); // 如果不存在,创建一个新的 if (!timerDisplay) { EducationHelper.Logger.action('创建倒计时显示元素'); timerDisplay = document.createElement('div'); timerDisplay.id = 'timerDisplay'; timerDisplay.className = 'timer-display'; // 添加到UI容器中 const uiContent = document.getElementById('uiContent'); if (uiContent) { // 添加到UI内容区的合适位置 const buttons = uiContent.querySelector('div[style*="display: flex"]'); if (buttons) { uiContent.insertBefore(timerDisplay, buttons); } else { // 如果找不到按钮区域,添加到内容区最后 uiContent.appendChild(timerDisplay); } } else { // 如果找不到UI容器,添加到body document.body.appendChild(timerDisplay); } } // 确保样式正确 timerDisplay.style.display = 'block'; timerDisplay.style.backgroundColor = '#e3f2fd'; timerDisplay.style.border = '1px solid #1976d2'; timerDisplay.style.padding = '10px'; timerDisplay.style.borderRadius = '4px'; timerDisplay.style.marginBottom = '10px'; timerDisplay.style.fontWeight = 'bold'; timerDisplay.style.fontSize = '16px'; timerDisplay.style.textAlign = 'center'; timerDisplay.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)'; // 设置初始内容 if (!timerDisplay.innerHTML || !timerDisplay.innerHTML.includes('timerValue')) { timerDisplay.innerHTML = '等待提交: <span id="timerValue">120</span> 秒'; } // 如果是自动模式,使用不同的样式 if (EducationHelper.Config.state.autoMode) { timerDisplay.style.backgroundColor = '#e8f5e9'; timerDisplay.style.border = '1px solid #4caf50'; timerDisplay.innerHTML = '<span style="color:#2e7d32; font-size:18px;">⏱️ 自动提交倒计时: <span id="timerValue">120</span> 秒</span>'; } return timerDisplay; }, // 更新倒计时显示 updateDisplay: function() { const timerElement = document.getElementById('timerValue'); if (timerElement) { timerElement.textContent = this.seconds; } return this; } }, // 查找并点击提交按钮 findAndClickSubmitButton: function(showMessage = true) { EducationHelper.Logger.action('查找提交按钮...'); // 显示状态消息 let statusMsg = null; if (showMessage) { statusMsg = EducationHelper.UI.showMessage('<div>正在提交评价...</div>', 'info', 0); // 0表示不自动消失 } setTimeout(() => { // 收集所有可能的按钮,生成一个优先级列表 const possibleButtons = []; // 查找带有"提交"文本的所有按钮 const allButtons = document.querySelectorAll('button, input[type="submit"], input[type="button"]'); EducationHelper.Logger.debug(`找到 ${allButtons.length} 个按钮元素`); allButtons.forEach(btn => { const btnText = btn.textContent || btn.value || ''; EducationHelper.Logger.debug(`检查按钮: "${btnText}", HTML: ${btn.outerHTML}`); // 按钮匹配度评分 let score = 0; // 文本包含"提交" if (btnText.includes('提交')) { score += 10; } // 底部按钮优先 const rect = btn.getBoundingClientRect(); if (rect.top > window.innerHeight / 2) { score += 5; } // 样式匹配度 if (btn.className.includes('btn-danger') || btn.className.includes('btn-primary') || btn.className.includes('layui-btn')) { score += 3; } // 有红色或蓝色背景 const style = window.getComputedStyle(btn); const bgColor = style.backgroundColor; if (bgColor.includes('rgb(') && (bgColor.includes('255') || bgColor.includes('0, 0, 255'))) { score += 2; } // 如果得分大于0,添加到可能按钮列表 if (score > 0) { possibleButtons.push({button: btn, score: score}); } }); // 按得分排序 possibleButtons.sort((a, b) => b.score - a.score); // 选择得分最高的按钮 let submitButton = null; if (possibleButtons.length > 0) { submitButton = possibleButtons[0].button; EducationHelper.Logger.success(`找到提交按钮, 得分: ${possibleButtons[0].score}`); } // 如果没找到按钮,尝试其他方法 if (!submitButton) { // 尝试特定ID或名称 submitButton = document.querySelector('#submit, #btnSubmit, .submit-btn, [name="submit"]'); if (!submitButton) { // 尝试表单提交按钮 const forms = document.querySelectorAll('form'); forms.forEach(form => { const submitBtn = form.querySelector('[type="submit"]'); if (submitBtn) { submitButton = submitBtn; } }); } } // 点击提交按钮 if (submitButton) { // 更新状态提示 if (statusMsg) { statusMsg.innerHTML = '<div>找到提交按钮,正在点击...</div>'; } EducationHelper.Logger.action("找到提交按钮,点击提交"); // 确保按钮可见 submitButton.scrollIntoView({behavior: 'smooth', block: 'center'}); // 加上小延迟,确保滚动完成后再点击 setTimeout(() => { // 点击按钮 submitButton.click(); // 处理确认对话框 this.handleConfirmDialog(statusMsg); }, 500); return true; } else { EducationHelper.Logger.warn("未找到提交按钮"); if (statusMsg) { statusMsg.innerHTML = '<div style="color:#ff9800">未找到提交按钮,尝试其他方法...</div>'; } // 尝试直接提交表单 const mainForm = document.querySelector('form'); if (mainForm) { EducationHelper.Logger.action("尝试直接提交表单"); try { mainForm.submit(); EducationHelper.Logger.success("已调用表单的submit()方法"); if (statusMsg) { statusMsg.innerHTML = '<div style="color:#4caf50">已尝试提交表单,请检查是否成功</div>'; // 2秒后移除状态提示 setTimeout(() => { if (statusMsg && document.contains(statusMsg)) { statusMsg.remove(); } }, 2000); } return true; } catch (e) { EducationHelper.Logger.error("尝试提交表单失败", e); if (statusMsg) { statusMsg.innerHTML = '<div style="color:red">自动提交失败,请手动点击页面中的"提交"按钮</div>'; // 5秒后移除提示 setTimeout(() => { if (statusMsg && document.contains(statusMsg)) { statusMsg.remove(); } }, 5000); } return false; } } else { // 提示用户手动提交 if (statusMsg) { statusMsg.innerHTML = '<div style="color:red">未找到提交按钮,请手动点击页面中的"提交"按钮</div>'; // 5秒后移除提示 setTimeout(() => { if (statusMsg && document.contains(statusMsg)) { statusMsg.remove(); } }, 5000); } return false; } } }, 500); }, // 处理确认对话框 handleConfirmDialog: function(statusMsg) { EducationHelper.Logger.action("等待确认对话框..."); // 等待确认对话框出现 setTimeout(() => { // 尝试查找确认按钮 let confirmButton = document.querySelector('.layui-layer-btn0, .layui-btn, [type="submit"]'); if (!confirmButton) { // 更通用地查找确认按钮 const modalButtons = document.querySelectorAll('.modal-footer .btn, .layui-layer-btn .layui-layer-btn0, .dialog-footer .btn'); if (modalButtons.length > 0) { confirmButton = modalButtons[0]; } else { const buttons = document.querySelectorAll('button, a.btn, input[type="button"]'); for (const btn of buttons) { const btnText = btn.textContent || btn.value || ''; if (btnText.includes('确定') || btnText.includes('确认') || btnText.includes('是')) { confirmButton = btn; break; } } } } if (confirmButton) { EducationHelper.Logger.action("找到确认按钮,确认提交"); // 更新状态提示 if (statusMsg) { statusMsg.innerHTML = '<div>找到确认按钮,正在确认提交...</div>'; } // 点击确认按钮 confirmButton.click(); // 显示成功消息 if (statusMsg) { statusMsg.innerHTML = '<div style="color:#4caf50">评价提交成功!</div>'; // 2秒后隐藏提示 setTimeout(() => { if (statusMsg && document.contains(statusMsg)) { statusMsg.remove(); } }, 2000); } EducationHelper.Logger.success("已完成评价提交"); // 全屏成功提示 EducationHelper.UI.showMessage(` <div style="font-size: 48px; margin-bottom: 20px;">✅</div> <div style="font-weight: bold; margin-bottom: 10px;">评价提交成功!</div> `, 'success', 2000); // 如果处于自动模式,尝试自动返回列表页以继续评价 if (EducationHelper.Config.state.autoMode) { // 查找返回按钮或列表链接 setTimeout(() => { const backBtn = document.querySelector('a:contains("返回"), a:contains("列表"), a[href*="index"]'); if (backBtn) { EducationHelper.Logger.action("找到返回按钮,自动返回列表页"); backBtn.click(); } }, 2000); } return true; } else { EducationHelper.Logger.action("未找到确认按钮,可能评价已直接提交或需要手动确认"); // 提示用户可能需要手动确认 if (statusMsg) { statusMsg.innerHTML = '<div style="color:#ff9800">可能需要手动确认提交,请检查是否有弹出确认窗口</div>'; // 5秒后移除提示 setTimeout(() => { if (statusMsg && document.contains(statusMsg)) { statusMsg.remove(); } }, 5000); } return false; } }, 1000); } }, // 流程控制 process: { // 启动自动评价流程 start: function() { EducationHelper.Logger.action('开始评价流程...'); // 显示状态消息 const statusMsg = EducationHelper.UI.showMessage( '<div>正在进行评价操作...</div>', 'info', 2000 ); // 1. 选择选项 EducationHelper.Evaluator.optionSelector.selectByLetter( EducationHelper.Config.state.selectedOption ); // 2. 填写评价内容 setTimeout(() => { EducationHelper.Evaluator.contentFiller.fillContent( document.getElementById('evaluationContent')?.value || EducationHelper.Config.content.evaluationComment ); // 禁用开始按钮,防止重复点击 const startButton = document.getElementById('startEvaluation'); if (startButton) { startButton.disabled = true; startButton.style.opacity = '0.6'; startButton.textContent = '评价已开始'; } // 3. 如果自动提交已启用,启动倒计时 if (EducationHelper.Config.state.autoSubmitEnabled) { EducationHelper.Logger.action('已启用自动提交,开始倒计时...'); // 启动倒计时 EducationHelper.Evaluator.submitter.countdown.start( EducationHelper.Config.timers.autoSubmitDelay / 1000, // 倒计时结束回调 () => { if (EducationHelper.Config.state.autoSubmitEnabled) { EducationHelper.Logger.action('倒计时结束,自动提交评价'); // 提示用户即将提交 EducationHelper.UI.showMessage( `<div style="font-size: 24px; margin-bottom: 10px;">⏱️ 倒计时结束</div> <div style="font-weight: bold; margin-bottom: 15px;">正在自动提交评价...</div>`, 'info', 2000 ); // 提交评价 setTimeout(() => { EducationHelper.Evaluator.process.submit(); }, 2000); } } ); } }, 500); }, // 提交评价 submit: function() { EducationHelper.Logger.action('提交评价...'); // 保存评价内容到配置 const contentElement = document.getElementById('evaluationContent'); if (contentElement) { EducationHelper.Config.content.evaluationComment = contentElement.value; // 保存到localStorage EducationHelper.Config.saveSettings(); } // 再次确认文本框已填写 EducationHelper.Evaluator.contentFiller.fillContent(); // 查找并点击提交按钮 EducationHelper.Evaluator.submitter.findAndClickSubmitButton(); } }, // UI生成 generateUI: function() { return ` <div class="ui-tabs"> <div class="ui-tab active" data-tab="evaluationTab">教学评估</div> </div> <div class="ui-tab-content active" id="evaluationTab"> <div class="ui-panel" style="max-height: none;"> <div class="ui-panel-title">选项设置</div> <div class="option-container"> <div class="option-row"> <label class="radio-label"> <input type="radio" name="evaluationOption" value="A" ${EducationHelper.Config.state.selectedOption === 'A' ? 'checked' : ''}> <span>全选A选项</span> </label> </div> <div class="option-row"> <label class="radio-label"> <input type="radio" name="evaluationOption" value="B" ${EducationHelper.Config.state.selectedOption === 'B' ? 'checked' : ''}> <span>全选B选项</span> </label> </div> <div class="option-row"> <label class="radio-label"> <input type="radio" name="evaluationOption" value="C" ${EducationHelper.Config.state.selectedOption === 'C' ? 'checked' : ''}> <span>全选C选项</span> </label> </div> </div> </div> <label class="ui-label">评价内容:</label> <textarea id="evaluationContent" class="ui-input" style="height: 80px;" placeholder="输入评价内容">${EducationHelper.Config.content.evaluationComment}</textarea> <div class="ui-checkbox-container"> <input type="checkbox" id="autoSubmitEvaluation" class="ui-checkbox" ${EducationHelper.Config.state.autoSubmitEnabled ? 'checked' : ''}> <label for="autoSubmitEvaluation" class="ui-label" style="display: inline; margin: 0;">自动提交评价</label> </div> <div class="timer-display" id="timerDisplay"> 等待提交: <span id="timerValue">120</span> 秒 </div> <div style="display: flex; gap: 5px; margin-bottom: 10px;"> <button class="ui-button" id="selectOptions">选择选项</button> <button class="ui-button" id="submitEvaluation">立即提交</button> </div> <button class="ui-button" id="startEvaluation" style="background: linear-gradient(135deg, #4caf50, #2e7d32);">开始评价</button> </div> `; }, // 事件绑定 bindEvents: function() { // 选项单选按钮 const optionRadios = document.getElementsByName('evaluationOption'); optionRadios.forEach(radio => { radio.addEventListener('change', function() { EducationHelper.Config.state.selectedOption = this.value; EducationHelper.Logger.action(`已选择${this.value}选项`); // 保存选择到localStorage EducationHelper.Config.saveSettings(); }); }); // 自动提交复选框 document.getElementById('autoSubmitEvaluation').addEventListener('change', function() { EducationHelper.Config.state.autoSubmitEnabled = this.checked; EducationHelper.Logger.action(`自动提交评价: ${this.checked ? '已启用' : '已禁用'}`); }); // 评价内容输入框 document.getElementById('evaluationContent').addEventListener('input', function() { EducationHelper.Config.content.evaluationComment = this.value; }); // 选择选项按钮 document.getElementById('selectOptions').addEventListener('click', () => { EducationHelper.Evaluator.optionSelector.selectByLetter( EducationHelper.Config.state.selectedOption ); // 如果启用了自动提交,则应用选项后自动提交 if (EducationHelper.Config.state.autoSubmitEnabled) { EducationHelper.Logger.action('已启用自动提交,将在3秒后提交评价...'); setTimeout(() => { EducationHelper.Evaluator.process.submit(); }, 3000); } }); // 立即提交评价按钮 document.getElementById('submitEvaluation').addEventListener('click', () => { EducationHelper.Evaluator.process.submit(); }); // 开始评价按钮 document.getElementById('startEvaluation').addEventListener('click', () => { EducationHelper.Evaluator.process.start(); }); }, // 初始化 init: function() { if (!EducationHelper.Config.pageType.isEvaluationPage) return; EducationHelper.Logger.action('初始化评估模块...'); // 检查localStorage中是否存在autoMode标记 if (EducationHelper.Config.state.autoMode) { EducationHelper.Logger.action('检测到全自动模式,自动开始评价流程'); // 显示状态提示 EducationHelper.UI.showMessage( '<div>全自动模式已启用,将在2秒后自动开始评价...</div>', 'info', 2000 ); // 延迟执行,确保页面已完全加载 setTimeout(() => { // 自动执行评价流程 this.process.start(); // 更新状态提示 EducationHelper.UI.showMessage( '<div>已自动开始评价,将在2分钟后自动提交...</div>', 'info', 5000 ); }, 2000); } return this; } }, // 评估列表模块 - 处理评估列表页面 EvaluationList: { // 自动点击功能 autoClicker: { // 开始自动点击倒计时 startCountdown: function() { EducationHelper.Logger.action(`开始自动点击倒计时,${EducationHelper.Config.timers.autoClickEvaluationDelay/1000}秒后开始执行...`); // 设置初始倒计时值 const countdownElement = document.getElementById('countdownValue'); if (!countdownElement) return false; let secondsLeft = EducationHelper.Config.timers.autoClickEvaluationDelay / 1000; countdownElement.textContent = secondsLeft; // 清除之前的计时器 if (window.autoClickCountdownTimer) { clearInterval(window.autoClickCountdownTimer); } // 创建全局标记来表示停止状态 window.autoClickStopped = false; // 创建新的倒计时 window.autoClickCountdownTimer = setInterval(() => { // 每次检查是否已停止 if (window.autoClickStopped) { clearInterval(window.autoClickCountdownTimer); window.autoClickCountdownTimer = null; EducationHelper.Logger.action('倒计时已被手动停止'); return; } secondsLeft -= 1; countdownElement.textContent = secondsLeft; // 倒计时结束,执行自动点击 if (secondsLeft <= 0) { clearInterval(window.autoClickCountdownTimer); window.autoClickCountdownTimer = null; // 再次检查是否仍然启用了自动点击和未被停止 if ((EducationHelper.Config.state.autoClickEvaluationEnabled || EducationHelper.Config.state.autoMode) && !window.autoClickStopped) { EducationHelper.Logger.action('倒计时结束,开始扫描评估按钮...'); // 更新倒计时文本 const countdownDiv = document.getElementById('countdownDiv'); if (countdownDiv) { countdownDiv.innerHTML = '<span style="color:#4caf50;">自动操作开始执行...</span>'; } // 延迟执行扫描,让用户有机会看到状态更新 setTimeout(() => { // 再次检查,确保在延迟期间没有被停止 if (!window.autoClickStopped) { // 扫描并点击评估按钮 EducationHelper.EvaluationList.scanner.scanAndClick(false); // 扫描完成后隐藏倒计时区域 setTimeout(() => { if (countdownDiv) { countdownDiv.style.display = 'none'; } // 自动模式下不关闭开关,保持自动状态 if (!EducationHelper.Config.state.autoMode) { EducationHelper.Config.state.autoClickEvaluationEnabled = false; const checkbox = document.getElementById('autoClickEvaluation'); if (checkbox) checkbox.checked = false; } }, 2000); } else { EducationHelper.Logger.action('在延迟期间检测到停止请求,取消自动操作'); if (countdownDiv) { countdownDiv.style.display = 'none'; } } }, 500); } else { EducationHelper.Logger.action('倒计时结束,但自动点击已被禁用'); const countdownDiv = document.getElementById('countdownDiv'); if (countdownDiv) { countdownDiv.style.display = 'none'; } } } }, 1000); return true; } }, // 扫描与点击 scanner: { // 扫描评估按钮并点击 scanAndClick: function(isManualMode = false) { EducationHelper.Logger.action(`${isManualMode ? '手动' : '自动'}扫描评估按钮开始...`); // 获取所有按钮 const buttons = document.querySelectorAll('button'); // 设置状态展示 let statusDisplay = document.createElement('div'); statusDisplay.id = 'evaluationStatus'; statusDisplay.style = 'position:fixed; top:10px; right:10px; background:rgba(0,0,0,0.7); color:white; padding:10px; border-radius:5px; z-index:9999;'; statusDisplay.innerHTML = '<div>正在扫描评估按钮...</div>'; document.body.appendChild(statusDisplay); // 找到包含"评估"的按钮 let evaluationButtons = []; buttons.forEach(button => { if ((button.innerText && button.innerText.includes('评估')) || (button.textContent && button.textContent.includes('评估'))) { evaluationButtons.push(button); EducationHelper.Logger.debug(`评估按钮: ${button.outerHTML}`); } }); // 如果找不到评估按钮,尝试链接 if (evaluationButtons.length === 0) { const links = document.querySelectorAll('a'); links.forEach(link => { if ((link.innerText && link.innerText.includes('评估')) || (link.textContent && link.textContent.includes('评估'))) { evaluationButtons.push(link); EducationHelper.Logger.debug(`评估链接: ${link.outerHTML}`); } }); } statusDisplay.innerHTML = `<div>找到 ${evaluationButtons.length} 个评估按钮</div>`; // 如果是手动模式,显示一个提示并等待用户确认 if (isManualMode) { statusDisplay.innerHTML += ` <div style="margin-top:10px;"> <button id="confirmClick" style="background:#4CAF50; color:white; border:none; padding:5px 10px; margin-right:5px; cursor:pointer;">点击第一个按钮</button> <button id="cancelClick" style="background:#F44336; color:white; border:none; padding:5px 10px; cursor:pointer;">取消</button> </div> `; document.getElementById('confirmClick').addEventListener('click', () => { // 点击第一个评估按钮 if (evaluationButtons.length > 0) { this.clickButton(evaluationButtons[0]); } statusDisplay.remove(); }); document.getElementById('cancelClick').addEventListener('click', () => { statusDisplay.remove(); }); return; } // 自动模式处理 if (evaluationButtons.length > 0) { // 优先点击带有"评估"文本的按钮 const buttonToClick = evaluationButtons[0]; // 创建一个明显的大号倒计时提示 let countdownSeconds = 5; // 单独设置5秒倒计时,让用户有足够时间反应 // 创建明显的倒计时提示框 const countdownDisplay = document.createElement('div'); countdownDisplay.style = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(33, 150, 243, 0.9); color: white; padding: 20px; border-radius: 8px; z-index: 10000; text-align: center; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3); font-weight: bold; font-size: 18px; min-width: 300px; `; countdownDisplay.innerHTML = ` <div style="font-size: 24px; margin-bottom: 15px;">⚠️ 即将点击评估按钮</div> <div>找到评估按钮,将在 <span id="clickCountdown" style="font-size: 26px; color: #ffeb3b;">${countdownSeconds}</span> 秒后点击</div> <div style="margin-top: 15px; font-size: 14px;">点击下方按钮可以取消自动操作</div> <button id="cancelAutoClick" style="background: #f44336; border: none; color: white; padding: 8px 15px; margin-top: 10px; border-radius: 4px; cursor: pointer;">取消自动点击</button> `; document.body.appendChild(countdownDisplay); // 更新状态 statusDisplay.innerHTML = '<div>找到评估按钮,请查看屏幕中央的倒计时提示</div>'; // 添加取消按钮事件 document.getElementById('cancelAutoClick').addEventListener('click', () => { clearInterval(countdownTimer); countdownDisplay.remove(); statusDisplay.innerHTML = '<div>已取消自动点击操作</div>'; // 设置全局停止标记 window.autoClickStopped = true; // 3秒后移除状态显示 setTimeout(() => { if (statusDisplay && document.contains(statusDisplay)) { statusDisplay.remove(); } }, 3000); }); // 开始倒计时 const countdownTimer = setInterval(() => { countdownSeconds--; // 检查是否已手动停止 if (window.autoClickStopped) { clearInterval(countdownTimer); if (countdownDisplay && document.contains(countdownDisplay)) { countdownDisplay.remove(); } if (statusDisplay && document.contains(statusDisplay)) { statusDisplay.innerHTML = '<div>操作已停止</div>'; setTimeout(() => statusDisplay.remove(), 2000); } return; } const countdownElement = document.getElementById('clickCountdown'); if (countdownElement) { countdownElement.textContent = countdownSeconds; // 当倒计时小于3秒时,改变颜色提醒用户 if (countdownSeconds <= 3) { countdownElement.style.color = '#ff5252'; countdownElement.style.fontSize = '30px'; } } if (countdownSeconds <= 0) { clearInterval(countdownTimer); countdownDisplay.innerHTML = '<div style="font-size: 24px;">正在点击评估按钮...</div>'; // 点击评估按钮 setTimeout(() => { // 再次检查是否已停止 if (!window.autoClickStopped) { this.clickButton(buttonToClick); // 移除倒计时显示 countdownDisplay.remove(); // 更新状态 statusDisplay.innerHTML = '<div>已点击评估按钮,即将跳转...</div>'; setTimeout(() => { if (statusDisplay && document.contains(statusDisplay)) { statusDisplay.remove(); } }, 2000); } else { // 操作已被用户停止 countdownDisplay.remove(); statusDisplay.innerHTML = '<div>操作已停止</div>'; setTimeout(() => statusDisplay.remove(), 2000); } }, 500); } }, 1000); } else { statusDisplay.innerHTML = '<div style="color:#ff9800">未找到评估按钮</div>'; // 3秒后移除状态显示 setTimeout(() => { statusDisplay.remove(); }, 3000); } }, // 安全点击按钮 clickButton: function(button) { EducationHelper.Logger.action(`点击按钮: ${button.outerHTML}`); // 尝试使用默认点击事件 try { button.click(); EducationHelper.Logger.success('已点击按钮'); return true; } catch (error) { EducationHelper.Logger.warn('直接点击失败,尝试使用替代方法:', error); } // 尝试触发合成事件 try { // 创建鼠标事件并触发 const evt = new MouseEvent('click', { bubbles: true, cancelable: true, view: window }); // 分发事件 button.dispatchEvent(evt); EducationHelper.Logger.success('已通过事件触发点击按钮'); return true; } catch (error) { EducationHelper.Logger.error('无法点击按钮:', error); return false; } } }, // 自动模式控制 autoMode: { // 启用自动模式 enable: function() { EducationHelper.Config.state.autoMode = true; EducationHelper.Logger.action('全自动模式已启用'); // 将autoMode状态保存到localStorage EducationHelper.Config.saveSettings(); // 自动启用评估按钮点击 EducationHelper.Config.state.autoClickEvaluationEnabled = true; const checkbox = document.getElementById('autoClickEvaluation'); if (checkbox) checkbox.checked = true; // 显示倒计时并开始自动点击 const countdownDiv = document.getElementById('countdownDiv'); if (countdownDiv) { countdownDiv.style.display = 'block'; countdownDiv.innerHTML = ` <span style="display: block; margin-bottom: 5px; font-weight: bold; color: #2e7d32;"> 🚀 全自动模式已启用! </span> <span>自动操作将在 <span id="countdownValue">${EducationHelper.Config.timers.autoClickEvaluationDelay/1000}</span> 秒后开始</span> `; } // 开始倒计时 EducationHelper.EvaluationList.autoClicker.startCountdown(); // 显示提示消息 EducationHelper.UI.showMessage(` <div style="margin-bottom: 10px; font-weight: bold; font-size: 18px;">✅ 全自动模式已启用</div> <div>系统将自动完成整个评价流程:</div> <div style="margin: 10px 0; text-align: left;"> 1. 自动点击"评估"按钮 ⏳<br> 2. 自动选择选项和填写内容 ⏳<br> 3. 自动提交评价 ⏳ </div> `, 'success', 5000); return true; }, // 禁用自动模式 disable: function() { EducationHelper.Config.state.autoMode = false; EducationHelper.Logger.action('全自动模式已禁用'); // 将autoMode状态保存到localStorage EducationHelper.Config.saveSettings(); // 立即设置停止标记 window.autoClickStopped = true; // 立即停止倒计时 if (window.autoClickCountdownTimer) { clearInterval(window.autoClickCountdownTimer); window.autoClickCountdownTimer = null; } // 关闭自动点击评估按钮功能 EducationHelper.Config.state.autoClickEvaluationEnabled = false; const checkbox = document.getElementById('autoClickEvaluation'); if (checkbox) checkbox.checked = false; // 隐藏倒计时区域 const countdownDiv = document.getElementById('countdownDiv'); if (countdownDiv) { countdownDiv.style.display = 'none'; } // 显示停止提示 EducationHelper.UI.showMessage(` <div style="margin-bottom: 10px; font-weight: bold; font-size: 18px;">⛔ 全自动模式已停止</div> <div>自动评价流程已终止,您可以手动操作</div> `, 'error', 3000); return true; } }, // UI生成 generateUI: function() { return ` <div class="ui-tabs"> <div class="ui-tab active" data-tab="evaluationListTab">评估列表</div> </div> <div class="ui-tab-content active" id="evaluationListTab"> <div class="ui-checkbox-container" style="margin-bottom: 5px;"> <input type="checkbox" id="autoClickEvaluation" class="ui-checkbox" ${EducationHelper.Config.state.autoClickEvaluationEnabled ? 'checked' : ''}> <label for="autoClickEvaluation" class="ui-label" style="display: inline; margin: 0;">自动点击"评估"按钮</label> </div> <div class="ui-panel" style="max-height: none; margin-bottom: 10px; background-color: #fff8e1; border-color: #ffecb3;"> <div class="ui-panel-title" style="color: #ff8f00;">注意事项</div> <p style="margin: 5px 0; font-size: 12px; color: #e65100;"> • 自动点击功能默认关闭<br> • 全自动模式将完成所有评价流程<br> • 自动操作将在<strong>${EducationHelper.Config.timers.autoClickEvaluationDelay/1000}秒</strong>后开始执行 </p> </div> <div class="ui-checkbox-container"> <input type="checkbox" id="debugMode" class="ui-checkbox" ${EducationHelper.Config.state.debugMode ? 'checked' : ''}> <label for="debugMode" class="ui-label" style="display: inline; margin: 0;">调试模式</label> </div> <button class="ui-button" id="scanEvaluationButtons">手动扫描评估按钮</button> <button class="ui-button" id="autoModeButton" style="background: ${EducationHelper.Config.state.autoMode ? 'linear-gradient(135deg, #4caf50, #2e7d32)' : 'linear-gradient(135deg, #2196f3, #0d47a1)'}; margin-top: 10px;"> <div style="display: flex; align-items: center; justify-content: center;"> <span style="margin-right: 5px;">${EducationHelper.Config.state.autoMode ? '✅' : '🚀'}</span> <span>${EducationHelper.Config.state.autoMode ? '停止全自动模式' : '启用全自动模式'}</span> ${!EducationHelper.Config.state.autoMode ? '<span style="margin-left: 5px; font-size: 11px;">(自动评估、选择、提交)</span>' : ''} </div> </button> <div id="countdownDiv" style="display: ${(EducationHelper.Config.state.autoClickEvaluationEnabled || EducationHelper.Config.state.autoMode) ? 'block' : 'none'}; margin-bottom: 10px; text-align: center; padding: 5px; background-color: #e3f2fd; border-radius: 4px;"> <span>自动操作将在 <span id="countdownValue">${EducationHelper.Config.timers.autoClickEvaluationDelay/1000}</span> 秒后开始</span> </div> <div id="debugInfo" class="ui-panel" style="max-height: 150px; display: ${EducationHelper.Config.state.debugMode ? 'block' : 'none'};"> <div class="ui-panel-title">调试信息</div> <div id="debugContent" style="font-size: 12px; color: #666;"> <p>启用调试模式可以查看详细信息</p> </div> </div> <div class="ui-panel"> <div class="ui-panel-title">使用说明</div> <p style="margin: 5px 0; font-size: 12px; color: #666;"> 1. <strong>手动模式</strong>:直接点击"手动扫描"按钮<br> 2. <strong>半自动</strong>:勾选"自动点击评估"选项<br> 3. <strong>全自动</strong>:点击"全自动模式"按钮 </p> </div> </div> `; }, // 事件绑定 bindEvents: function() { // 自动点击评估按钮复选框 document.getElementById('autoClickEvaluation').addEventListener('change', function() { EducationHelper.Config.state.autoClickEvaluationEnabled = this.checked; EducationHelper.Logger.action(`自动点击评估按钮: ${this.checked ? '已启用' : '已禁用'}`); // 显示或隐藏倒计时区域 const countdownDiv = document.getElementById('countdownDiv'); if (this.checked) { countdownDiv.style.display = 'block'; EducationHelper.EvaluationList.autoClicker.startCountdown(); } else { countdownDiv.style.display = 'none'; // 如果有正在进行的倒计时,取消它 if (window.autoClickCountdownTimer) { clearInterval(window.autoClickCountdownTimer); window.autoClickCountdownTimer = null; } } }); // 全自动模式按钮 document.getElementById('autoModeButton').addEventListener('click', function() { // 根据当前状态切换自动模式 if (EducationHelper.Config.state.autoMode) { EducationHelper.EvaluationList.autoMode.disable(); } else { EducationHelper.EvaluationList.autoMode.enable(); } // 更新按钮样式 this.style.background = EducationHelper.Config.state.autoMode ? 'linear-gradient(135deg, #4caf50, #2e7d32)' : 'linear-gradient(135deg, #2196f3, #0d47a1)'; this.innerHTML = `<div style="display: flex; align-items: center; justify-content: center;"> <span style="margin-right: 5px;">${EducationHelper.Config.state.autoMode ? '✅' : '🚀'}</span> <span>${EducationHelper.Config.state.autoMode ? '停止全自动模式' : '启用全自动模式'}</span> ${!EducationHelper.Config.state.autoMode ? '<span style="margin-left: 5px; font-size: 11px;">(自动评估、选择、提交)</span>' : ''} </div>`; }); // 调试模式复选框 document.getElementById('debugMode').addEventListener('change', function() { EducationHelper.Config.state.debugMode = this.checked; EducationHelper.Logger.action(`调试模式: ${this.checked ? '已启用' : '已禁用'}`); // 显示/隐藏调试面板 const debugPanel = document.getElementById('debugInfo'); if (debugPanel) { debugPanel.style.display = this.checked ? 'block' : 'none'; } // 如果启用调试模式,输出页面基本信息 if (this.checked) { EducationHelper.Logger.debug('调试模式已启用'); EducationHelper.Logger.debug(`当前URL: ${window.location.href}`); EducationHelper.Logger.debug(`页面标题: ${document.title}`); EducationHelper.Logger.debug(`jQuery可用: ${typeof $ !== 'undefined'}`); } }); // 扫描评估按钮 document.getElementById('scanEvaluationButtons').addEventListener('click', () => { EducationHelper.EvaluationList.scanner.scanAndClick(true); // 手动模式 }); }, // 初始化 init: function() { if (!EducationHelper.Config.pageType.isEvaluationListPage) return; EducationHelper.Logger.action('初始化评估列表模块...'); // 如果启用了自动点击,则设置倒计时 if (EducationHelper.Config.state.autoClickEvaluationEnabled || EducationHelper.Config.state.autoMode) { // 等待UI元素创建完成后启动倒计时 setTimeout(() => { const countdownDiv = document.getElementById('countdownDiv'); if (countdownDiv) { countdownDiv.style.display = 'block'; // 开始倒计时 this.autoClicker.startCountdown(); } }, 500); } return this; } }, }; // 初始化配置 EducationHelper.Config.init(); // 主入口点 - 脚本初始化 function init() { console.log('齐大教务助手启动中...'); // 等待DOM加载完成 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initAfterDOMLoaded); } else { initAfterDOMLoaded(); } } // DOM加载完成后初始化 function initAfterDOMLoaded() { // 创建UI界面 EducationHelper.UI.create(); // 根据页面类型初始化相应模块 initModulesByPageType(); } // 根据页面类型初始化模块 function initModulesByPageType() { const config = EducationHelper.Config; if (config.pageType.isCoursePage) { // 初始化抢课模块 EducationHelper.CourseGrabber.init(); // 生成UI内容 EducationHelper.UI.elements.content.innerHTML = EducationHelper.CourseGrabber.generateUI(); // 绑定事件 EducationHelper.CourseGrabber.bindEvents(); } else if (config.pageType.isEvaluationPage) { // 评估页面初始化代码 EducationHelper.Evaluator.init(); EducationHelper.UI.elements.content.innerHTML = EducationHelper.Evaluator.generateUI(); EducationHelper.Evaluator.bindEvents(); } else if (config.pageType.isEvaluationListPage) { // 评估列表页面初始化代码 EducationHelper.EvaluationList.init(); EducationHelper.UI.elements.content.innerHTML = EducationHelper.EvaluationList.generateUI(); EducationHelper.EvaluationList.bindEvents(); } else { // 不支持的页面 EducationHelper.UI.elements.content.innerHTML = ` <div style="text-align: center; padding: 20px;"> <p>当前页面不支持本助手功能</p> </div> `; } } // 启动脚本 init(); })();