// ==UserScript== // @name 新海天帮你查跨年级课余量 // @namespace http://tampermonkey.net/ // @version 2.2 // @description 适配新版教务系统的自动跨年级选课脚本(增强通知版) // @author 上条当咩 & Claude // @match https://aa.bjtu.edu.cn/course_selection/courseselecttask/selects/ // @icon https://yaya.csoci.com:1314/files/spc_ico_sora_sd.jpg // @license MIT // @grant GM_xmlhttpRequest // @grant GM_notification // @downloadURL https://update.greasyfork.icu/scripts/521273/%E6%96%B0%E6%B5%B7%E5%A4%A9%E5%B8%AE%E4%BD%A0%E6%9F%A5%E8%B7%A8%E5%B9%B4%E7%BA%A7%E8%AF%BE%E4%BD%99%E9%87%8F.user.js // @updateURL https://update.greasyfork.icu/scripts/521273/%E6%96%B0%E6%B5%B7%E5%A4%A9%E5%B8%AE%E4%BD%A0%E6%9F%A5%E8%B7%A8%E5%B9%B4%E7%BA%A7%E8%AF%BE%E4%BD%99%E9%87%8F.meta.js // ==/UserScript== (function() { 'use strict'; // 您的愿望单课程数组 var wishListCourses = [ 'C102014B 01', 'M402005B 02', ]; let hasSubmitted = false; let notificationIntervals = {}; let isMonitoring = false; // 是否正在监控中 console.log("脚本开始运行..."); // 直接调用initPanel打开跨年级选课页面 function openCrossGradePage() { console.log("尝试打开跨年级选课页面..."); try { unsafeWindow.initPanel('/course_selection/courseselecttask/selects_action/?action=load&iframe=cross&page=1&perpage=10000', 1200); console.log("成功调用initPanel"); return true; } catch(e) { console.error("调用initPanel失败:", e); return false; } } // 检查课程 function checkCourses(iframeDoc) { console.log("开始检查课程..."); const courseTable = iframeDoc.querySelector('table'); if (!courseTable) { throw new Error("未找到课程表"); } const rows = courseTable.querySelectorAll('tbody tr'); console.log(`找到${rows.length}门课程`); let availableCourseCount = 0; rows.forEach((row, index) => { const cells = row.cells; if (cells.length >= 3) { const courseCell = cells[2]; const statusCell = cells[0]; const remainingCell = cells[3]; const courseText = courseCell.textContent.trim(); const match = courseText.match(/([A-Z]\d{6}[A-Z])[^\d]*(\d{2})/); if (match) { const fullCode = `${match[1]} ${match[2]}`; if (wishListCourses.includes(fullCode)) { const statusText = statusCell.textContent.trim(); const remaining = parseInt(remainingCell.textContent.trim()) || 0; console.log(`检查课程[${index}]: ${fullCode}, 状态: ${statusText}, 余量: ${remaining}`); if (remaining > 0 && !statusText.includes('已选')) { availableCourseCount++; const checkbox = row.querySelector('input[type="checkbox"]'); if (checkbox && !checkbox.disabled) { checkbox.checked = true; console.log(`选中课程: ${fullCode}`); } if (!notificationIntervals[fullCode]) { notificationIntervals[fullCode] = setInterval(() => { GM_notification({ title: '跨年级课程余量提醒!', text: `课程 ${fullCode} 有余量!点击停止提醒`, timeout: 0, onclick: () => { clearInterval(notificationIntervals[fullCode]); delete notificationIntervals[fullCode]; } }); }, 3000); } } } } } }); return availableCourseCount; } // 循环监控逻辑 async function monitor() { if (!isMonitoring) return; const iframe = document.querySelector('#panel-container iframe'); if (!iframe) { console.log("未找到iframe,重新打开跨年级选课页面"); openCrossGradePage(); setTimeout(monitor, 2000); return; } try { const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; // 检查课程并自动选课 const availableCourseCount = checkCourses(iframeDoc); console.log(`检测到${availableCourseCount}个可选课程`); if (availableCourseCount > 0 && !hasSubmitted) { const submitBtn = iframeDoc.querySelector('#select-submit-btn'); if (submitBtn) { submitBtn.click(); hasSubmitted = true; console.log("已点击提交按钮"); iframeDoc.addEventListener('keydown', event => { if (event.key === 'Enter') { const captchaDialog = iframeDoc.querySelector('.captcha-dialog:not(.hide)'); if (captchaDialog) { const confirmBtn = iframeDoc.querySelector('.btn-info[data-bb-handler="ok"]'); if (confirmBtn) { confirmBtn.click(); } } } }); } } // 无论是否有课都继续监控 console.log("1秒后刷新页面继续检测..."); setTimeout(() => { if (iframe.contentWindow) { iframe.contentWindow.location.reload(); } setTimeout(monitor, 1000); // 页面刷新后继续监控 }, 1000); } catch(e) { console.error("执行出错:", e); setTimeout(monitor, 2000); // 出错后重试 } } // 启动监控 function startMonitoring() { if (!isMonitoring) { isMonitoring = true; console.log("开始监控..."); openCrossGradePage(); setTimeout(monitor, 2000); } } // 停止监控 function stopMonitoring() { isMonitoring = false; console.log("停止监控"); Object.keys(notificationIntervals).forEach(key => { clearInterval(notificationIntervals[key]); }); } // 清理通知 window.addEventListener('beforeunload', stopMonitoring); // 添加控制按钮 const controlDiv = document.createElement('div'); controlDiv.style.cssText = 'position:fixed;top:10px;right:10px;z-index:9999;'; controlDiv.innerHTML = ` `; document.body.appendChild(controlDiv); document.getElementById('startMonitor').addEventListener('click', startMonitoring); document.getElementById('stopMonitor').addEventListener('click', stopMonitoring); // 自动启动 startMonitoring(); })();