齐齐哈尔大学抢课

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

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==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);
})();