// ==UserScript== // @name 兰州博文科技学院教学评教 // @namespace https://github.com/bowenedu-auto-evaluation // @version 1.0.0 // @description 兰博文教务系统自动评教脚本,一键完成教学评价,默认最高好评 // @author Assistant // @license GPL-3.0-or-later // @match *://jwxt.bowenedu.cn:8080/* // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @run-at document-end // ==/UserScript== // ========== 验证码验证模块 ========== window.BOWEN_VERIFIED = false; (function() { 'use strict'; const VERIFY_API = 'https://qsy.iano.cn/index.php?s=/api/code/verify'; const STORAGE_KEY = 'bowen_eval_valid_until'; const VERIFY_DATE_KEY = 'bowen_eval_verify_date'; const SESSION_KEY = 'bowen_eval_session'; const QRCODE_IMG = 'https://qsy.iano.cn/yzm.png'; function getTodayStr() { return new Date().toISOString().slice(0, 10); } function isVerified() { const validUntil = GM_getValue(STORAGE_KEY, 0); if (validUntil <= Date.now() / 1000) return false; if (sessionStorage.getItem(SESSION_KEY)) return true; const verifyDate = GM_getValue(VERIFY_DATE_KEY, ''); const today = getTodayStr(); if (verifyDate !== today) return false; sessionStorage.setItem(SESSION_KEY, '1'); return true; } function showVerifyDialog() { if (document.getElementById('_verify_overlay')) return; const overlay = document.createElement('div'); overlay.id = '_verify_overlay'; overlay.innerHTML = `
🔐 验证码验证
扫码观看广告获取验证码
验证后免费使用24小时
小程序码
`; (document.body || document.documentElement).appendChild(overlay); const input = document.getElementById('_verify_code'); const btn = document.getElementById('_verify_submit'); const errorEl = document.getElementById('_verify_error'); btn.onclick = function() { const code = input.value.trim(); if (!/^\d{4}$/.test(code)) { errorEl.textContent = '请输入4位验证码'; errorEl.style.display = 'block'; errorEl.classList.remove('shake'); void errorEl.offsetWidth; errorEl.classList.add('shake'); return; } btn.disabled = true; btn.textContent = '验证中...'; errorEl.style.display = 'none'; GM_xmlhttpRequest({ method: 'POST', url: VERIFY_API, timeout: 10000, headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, data: 'code=' + encodeURIComponent(code), onload: function(res) { try { const data = JSON.parse(res.responseText); if (data.code === 1 && data.data.valid) { GM_setValue(STORAGE_KEY, data.data.valid_until); GM_setValue(VERIFY_DATE_KEY, getTodayStr()); sessionStorage.setItem(SESSION_KEY, '1'); overlay.remove(); alert('验证成功!24小时内免费使用'); location.reload(); } else { errorEl.textContent = data.msg || '验证码无效或已过期'; errorEl.style.display = 'block'; errorEl.classList.remove('shake'); void errorEl.offsetWidth; errorEl.classList.add('shake'); btn.disabled = false; btn.textContent = '立即验证'; } } catch(e) { errorEl.textContent = '验证失败,请重试'; errorEl.style.display = 'block'; btn.disabled = false; btn.textContent = '立即验证'; } }, onerror: function() { errorEl.textContent = '网络错误,请重试'; errorEl.style.display = 'block'; btn.disabled = false; btn.textContent = '立即验证'; } }); }; input.onkeypress = function(e) { if (e.key === 'Enter') btn.click(); }; } if (!isVerified()) { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', showVerifyDialog); } else { showVerifyDialog(); } return; } window.BOWEN_VERIFIED = true; })(); // ========== 验证码验证模块结束 ========== (function() { 'use strict'; if (!window.BOWEN_VERIFIED) { console.log('[博文评教] 未通过验证,脚本已停止'); return; } const CONFIG = { AUTO_SUBMIT: true, LOG_DETAIL: true }; const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); const log = (...args) => CONFIG.LOG_DETAIL && console.log('[博文评教]', ...args); const logImportant = (...args) => console.log('[博文评教]', ...args); function getAutoSubmitState() { if (typeof GM_getValue !== 'undefined') { return GM_getValue('AUTO_SUBMIT', CONFIG.AUTO_SUBMIT); } const saved = localStorage.getItem('BOWEN_AUTO_SUBMIT'); return saved !== null ? JSON.parse(saved) : CONFIG.AUTO_SUBMIT; } function setAutoSubmitState(state) { if (typeof GM_setValue !== 'undefined') { GM_setValue('AUTO_SUBMIT', state); } else { localStorage.setItem('BOWEN_AUTO_SUBMIT', JSON.stringify(state)); } updateToggleButton(state); } let buttonsCreated = false; function updateToggleButton(autoSubmitState) { const toggleBtn = document.getElementById('toggleAutoSubmitBtn'); if (toggleBtn) { toggleBtn.textContent = autoSubmitState ? '✅ 自动提交:开' : '⏸️ 自动提交:关'; toggleBtn.style.background = autoSubmitState ? 'linear-gradient(135deg, #4CAF50 0%, #2E7D32 100%)' : 'linear-gradient(135deg, #757575 0%, #424242 100%)'; } } function createControlButtons() { // 检查面板是否真实存在于DOM中 const existingPanel = document.getElementById('bowen-eval-controls'); if (existingPanel) { logImportant('控制面板已存在于DOM,跳过创建'); return; } // 检查是否已经在创建过程中 if (buttonsCreated) { logImportant('控制面板正在创建中,跳过'); return; } buttonsCreated = true; logImportant('创建控制面板...'); const panel = document.createElement('div'); panel.id = 'bowen-eval-controls'; panel.style.cssText = ` position: fixed !important; top: 20px !important; right: 20px !important; z-index: 2147483647 !important; background: linear-gradient(135deg, rgba(255,255,255,0.98) 0%, rgba(250,250,255,0.98) 100%) !important; backdrop-filter: blur(15px) !important; border-radius: 20px !important; padding: 24px !important; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15) !important; border: 1px solid rgba(255, 255, 255, 0.9) !important; min-width: 280px !important; font-family: 'Microsoft YaHei', 'PingFang SC', sans-serif !important; `; const title = document.createElement('div'); title.style.cssText = ` font-size: 18px !important; font-weight: bold !important; color: #333 !important; margin-bottom: 16px !important; text-align: center !important; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; -webkit-background-clip: text !important; -webkit-text-fill-color: transparent !important; background-clip: text !important; `; title.textContent = '博文自动评教'; const mainBtn = document.createElement('button'); mainBtn.id = 'mainEvaluateBtn'; mainBtn.textContent = '开始自动评教'; mainBtn.style.cssText = ` width: 100% !important; padding: 14px !important; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; color: white !important; border: none !important; border-radius: 12px !important; font-size: 15px !important; font-weight: bold !important; cursor: pointer !important; box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4) !important; transition: all 0.3s !important; margin-bottom: 12px !important; `; const toggleBtn = document.createElement('button'); toggleBtn.id = 'toggleAutoSubmitBtn'; const autoSubmitState = getAutoSubmitState(); toggleBtn.textContent = autoSubmitState ? '自动提交: 开启' : '自动提交: 关闭'; toggleBtn.style.cssText = ` width: 100% !important; padding: 10px !important; background: ${autoSubmitState ? 'linear-gradient(135deg, #11998e 0%, #38ef7d 100%)' : 'linear-gradient(135deg, #bdc3c7 0%, #95a5a6 100%)'} !important; color: white !important; border: none !important; border-radius: 10px !important; font-size: 13px !important; font-weight: 600 !important; cursor: pointer !important; transition: all 0.3s !important; margin-bottom: 16px !important; `; const divider = document.createElement('div'); divider.style.cssText = ` height: 1px !important; background: linear-gradient(90deg, transparent, #e0e0e0, transparent) !important; margin: 16px 0 !important; `; const infoText = document.createElement('div'); infoText.style.cssText = ` font-size: 12px !important; color: #666 !important; line-height: 1.8 !important; `; infoText.innerHTML = `
✓ 自动选择最高分
✓ 自动填写好评
✓ 可选自动提交
`; mainBtn.onmouseover = () => { mainBtn.style.transform = 'translateY(-2px)'; mainBtn.style.boxShadow = '0 6px 20px rgba(102, 126, 234, 0.5)'; }; mainBtn.onmouseout = () => { mainBtn.style.transform = 'translateY(0)'; mainBtn.style.boxShadow = '0 4px 15px rgba(102, 126, 234, 0.4)'; }; toggleBtn.onmouseover = () => toggleBtn.style.transform = 'translateY(-1px)'; toggleBtn.onmouseout = () => toggleBtn.style.transform = 'translateY(0)'; mainBtn.addEventListener('click', async () => { logImportant('按钮被点击'); mainBtn.disabled = true; mainBtn.style.opacity = '0.6'; mainBtn.textContent = '执行中...'; try { const evalLink = document.querySelector('li[data-link*="teacherstudentemenu"]') || document.querySelector('li.menu-item[title*="教学评价"]') || Array.from(document.querySelectorAll('li, a')).find(el => el.textContent?.trim() === '教学评价' || el.getAttribute('title')?.includes('教学评价')); if (evalLink && !document.querySelector('textarea, input[type="radio"]')) { logImportant('检测到教学评价链接,正在跳转...', evalLink); evalLink.click(); await sleep(3000); const iframe = document.querySelector('iframe'); if (iframe) { logImportant('检测到iframe,等待加载...'); await sleep(2000); } } else if (!evalLink) { logImportant('未找到教学评价链接,直接执行评教'); } else { logImportant('已在评教页面,直接执行'); } await autoEvaluate(); } catch (error) { logImportant('执行出错:', error); } finally { setTimeout(() => { mainBtn.disabled = false; mainBtn.style.opacity = '1'; mainBtn.textContent = '开始自动评教'; }, 3000); } }); toggleBtn.addEventListener('click', () => { const newState = !getAutoSubmitState(); setAutoSubmitState(newState); toggleBtn.textContent = newState ? '自动提交: 开启' : '自动提交: 关闭'; toggleBtn.style.background = newState ? 'linear-gradient(135deg, #11998e 0%, #38ef7d 100%)' : 'linear-gradient(135deg, #bdc3c7 0%, #95a5a6 100%)'; logImportant(`自动提交已${newState ? '开启' : '关闭'}`); }); panel.appendChild(title); panel.appendChild(mainBtn); panel.appendChild(toggleBtn); panel.appendChild(divider); panel.appendChild(infoText); document.body.appendChild(panel); } async function fillTextEvaluations() { const textAreas = document.querySelectorAll('textarea'); if (textAreas.length === 0) return; logImportant(`找到 ${textAreas.length} 个文本框`); const comments = [ "老师授课准备充分,讲解清晰生动,重点突出,课堂节奏把握得很好。", "课程内容充实,理论与实践结合紧密,对启发思维和掌握知识很有帮助。", "教学态度认真负责,对课程内容掌握深入,能感受到老师对教学的热情。" ]; for (let i = 0; i < textAreas.length; i++) { const textArea = textAreas[i]; const comment = comments[i % comments.length]; textArea.value = comment; textArea.dispatchEvent(new Event('input', { bubbles: true })); textArea.dispatchEvent(new Event('change', { bubbles: true })); await sleep(300); } logImportant('文本评价完成'); } async function submitEvaluation() { if (!getAutoSubmitState()) { logImportant('自动提交已关闭,请手动提交'); return false; } await sleep(1000); const submitBtn = document.querySelector('input[type="submit"], button[type="submit"], input[value*="提交"], button:contains("提交")') || Array.from(document.querySelectorAll('input, button')).find(el => el.value?.includes('提交') || el.textContent?.includes('提交')); if (submitBtn) { logImportant('找到提交按钮,准备提交...'); submitBtn.click(); await sleep(1500); const confirmBtn = document.querySelector('.confirm, button:contains("确定")') || Array.from(document.querySelectorAll('button')).find(el => el.textContent?.includes('确定')); if (confirmBtn) confirmBtn.click(); logImportant('✅ 提交完成'); return true; } logImportant('⚠️ 未找到提交按钮'); return false; } async function autoEvaluate() { logImportant('🚀 开始自动评教...'); // 选择所有单选按钮的最高分 const radioGroups = {}; document.querySelectorAll('input[type="radio"]').forEach(radio => { if (!radioGroups[radio.name]) radioGroups[radio.name] = []; radioGroups[radio.name].push(radio); }); let clickedCount = 0; for (const [name, radios] of Object.entries(radioGroups)) { if (radios.length > 0) { radios[0].click(); clickedCount++; await sleep(200); } } logImportant(`选择题完成 ${clickedCount} 题`); // 选择所有复选框 const checkboxes = document.querySelectorAll('input[type="checkbox"]'); checkboxes.forEach(cb => !cb.checked && cb.click()); if (checkboxes.length > 0) logImportant(`复选框完成 ${checkboxes.length} 个`); await fillTextEvaluations(); await submitEvaluation(); logImportant('✨ 评教流程完成!'); } function initialize() { if (!window.location.href.includes('jwxt.bowenedu.cn')) return; // 防止重复创建 if (document.getElementById('bowen-eval-controls')) { logImportant('控制面板已存在,跳过创建'); return; } // 延迟创建,确保页面加载完成 const createPanel = () => { if (document.getElementById('bowen-eval-controls')) return; createControlButtons(); }; if (document.readyState === 'complete') { createPanel(); } else { window.addEventListener('load', createPanel, { once: true }); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initialize); } else { initialize(); } })();