齐齐哈尔大学抢课

仅供学习交流使用,可同时匹配多个课程代码,课程码为纯数字,例如“体育4(1234-5)”就填“412345”

// ==UserScript==
// @name         齐齐哈尔大学抢课
// @namespace    
// @version      1.0
// @description  仅供学习交流使用,可同时匹配多个课程代码,课程码为纯数字,例如“体育4(1234-5)”就填“412345”
// @icon         https://xyh.qqhru.edu.cn/favicon.ico
// @author       忘忧
// @license MIT
// @match        http://111.43.36.164/student/courseSelect/courseSelect/index
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    let targetCourses = [];
    let matchedCourses = [];
    let timer = null;

    // 创建UI
    function createUI() {
        console.log('[初始化] 正在创建 UI...');
        const uiContainer = document.createElement('div');
        uiContainer.id = 'uiContainer';
        uiContainer.style.position = 'absolute';
        uiContainer.style.top = '10px';
        uiContainer.style.right = '10px';
        uiContainer.style.width = '300px';
        uiContainer.style.backgroundColor = '#f4f4f4';
        uiContainer.style.border = '1px solid #ccc';
        uiContainer.style.padding = '10px';
        uiContainer.style.zIndex = '9999';
        uiContainer.style.boxShadow = '0 2px 5px rgba(0, 0, 0, 0.2)';

        uiContainer.innerHTML = `
            <div id="dragBar" style="background-color: #007bff; color: white; padding: 5px; text-align: center; cursor: grab;">
                抢课工具
            </div>
            <div style="padding: 5px;">
                <label>课程代码: 
                    <textarea id="courseCode" style="width: 90%; height: 60px;" placeholder="输入多个课程代码,一行一个"></textarea>
                </label>
                <br />
                <button class="ui-button" id="addCourses">添加课程</button>
                <div id="courseList" style="margin: 5px 0; max-height: 100px; overflow-y: auto; border: 1px solid #ccc; padding: 5px;">
                    <p style="margin: 0;">暂无课程</p>
                </div>
                <button class="ui-button" id="startScript">启动抢课</button>
                <button class="ui-button" id="stopScript" disabled>停止抢课</button>
                <div id="matchedCourses" style="margin: 10px 0; max-height: 100px; overflow-y: auto; border: 1px solid #ccc; padding: 5px;">
                    <p style="margin: 0;">匹配成功的课程代码</p>
                </div>
            </div>
        `;

        document.body.appendChild(uiContainer);

        const style = document.createElement('style');
        style.innerHTML = `
            .ui-button {
                background: #007bff;
                color: white;
                border: none;
                padding: 10px;
                cursor: pointer;
                width: 100%;
                margin-bottom: 5px;
                transition: background 0.3s, transform 0.1s;
            }
            .ui-button:active {
                background: #0056b3;
                transform: scale(0.95);
            }
        `;
        document.head.appendChild(style);

        document.getElementById('addCourses').addEventListener('click', addCourses);
        document.getElementById('startScript').addEventListener('click', startScript);
        document.getElementById('stopScript').addEventListener('click', stopScript);

        // 调用拖动功能
        makeDraggable(uiContainer);
        console.log('[初始化] UI 创建完成');
    }

    // 实现拖动功能并防止 UI 超出页面
    function makeDraggable(element) {
        const dragBar = document.getElementById('dragBar');
        let offsetX = 0;
        let offsetY = 0;
        let isDragging = false;

        dragBar.addEventListener('mousedown', (e) => {
            isDragging = true;
            offsetX = e.clientX - element.getBoundingClientRect().left;
            offsetY = e.clientY - element.getBoundingClientRect().top;
            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 - element.offsetWidth;
                const maxY = window.innerHeight - element.offsetHeight;
                if (newX < 0) newX = 0;
                if (newY < 0) newY = 0;
                if (newX > maxX) newX = maxX;
                if (newY > maxY) newY = maxY;

                element.style.left = `${newX}px`;
                element.style.top = `${newY}px`;
                element.style.position = 'absolute';
            }
        });

        document.addEventListener('mouseup', () => {
            isDragging = false;
            dragBar.style.cursor = 'grab';
            document.body.style.userSelect = ''; // 恢复文本选择
        });
    }

    // 添加课程(逐行输入)
    function addCourses() {
        console.log('[操作] 添加课程...');
        const courseCodesInput = document.getElementById('courseCode').value.trim();
        if (courseCodesInput) {
            const courses = courseCodesInput.split('\n').map(code => code.trim()); // 按行分隔并去除多余空格
            targetCourses = targetCourses.concat(courses.filter(code => !targetCourses.includes(code))); // 去重
            updateCourseList();
            document.getElementById('courseCode').value = '';
            console.log(`[操作成功] 已添加课程代码: ${courses.join(', ')}`);
        } else {
            console.warn('[操作失败] 请输入课程代码');
        }
    }

    // 更新课程列表
    function updateCourseList() {
        console.log('[操作] 更新课程列表...');
        const courseListDiv = document.getElementById('courseList');
        courseListDiv.innerHTML = '';

        if (targetCourses.length === 0) {
            courseListDiv.innerHTML = '<p style="margin: 0;">暂无课程</p>';
            console.log('[操作成功] 当前课程列表为空');
        } else {
            targetCourses.forEach((course, index) => {
                const courseItem = document.createElement('div');
                courseItem.style.display = 'flex';
                courseItem.style.justifyContent = 'space-between';
                courseItem.style.marginBottom = '5px';

                courseItem.innerHTML = `
                    <span>${course}</span>
                    <button style="color: white; background: red; border: none; cursor: pointer;" data-index="${index}">删除</button>
                `;

                courseItem.querySelector('button').addEventListener('click', (e) => {
                    const idx = e.target.getAttribute('data-index');
                    targetCourses.splice(idx, 1);
                    updateCourseList();
                    console.log(`[操作成功] 已删除课程代码: ${course}`);
                });

                courseListDiv.appendChild(courseItem);
            });
            console.log('[操作成功] 更新课程列表完成');
        }
    }

    // 更新匹配成功的课程列表
    function updateMatchedCourses() {
        console.log('[操作] 更新匹配成功的课程列表...');
        const matchedCoursesDiv = document.getElementById('matchedCourses');
        matchedCoursesDiv.innerHTML = '';

        if (matchedCourses.length === 0) {
            matchedCoursesDiv.innerHTML = '<p style="margin: 0;">匹配成功的课程代码</p>';
        } else {
            matchedCourses.forEach(course => {
                const courseItem = document.createElement('div');
                courseItem.textContent = course;
                matchedCoursesDiv.appendChild(courseItem);
            });
            console.log('[操作成功] 更新匹配成功的课程列表完成');
        }
    }

    // 点击提交按钮
    function clickSubmitButton() {
        const button = document.querySelector('#submitButton'); // 在主页面上下文查找提交按钮
        if (button) {
            console.log('[操作成功] 找到提交按钮,正在尝试使用 dispatchEvent 提交...');
            const event = new MouseEvent('click', {
                bubbles: true,
                cancelable: true,
                view: window
            });
            button.dispatchEvent(event); // 使用 dispatchEvent 触发事件
            console.log('[操作成功] 使用 dispatchEvent 提交课程');
        } else {
            console.warn('[警告] 未找到提交按钮,请检查选择器是否正确');
        }
    }

    // 检查并选中课程
    async function checkAndSelectCourses() {
        console.log('[操作] 开始检查课程...');
        const iframeDoc = document.querySelector('#ifra')?.contentDocument;
        if (!iframeDoc) {
            console.error('[错误] 无法获取 iframe 文档');
            return;
        }

        if (targetCourses.length === 0) {
            console.log('[操作完成] 所有课程已处理,尝试提交...');
            clickSubmitButton();
            stopScript();
            return;
        }

        const courseCode = targetCourses[0]; // 获取第一个课程码
        const rows = iframeDoc.querySelectorAll('tr');
        console.log(`[调试] 正在匹配课程代码: ${courseCode},总共找到 ${rows.length} 行课程数据`);

        let matched = false;

        rows.forEach((row) => {
            const courseCells = row.querySelectorAll('td[rowspan]'); // 匹配所有具有 rowspan 属性的单元格
            courseCells.forEach((courseCell) => {
                const cellText = courseCell.textContent.trim();
                const cellNumber = cellText.match(/\d+/g)?.join('') || '';
                console.log(`[调试] 检查单元格内容: ${cellText}, 提取的数字: ${cellNumber}`);

                if (cellNumber === courseCode) {
                    matched = true;
                    console.log(`[匹配成功] 课程代码: ${courseCode}, 单元格内容: ${cellText}`);

                    const checkbox = row.querySelector(`input[type="checkbox"]`);
                    if (checkbox && !checkbox.checked) {
                        checkbox.click();
                        console.log(`[操作成功] 已勾选课程: ${courseCode}`);
                    }
                }
            });
        });

        if (matched) {
            console.log(`[操作完成] 已处理课程: ${courseCode}`);
            matchedCourses.push(courseCode);
            updateMatchedCourses();
            targetCourses.shift(); // 移除已处理的课程码
        } else {
            console.warn(`[警告] 未匹配到课程代码: ${courseCode}`);
        }
    }

    // 启动脚本
    function startScript() {
        console.log('[操作] 启动脚本...');
        if (targetCourses.length === 0) {
            alert('[错误] 请先添加课程');
            return;
        }

        timer = setInterval(checkAndSelectCourses, 1000);
        document.getElementById('startScript').disabled = true;
        document.getElementById('stopScript').disabled = false;
        console.log('[操作成功] 脚本已启动');
    }

    // 停止脚本
    function stopScript() {
        console.log('[操作] 停止脚本...');
        clearInterval(timer);
        timer = null;

        document.getElementById('startScript').disabled = false;
        document.getElementById('stopScript').disabled = true;
        console.log('[操作成功] 脚本已停止');
    }

    // 初始化脚本
    window.addEventListener('load', createUI);
})();