Greasy Fork

Greasy Fork is available in English.

重庆高等教育智慧教育平台学习助手 || cqooc重庆高等教育智慧教育平台学习助手 || www.cqooc.com

1.看说明就行了。2.反对任何形式牟利,祝各位同学学有所成。3.更新了作业测验作答

当前为 2024-12-28 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         重庆高等教育智慧教育平台学习助手 || cqooc重庆高等教育智慧教育平台学习助手 || www.cqooc.com
// @namespace    http://tampermonkey.net/
// @version      3.2
// @description  1.看说明就行了。2.反对任何形式牟利,祝各位同学学有所成。3.更新了作业测验作答
// @author       Abstract
// @include      https://*.cqooc.com/*
// @grant        none
// @run-at       document-end
// @require      https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';



    let currentTimeout = null;
    let currentInterval = null;
    let pageInitialized = false;
    let pptTimeoutId = null;

    let currentPlayingVideo = null;
    let coursewareQueue = [];
    let isProcessing = false;

    let pptTaskId = null;

    let currentQueueName = null;
    let isQueueProcessing = false;


    const completionStatuses = {
        '未完成': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGPC/xhBQAACklpQ0NQc1JHQiBJRUM2MTk2Ni0yLjEAAEiJnVN3WJP3Fj7f92UPVkLY8LGXbIEAIiOsCMgQWaIQkgBhhBASQMWFiApWFBURnEhVxILVCkidiOKgKLhnQYqIWotVXDjuH9yntX167+3t+9f7vOec5/zOec8PgBESJpHmomoAOVKFPDrYH49PSMTJvYACFUjgBCAQ5svCZwXFAADwA3l4fnSwP/wBr28AAgBw1S4kEsfh/4O6UCZXACCRAOAiEucLAZBSAMguVMgUAMgYALBTs2QKAJQAAGx5fEIiAKoNAOz0ST4FANipk9wXANiiHKkIAI0BAJkoRyQCQLsAYFWBUiwCwMIAoKxAIi4EwK4BgFm2MkcCgL0FAHaOWJAPQGAAgJlCLMwAIDgCAEMeE80DIEwDoDDSv+CpX3CFuEgBAMDLlc2XS9IzFLiV0Bp38vDg4iHiwmyxQmEXKRBmCeQinJebIxNI5wNMzgwAABr50cH+OD+Q5+bk4eZm52zv9MWi/mvwbyI+IfHf/ryMAgQAEE7P79pf5eXWA3DHAbB1v2upWwDaVgBo3/ldM9sJoFoK0Hr5i3k4/EAenqFQyDwdHAoLC+0lYqG9MOOLPv8z4W/gi372/EAe/tt68ABxmkCZrcCjg/1xYW52rlKO58sEQjFu9+cj/seFf/2OKdHiNLFcLBWK8ViJuFAiTcd5uVKRRCHJleIS6X8y8R+W/QmTdw0ArIZPwE62B7XLbMB+7gECiw5Y0nYAQH7zLYwaC5EAEGc0Mnn3AACTv/mPQCsBAM2XpOMAALzoGFyolBdMxggAAESggSqwQQcMwRSswA6cwR28wBcCYQZEQAwkwDwQQgbkgBwKoRiWQRlUwDrYBLWwAxqgEZrhELTBMTgN5+ASXIHrcBcGYBiewhi8hgkEQcgIE2EhOogRYo7YIs4IF5mOBCJhSDSSgKQg6YgUUSLFyHKkAqlCapFdSCPyLXIUOY1cQPqQ28ggMor8irxHMZSBslED1AJ1QLmoHxqKxqBz0XQ0D12AlqJr0Rq0Hj2AtqKn0UvodXQAfYqOY4DRMQ5mjNlhXIyHRWCJWBomxxZj5Vg1Vo81Yx1YN3YVG8CeYe8IJAKLgBPsCF6EEMJsgpCQR1hMWEOoJewjtBK6CFcJg4Qxwicik6hPtCV6EvnEeGI6sZBYRqwm7iEeIZ4lXicOE1+TSCQOyZLkTgohJZAySQtJa0jbSC2kU6Q+0hBpnEwm65Btyd7kCLKArCCXkbeQD5BPkvvJw+S3FDrFiOJMCaIkUqSUEko1ZT/lBKWfMkKZoKpRzame1AiqiDqfWkltoHZQL1OHqRM0dZolzZsWQ8ukLaPV0JppZ2n3aC/pdLoJ3YMeRZfQl9Jr6Afp5+mD9HcMDYYNg8dIYigZaxl7GacYtxkvmUymBdOXmchUMNcyG5lnmA+Yb1VYKvYqfBWRyhKVOpVWlX6V56pUVXNVP9V5qgtUq1UPq15WfaZGVbNQ46kJ1Bar1akdVbupNq7OUndSj1DPUV+jvl/9gvpjDbKGhUaghkijVGO3xhmNIRbGMmXxWELWclYD6yxrmE1iW7L57Ex2Bfsbdi97TFNDc6pmrGaRZp3mcc0BDsax4PA52ZxKziHODc57LQMtPy2x1mqtZq1+rTfaetq+2mLtcu0W7eva73VwnUCdLJ31Om0693UJuja6UbqFutt1z+o+02PreekJ9cr1Dund0Uf1bfSj9Rfq79bv0R83MDQINpAZbDE4Y/DMkGPoa5hpuNHwhOGoEctoupHEaKPRSaMnuCbuh2fjNXgXPmasbxxirDTeZdxrPGFiaTLbpMSkxeS+Kc2Ua5pmutG003TMzMgs3KzYrMnsjjnVnGueYb7ZvNv8jYWlRZzFSos2i8eW2pZ8ywWWTZb3rJhWPlZ5VvVW16xJ1lzrLOtt1ldsUBtXmwybOpvLtqitm63Edptt3xTiFI8p0in1U27aMez87ArsmuwG7Tn2YfYl9m32zx3MHBId1jt0O3xydHXMdmxwvOuk4TTDqcSpw+lXZxtnoXOd8zUXpkuQyxKXdpcXU22niqdun3rLleUa7rrStdP1o5u7m9yt2W3U3cw9xX2r+00umxvJXcM970H08PdY4nHM452nm6fC85DnL152Xlle+70eT7OcJp7WMG3I28Rb4L3Le2A6Pj1l+s7pAz7GPgKfep+Hvqa+It89viN+1n6Zfgf8nvs7+sv9j/i/4XnyFvFOBWABwQHlAb2BGoGzA2sDHwSZBKUHNQWNBbsGLww+FUIMCQ1ZH3KTb8AX8hv5YzPcZyya0RXKCJ0VWhv6MMwmTB7WEY6GzwjfEH5vpvlM6cy2CIjgR2yIuB9pGZkX+X0UKSoyqi7qUbRTdHF09yzWrORZ+2e9jvGPqYy5O9tqtnJ2Z6xqbFJsY+ybuIC4qriBeIf4RfGXEnQTJAntieTE2MQ9ieNzAudsmjOc5JpUlnRjruXcorkX5unOy553PFk1WZB8OIWYEpeyP+WDIEJQLxhP5aduTR0T8oSbhU9FvqKNolGxt7hKPJLmnVaV9jjdO31D+miGT0Z1xjMJT1IreZEZkrkj801WRNberM/ZcdktOZSclJyjUg1plrQr1zC3KLdPZisrkw3keeZtyhuTh8r35CP5c/PbFWyFTNGjtFKuUA4WTC+oK3hbGFt4uEi9SFrUM99m/ur5IwuCFny9kLBQuLCz2Lh4WfHgIr9FuxYji1MXdy4xXVK6ZHhp8NJ9y2jLspb9UOJYUlXyannc8o5Sg9KlpUMrglc0lamUycturvRauWMVYZVkVe9ql9VbVn8qF5VfrHCsqK74sEa45uJXTl/VfPV5bdra3kq3yu3rSOuk626s91m/r0q9akHV0IbwDa0b8Y3lG19tSt50oXpq9Y7NtM3KzQM1YTXtW8y2rNvyoTaj9nqdf13LVv2tq7e+2Sba1r/dd3vzDoMdFTve75TsvLUreFdrvUV99W7S7oLdjxpiG7q/5n7duEd3T8Wej3ulewf2Re/ranRvbNyvv7+yCW1SNo0eSDpw5ZuAb9qb7Zp3tXBaKg7CQeXBJ9+mfHvjUOihzsPcw83fmX+39QjrSHkr0jq/dawto22gPaG97+iMo50dXh1Hvrf/fu8x42N1xzWPV56gnSg98fnkgpPjp2Snnp1OPz3Umdx590z8mWtdUV29Z0PPnj8XdO5Mt1/3yfPe549d8Lxw9CL3Ytslt0utPa49R35w/eFIr1tv62X3y+1XPK509E3rO9Hv03/6asDVc9f41y5dn3m978bsG7duJt0cuCW69fh29u0XdwruTNxdeo94r/y+2v3qB/oP6n+0/rFlwG3g+GDAYM/DWQ/vDgmHnv6U/9OH4dJHzEfVI0YjjY+dHx8bDRq98mTOk+GnsqcTz8p+Vv9563Or59/94vtLz1j82PAL+YvPv655qfNy76uprzrHI8cfvM55PfGm/K3O233vuO+638e9H5ko/ED+UPPR+mPHp9BP9z7nfP78L/eE8/stRzjPAAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAJcEhZcwAACxMAAAsTAQCanBgAAADXSURBVBiVjZA7agJRAEXPewHRZViMC5AYZGxN5Sc7mPRJESJoO2JjYdDO2YidWEgI5qMbkIC7mFFHvTYTCBohp7yc5h4jCYBcu3QHPBljbgAkfQL9ZfttRDLg+G63Fnh6/f5QvIsV72JNlzNVh54c3+1IAsd36/XgXuEm0inhJlIt8OT4bsUCjdbtI5lUmlMyqTTN8gPAs72ytlDM5s+kH4rZPMaYawvoogUkX7H7w2E+Wy0uiu+rBZLmFuj3xkOi7fpMCrcRL5MAYPDvPOaP4IWk79fv4Eft841qprSDGwAAAABJRU5ErkJggg==',
        '半完成': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAbVJREFUSEu9ls8rRFEUx7/nzsjvjWQxSSTPJE1Zv0nUjEiIhRQbxQKTUiSr914pK6mJFWUjlqL8ysbCrJWVIWUh/wBF4R3d18w0zMwzi7nztu/7zuee7zn3nEdweQJGV/2H+BqCzf0gNAPwJeQvYDxC0EmZ7T26ta6ec4WhbC9aDd3HBIsZkwB73A4B0DcRdolhxK3Yy19tBqDV0AcZ2GNwtVd4EPJ3IuzvRLvPj7rqWnSshbPyCPRKwETcih2nC34BWszgPGBvgCFk0OWeOTTU1P8KqJl67oQINiAWHszraFKUAsiT28SHBBKLoRlM6+NZA7kC5BcEWzANJzNxAI7nwJ20ZSk8mzO41P4LcBiOXX5ZEwegmfo2M09JW7bG1lxrmg/ASYRo596MTZNsxXd8PnmF8JxH9jM8/0vLFyC7qxwljaRZwTm27c3etm5ER1fdOzJPi1IFFiJCmqGfMrhvfcTAQKCnsADQGWmmHmdm7SJygKbahsICiO4l4JWZq25WLlFZWlFowFtRAIotUl5k1W2q/KIpHxVFGXYJiLpxnbxdShdOEqJ0ZaZB1C399GFUiN+WH16q+w/WuLNCAAAAAElFTkSuQmCC',
        '已完成': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAfhJREFUSEu9lj1oE2EYx//PqaDYDJHaQlCoH7k4dVYuUMFFERSHQIeCUcxiih/QpXS4u9Gp9MNJwSWC4CAKKgiClgSLg4hkMIkBISFrhwhKPu4p7zWXz7vLXWjMmPd5/r/3+XyP4PKbVS+e+Cc1rsPgqyCcARBqmVfAKEKit4eNg69/6J/KTjJkdxBRlRATdGbcAviA2yUAahLhGTHUnJ6p9NsOACKqco2BFIMD7sK9pwSqErCQ0zNvuk96AGEteg8wVsGQ/Ii3bQkGID0saOl16782QNzcIH41snhH0ZCYbliRmAAz58BPv2lxLqyZrnOiJiZA1pQnzHxnpLQ4OBHR07yWSZBoxb+o/x7eLX7x1DyCQzMk69EkG8amX3cv9iRJiySryjsGX/Hi0G8zHZhEeOo00sWvtu4Eek+ypuSYWfYLOHv8FFLxDRw7GsSltRhKOwMzBiLKC0CVmSf8ALrFPxe+IPF8yT4Coj+ugNsX5vGtlMX3crYt0C9+98Uy6s26K8A2RSeDIXy8/xK1Rg1CZOvXNvyIC+JeilyKvHL5AW6ej5mQRx8eIzkXN3Mu0uJ2885QiyIPaVMLYjl5FTcjEG3qZdAsiB9xscbNQfO6KkRN7FrRcR9Zq+K/LLsWZHzr2gpzrA+OBRnrk9kFGd+j390V+/HZsgvSIhcecicecAAAAABJRU5ErkJggg=='
    };

    const MAIN_PAGE_HOST = 'www.cqooc.com';
    const IFRAME_PAGE_HOST = 'preview.cqooc.com';

    let isProcessingQueue = false;

    let coursewareQueues = {
        '默认未完成队列': {
            items: [],
            interval: 240000
        }
    };


    const categoryKeywords = {
        '测验': ['测验', '测试'],
        '课件': ['课件', '小节', '视频'],
        '作业': ['作业'],
        '讨论': ['讨论', '答疑'],
        '考试': ['考试', '期末测试', '补考'],
        '其他': []
    };

  
    let processedItems = new Set();

 
    function simulateClick(element) {
        if (!element) return;
        const event = new MouseEvent('click', {
            view: window,
            bubbles: true,
            cancelable: true
        });
        element.dispatchEvent(event);
    }

  
    async function expandAllParentsAsync(element) {
        const parents = [];
        let parent = element.parentElement;

        while (parent && parent !== document.body) {
            if (parent.classList.contains('second-level-inner-box') || parent.classList.contains('first-level-inner-box')) {
                parents.push(parent);
            }
            parent = parent.parentElement;
        }

        parents.reverse();

        for (const parent of parents) {
            const toggleButton = parent.previousElementSibling && parent.previousElementSibling.querySelector('.right-icon > i.anticon-down');
            if (toggleButton) {
                const innerBox = parent;
                const height = window.getComputedStyle(innerBox).height;
                if (height === '0px') {
                    simulateClick(toggleButton);
                    await new Promise(resolve => setTimeout(resolve, 500));
                }
            }
        }
    }

    function waitForElement(selector, timeout) {
        return new Promise(resolve => {
            const startTime = Date.now();

            const interval = setInterval(() => {
                const element = document.querySelector(selector);
                if (element) {
                    clearInterval(interval);
                    resolve(element);
                } else if (Date.now() - startTime > timeout) {
                    clearInterval(interval);
                    resolve(null);
                }
            }, 100);
        });
    }

    async function jumpToContentItem(originalElement) {
        return new Promise(async (resolve, reject) => {
            try {
                let targetElement = originalElement;
                if (!document.body.contains(originalElement)) {
                    const title = originalElement.querySelector('p.title')?.textContent.trim();
                    if (title) {
                        targetElement = Array.from(document.querySelectorAll('.third-level-inner-box'))
                            .find(el => el.querySelector('p.title')?.textContent.trim() === title);
                    }
                    if (!targetElement) {
                        throw new Error('找不到目标元素');
                    }
                }

                await expandAllParentsAsync(targetElement);
                const clickable = targetElement.querySelector('a') ||
                      targetElement.querySelector('p.title') ||
                      targetElement;
                if (!clickable) {
                    throw new Error('未找到可点击的元素');
                }

                clickable.scrollIntoView({ behavior: 'smooth', block: 'center' });
                setTimeout(() => {
                    simulateClick(clickable);
                    resolve();
                }, 500);

            } catch (error) {
                console.error('跳转失败:', error);
                reject(error);
            }
        });
    }


    async function performBatchAutoReply(data, progressLabel) {
        let repliedCount = 0;
        for (const item of data.items) {
            try {
                await performAutoReply(item);
                repliedCount++;
                updateReplyProgress(data, progressLabel, repliedCount);
            } catch (error) {
                console.error('一键回复失败:', error);
            }
        }
    }


    async function performAutoReply(itemData) {
        try {
            await jumpToContentItem(itemData.originalElement);
            const discussionArea = await waitForElement('.course-courseQaDiscussion-qa', 5000);
            if (!discussionArea) return;

            const replyButton = discussionArea.querySelector('.conv-option .reply');
            if (!replyButton) return;

            replyButton.click();

            const replyInput = await waitForElement('.course-courseQaDiscussion-reply textarea.ant-input', 2000);
            const submitButton = await waitForElement('.course-courseQaDiscussion-reply .ant-btn-primary', 2000);
            const firstReply = discussionArea.querySelector('.conv-subtitle');

            if (replyInput && submitButton && firstReply) {
                replyInput.value = firstReply.textContent.trim();
                replyInput.dispatchEvent(new Event('input', { bubbles: true }));
                submitButton.click();


                itemData.replyStatus = '已回复';
                itemData.replyStatusElement.textContent = '已回复';
                itemData.replyStatusElement.style.color = 'green';

                console.log('自动回复完成');
            }
        } catch (error) {
            console.error('自动回复失败:', error);
        }
    }

    function updateReplyProgress(data, progressLabel, repliedCount = null) {
        if (repliedCount === null) {
            repliedCount = data.items.filter(item => item.replyStatus === '已回复').length;
        }
        progressLabel.textContent = `已回复:${repliedCount}/${data.items.length}`;
    }

    async function collectTestAttempts(data, progressLabel) {
        let processedCount = 0;
        for (const itemData of data.items) {
            try {
                await jumpToContentItem(itemData.originalElement);
                const attemptInfo = await getTestAttemptInfo();
                const timeInfo = await getTestTimeInfo();

                updateTestItemWithAttemptInfo(itemData, attemptInfo, timeInfo);

                processedCount++;
                progressLabel.textContent = `已获取:${processedCount}/${data.items.length}`;
                await new Promise(resolve => setTimeout(resolve, 500));

            } catch (error) {
                console.error('获取测验信息失败:', error);
            }
        }
    }

    async function getTestAttemptInfo() {
        return new Promise((resolve, reject) => {
            const timeout = 3000;
            const startTime = Date.now();

            const interval = setInterval(() => {
                const attemptElements = document.querySelectorAll('.list-content-text p');
                for (const p of attemptElements) {
                    if (p.textContent.includes('已作答/可作答次数')) {
                        const span = p.querySelector('span');
                        if (span) {
                            clearInterval(interval);
                            resolve(span.textContent.trim());
                            return;
                        }
                    }
                }

                if (Date.now() - startTime > timeout) {
                    clearInterval(interval);
                    reject('获取作答信息超时');
                }
            }, 100);
        });
    }

    async function getTestTimeInfo() {
        return new Promise((resolve, reject) => {
            const timeout = 3000;
            const startTime = Date.now();

            const interval = setInterval(() => {
                const timeElements = document.querySelectorAll('.list-content-text p');
                for (const p of timeElements) {
                    if (p.textContent.includes('开始至截止时间:')) {
                        const span = p.querySelector('span');
                        if (span) {
                            clearInterval(interval);
                            resolve(span.textContent.trim());
                            return;
                        }
                    }
                }

                if (Date.now() - startTime > timeout) {
                    clearInterval(interval);
                    reject('获取开始至截止时间超时');
                }
            }, 100);
        });
    }

    function updateTestItemWithAttemptInfo(itemData, attemptInfo, timeInfo) {
        if (itemData.taskNameElement) {
            const infoContainer = document.createElement('div');
            infoContainer.style.display = 'flex';
            infoContainer.style.flexDirection = 'column';
            infoContainer.style.marginLeft = '10px';

            const attemptLabel = document.createElement('span');
            attemptLabel.textContent = `作答信息:${attemptInfo}`;
            attemptLabel.style.color = 'blue';
            infoContainer.appendChild(attemptLabel);

            const timeLabel = document.createElement('span');
            timeLabel.textContent = `时间:${timeInfo}`;
            timeLabel.style.color = 'green';
            infoContainer.appendChild(timeLabel);

            itemData.taskNameElement.parentElement.appendChild(infoContainer);
        }
    }

    async function collectAssignmentInfo(data, progressLabel) {
        let processedCount = 0;
        for (const itemData of data.items) {
            try {
                await jumpToContentItem(itemData.originalElement);
                const attemptInfo = await getAssignmentAttemptInfo();
                const timeInfo = await getAssignmentTimeInfo();

                updateAssignmentItemWithInfo(itemData, attemptInfo, timeInfo);

                processedCount++;
                progressLabel.textContent = `已获取:${processedCount}/${data.items.length}`;
                await new Promise(resolve => setTimeout(resolve, 100));
            } catch (error) {
                console.error('获取作业信息失败:', error);
            }
        }
    }

async function getAssignmentAttemptInfo() {
    return new Promise((resolve, reject) => {
        const timeout = 3000;
        const startTime = Date.now();

        const interval = setInterval(() => {
            const attemptElement = Array.from(document.querySelectorAll('.list-content-text p'))
                .find(p => p.textContent.includes('已作答/可作答次数'))
                ?.querySelector('span');

            if (attemptElement) {
                clearInterval(interval);
                resolve(attemptElement.textContent.trim());
                return;
            }

            if (Date.now() - startTime > timeout) {
                clearInterval(interval);
                reject('获取作答次数超时');
            }
        }, 100);
    });
}


    async function getAssignmentTimeInfo() {
        return new Promise((resolve, reject) => {
            const timeout = 3000;
            const startTime = Date.now();

            const interval = setInterval(() => {
                const timeElement = Array.from(document.querySelectorAll('.list-content-text p'))
                .find(p => p.textContent.includes('开始至截止时间:'))?.querySelector('span');

                if (timeElement) {
                    clearInterval(interval);
                    resolve(timeElement.textContent.trim());
                }

                if (Date.now() - startTime > timeout) {
                    clearInterval(interval);
                    reject('获取开始至截止时间超时');
                }
            }, 100);
        });
    }

    function updateAssignmentItemWithInfo(itemData, attemptInfo, timeInfo) {
        if (itemData.taskNameElement) {
            const infoContainer = document.createElement('div');
            infoContainer.style.display = 'flex';
            infoContainer.style.flexDirection = 'column';
            infoContainer.style.marginLeft = '10px';

            const attemptLabel = document.createElement('span');
            attemptLabel.textContent = `作答信息:${attemptInfo}`;
            attemptLabel.style.color = 'blue';
            infoContainer.appendChild(attemptLabel);

            const timeLabel = document.createElement('span');
            timeLabel.textContent = `时间:${timeInfo}`;
            timeLabel.style.color = 'green';
            infoContainer.appendChild(timeLabel);

            itemData.taskNameElement.parentElement.appendChild(infoContainer);
        }
    }


    function isVideoCompleted(coursewareElement) {
        let video = coursewareElement.querySelector('#dplayer video') || coursewareElement.querySelector('video');
        if (video) {
            const progress = (video.currentTime / video.duration) * 100;
            return progress >= 100;
        }
        return false;
    }

    function isPptCompleted(coursewareElement) {
        if (!coursewareElement) return false;
        if (coursewareElement.dataset.pptCompleted === 'true') return true;

        const completeIcon = coursewareElement.querySelector('img.file-complete');
        if (completeIcon) {
            const src = completeIcon.getAttribute('src');
            return src.includes(completionStatuses['已完成']);
        }
        return false;
    }


    function categorizeItems(items) {
        const categories = {};

        items.forEach(item => {
            if (processedItems.has(item)) return;

            const titleElement = item.querySelector('p.title, p.title-big');
            if (!titleElement) return;
            const titleText = titleElement.textContent.trim();

            let matchedCategory = '其他';
            for (const [category, keywords] of Object.entries(categoryKeywords)) {
                if (keywords.some(keyword => titleText.includes(keyword))) {
                    matchedCategory = category;
                    break;
                }
            }

            const itemData = {
                element: item.cloneNode(true),
                originalElement: item,
                title: titleText,
                replyStatus: '未回复'
            };

            if (matchedCategory === '课件') {
                let status = '未完成';
                const img = item.querySelector('img.file-complete');
                if (img) {
                    const src = img.getAttribute('src');
                    if (src === completionStatuses['已完成']) {
                        status = '已完成';
                    } else if (src === completionStatuses['半完成']) {
                        status = '半完成';
                    } else if (src === completionStatuses['未完成']) {
                        status = '未完成';
                    } else {
                        // 如果无法匹配到已知的图标,默认未完成
                        status = '未完成';
                    }
                }


                itemData.status = status;


                if (status === '未完成' || status === '半完成') {
                    coursewareQueues['默认未完成队列'].items.push(itemData);
                }
            }

            if (!categories[matchedCategory]) {
                categories[matchedCategory] = { items: [], completed: 0, halfCompleted: 0, total: 0 };
            }

            categories[matchedCategory].items.push(itemData);
            if (matchedCategory === '课件') {
                categories[matchedCategory].total += 1;
                if (itemData.status === '已完成') {
                    categories[matchedCategory].completed += 1;
                } else if (itemData.status === '半完成') {
                    categories[matchedCategory].halfCompleted += 1;
                }
            }

            processedItems.add(item);
        });

        return categories;
    }

    async function waitForContentLoaded(maxRetries = 40, intervalTime = 500) {
        return new Promise((resolve) => {
            let retries = 0;
            const interval = setInterval(() => {
                const items = document.querySelectorAll('.third-level-inner-box');
                if (items.length > 0 || retries >= maxRetries) {
                    clearInterval(interval);
                    resolve();
                }
                retries++;
            }, intervalTime);
        });
    }

    function createDisplayPanel() {
        if (document.getElementById('custom-display-container')) return document.getElementById('custom-display-container').querySelector('.panel-content');

        const displayContainer = document.createElement('div');
        displayContainer.id = 'custom-display-container';
        displayContainer.style.position = 'fixed';
        displayContainer.style.top = '10%';
        displayContainer.style.left = '10%';
        displayContainer.style.width = '500px';
        displayContainer.style.height = '600px';
        displayContainer.style.overflow = 'auto';
        displayContainer.style.backgroundColor = '#fff';
        displayContainer.style.border = '1px solid #ccc';
        displayContainer.style.borderRadius = '8px';
        displayContainer.style.boxShadow = '0 2px 8px rgba(0,0,0,0.2)';
        displayContainer.style.zIndex = '10000';
        displayContainer.style.display = 'block';

        const panelHeader = document.createElement('div');
        panelHeader.className = 'panel-header';
        panelHeader.style.backgroundColor = '#007bff';
        panelHeader.style.color = '#fff';
        panelHeader.style.padding = '10px';
        panelHeader.style.cursor = 'move';
        panelHeader.style.fontSize = '16px';
        panelHeader.style.fontWeight = 'bold';
        panelHeader.style.position = 'relative';
        panelHeader.textContent = '反馈群:1006332809  || Written by Abstract😉';

        const minimizeButton = document.createElement('button');
        minimizeButton.textContent = '—';
        minimizeButton.title = '最小化';
        minimizeButton.style.position = 'absolute';
        minimizeButton.style.top = '5px';
        minimizeButton.style.right = '10px';
        minimizeButton.style.background = 'transparent';
        minimizeButton.style.border = 'none';
        minimizeButton.style.color = '#fff';
        minimizeButton.style.fontSize = '18px';
        minimizeButton.style.cursor = 'pointer';

        minimizeButton.addEventListener('click', () => {
            displayContainer.style.display = 'none';
            restoreButton.style.display = 'block';
        });

        panelHeader.appendChild(minimizeButton);

        const panelContent = document.createElement('div');
        panelContent.className = 'panel-content';
        panelContent.style.padding = '10px';


        const instructionsDiv = document.createElement('div');
        instructionsDiv.style.marginBottom = '10px';
        instructionsDiv.style.padding = '10px';
        instructionsDiv.style.border = '1px solid #eee';
        instructionsDiv.style.borderRadius = '5px';
        instructionsDiv.style.backgroundColor = '#f9f9f9';
        instructionsDiv.innerHTML = `
            <strong><b>说明:***---  注意课件切换时间是固定的哦 ---***</b></strong><br>
            1. 页面需保持可见,不可最小化(意思是窗口可最小,但是页面不能缩没)<br>
            2. 使用定时切换和自定义任务队列对抗干扰因素&提高灵活性,比如说,最下面你可以设置课件切换间隔为1min创建队列,然后把所有ppt课件添加进去,也可以开3倍速设置个6分钟创建队列(具体看这个时长能不能覆盖完所有的视频,一般18分钟够了),把视频课件添加进去。<br>
            2. 视频倍速默认3x,可在面板中调整<br>
            3. 课件切换默认4分钟,可调整<br>
            4. 自动化回复取的是评论区第一条,一键回复速度比较快,存在漏回复情况,建议单个回复<br>
            5. 一键自动刷课从默认未完成队列开始(即4分钟切换的那个)<br>
            6. <b>推荐自定义队列使用,先创建队列(设置课件切换时间和名称),然后添加需要执行的课件(选中课件标题后面的白色框框),然后再划到最下面选中目标队列然后添加进去最后执行就行了</b>
        `;
        panelContent.appendChild(instructionsDiv);


        const speedSelectorContainer = document.createElement('div');
        speedSelectorContainer.style.marginTop = '15px';

        const speedLabel = document.createElement('label');
        speedLabel.textContent = '视频倍速: ';
        speedLabel.style.marginRight = '10px';
        speedLabel.style.fontWeight = 'bold';

        const speedSelector = document.createElement('select');
        speedSelector.style.padding = '5px';
        speedSelector.style.borderRadius = '3px';
        speedSelector.style.border = '1px solid #ccc';

        const speeds = [1, 2, 3];
        const storedSpeed = parseFloat(localStorage.getItem('videoPlaybackSpeed')) || 3;
        speeds.forEach(speed => {
            const option = document.createElement('option');
            option.value = speed;
            option.textContent = `${speed}x`;
            if (speed === storedSpeed) option.selected = true;
            speedSelector.appendChild(option);
        });

        speedSelector.addEventListener('change', () => {
            const selectedSpeed = parseFloat(speedSelector.value);
            localStorage.setItem('videoPlaybackSpeed', selectedSpeed);

           
            if (window.videoController && window.videoController.activeVideos) {
                window.videoController.activeVideos.forEach(task => {
                    if (task.video) {
                        task.video.playbackRate = selectedSpeed;
                    }
                });
            }
        });


        speedSelectorContainer.appendChild(speedLabel);
        speedSelectorContainer.appendChild(speedSelector);
        panelContent.appendChild(speedSelectorContainer);


        const intervalContainer = document.createElement('div');
        intervalContainer.style.marginTop = '15px';

        const intervalLabel = document.createElement('label');
        intervalLabel.textContent = '课件切换的间隔时间(秒): ';
        intervalLabel.style.marginRight = '10px';
        intervalLabel.style.fontWeight = 'bold';

        const intervalInput = document.createElement('input');
        intervalInput.type = 'number';
        intervalInput.style.width = '60px';
        intervalInput.value = (coursewareQueues['默认未完成队列'].interval / 1000).toString();
        intervalInput.style.padding = '5px';
        intervalInput.style.borderRadius = '3px';
        intervalInput.style.border = '1px solid #ccc';

        intervalInput.addEventListener('change', () => {
            let val = parseInt(intervalInput.value);
            if (isNaN(val) || val <= 0) {
                val = 240;
            }
            coursewareQueues['默认未完成队列'].interval = val * 1000;
            localStorage.setItem('autoInterval', coursewareQueues['默认未完成队列'].interval);
        });

        intervalContainer.appendChild(intervalLabel);
        intervalContainer.appendChild(intervalInput);
        panelContent.appendChild(intervalContainer);


        const restoreButton = document.createElement('button');
        restoreButton.id = 'restore-button';
        restoreButton.textContent = 'Be yourself and Dream bigger😉';
        restoreButton.style.position = 'fixed';
        restoreButton.style.bottom = '20px';
        restoreButton.style.left = '20px';
        restoreButton.style.zIndex = '10001';
        restoreButton.style.padding = '10px 20px';
        restoreButton.style.backgroundColor = '#007bff';
        restoreButton.style.color = '#fff';
        restoreButton.style.border = 'none';
        restoreButton.style.borderRadius = '5px';
        restoreButton.style.cursor = 'pointer';
        restoreButton.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';
        restoreButton.style.display = 'none';

        restoreButton.addEventListener('click', () => {
            displayContainer.style.display = 'block';
            restoreButton.style.display = 'none';
        });

        document.body.appendChild(restoreButton);

        displayContainer.appendChild(panelHeader);
        displayContainer.appendChild(panelContent);
        document.body.appendChild(displayContainer);

        makeElementDraggable(displayContainer);

        return panelContent;
    }

    function makeElementDraggable(elmnt) {
        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
        const header = elmnt.querySelector(".panel-header");
        if (header) {
            header.style.cursor = 'move';
            header.onmousedown = dragMouseDown;
        }

        function dragMouseDown(e) {
            e = e || window.event;
            e.preventDefault();
            pos3 = e.clientX;
            pos4 = e.clientY;
            document.onmouseup = closeDragElement;
            document.onmousemove = elementDrag;
        }

        function elementDrag(e) {
            e = e || window.event;
            e.preventDefault();
            pos1 = pos3 - e.clientX;
            pos2 = pos4 - e.clientY;
            pos3 = e.clientX;
            pos4 = e.clientY;
            let newTop = elmnt.offsetTop - pos2;
            let newLeft = elmnt.offsetLeft - pos1;

            const windowWidth = window.innerWidth;
            const windowHeight = window.innerHeight;
            const elemWidth = elmnt.offsetWidth;
            const elemHeight = elmnt.offsetHeight;

            if (newTop < 0) newTop = 0;
            if (newLeft < 0) newLeft = 0;
            if (newTop + elemHeight > windowHeight) newTop = windowHeight - elemHeight;
            if (newLeft + elemWidth > windowWidth) newLeft = windowWidth - elemWidth;

            elmnt.style.top = newTop + "px";
            elmnt.style.left = newLeft + "px";
        }

        function closeDragElement() {
            document.onmouseup = null;
            document.onmousemove = null;
        }
    }

    function populatePanel(panelContent, categories) {

        const autoButton = document.createElement('button');
        autoButton.textContent = '一键自动刷课(默认未完成队列)';
        autoButton.style.width = '100%';
        autoButton.style.padding = '10px';
        autoButton.style.marginBottom = '15px';
        autoButton.style.backgroundColor = '#28a745';
        autoButton.style.color = '#fff';
        autoButton.style.border = 'none';
        autoButton.style.borderRadius = '5px';
        autoButton.style.cursor = 'pointer';
        autoButton.style.fontSize = '16px';
        autoButton.style.zIndex = '10001';

        autoButton.addEventListener('click', async () => {
            if (isQueueProcessing) {
                alert('已有队列在执行,请稍后。');
                return;
            }
            currentQueueName = '默认未完成队列';
            await startQueueProcessing(currentQueueName);
        });

        panelContent.appendChild(autoButton);


        if (categories['讨论'] && categories['讨论'].items.length > 0) {
            const data = categories['讨论'];
            const progressLabel = document.createElement('span');
            progressLabel.textContent = `已回复:0/${data.items.length}`;
            progressLabel.style.fontSize = '14px';

            const replyAllButton = document.createElement('button');
            replyAllButton.textContent = '讨论区一键自动回复';
            replyAllButton.style.width = '100%';
            replyAllButton.style.padding = '10px';
            replyAllButton.style.marginBottom = '5px';
            replyAllButton.style.backgroundColor = '#4caf50';
            replyAllButton.style.color = '#fff';
            replyAllButton.style.border = 'none';
            replyAllButton.style.borderRadius = '5px';
            replyAllButton.style.cursor = 'pointer';
            replyAllButton.style.fontSize = '14px';

            replyAllButton.addEventListener('click', async () => {
                await performBatchAutoReply(data, progressLabel);
            });

            panelContent.appendChild(replyAllButton);
            panelContent.appendChild(progressLabel);
        }


        if (categories['测验'] && categories['测验'].items.length > 0) {
            const data = categories['测验'];
            const testProgress = document.createElement('span');
            testProgress.textContent = `已获取:0/${data.items.length}`;
            testProgress.style.fontSize = '14px';

            const getInfoButton = document.createElement('button');
            getInfoButton.textContent = '获取测验作答信息';
            getInfoButton.style.width = '100%';
            getInfoButton.style.padding = '10px';
            getInfoButton.style.marginBottom = '5px';
            getInfoButton.style.backgroundColor = '#17a2b8';
            getInfoButton.style.color = '#fff';
            getInfoButton.style.border = 'none';
            getInfoButton.style.borderRadius = '5px';
            getInfoButton.style.cursor = 'pointer';
            getInfoButton.style.fontSize = '14px';

            getInfoButton.addEventListener('click', () => {
                collectTestAttempts(data, testProgress);
            });

            panelContent.appendChild(getInfoButton);
            panelContent.appendChild(testProgress);
        }


        if (categories['作业'] && categories['作业'].items.length > 0) {
            const data = categories['作业'];
            const assignmentProgress = document.createElement('span');
            assignmentProgress.textContent = `已获取:0/${data.items.length}`;
            assignmentProgress.style.fontSize = '14px';

            const getAssignmentButton = document.createElement('button');
            getAssignmentButton.textContent = '获取作业信息';
            getAssignmentButton.style.width = '100%';
            getAssignmentButton.style.padding = '10px';
            getAssignmentButton.style.marginBottom = '5px';
            getAssignmentButton.style.backgroundColor = '#ffc107';
            getAssignmentButton.style.color = '#fff';
            getAssignmentButton.style.border = 'none';
            getAssignmentButton.style.borderRadius = '5px';
            getAssignmentButton.style.cursor = 'pointer';
            getAssignmentButton.style.fontSize = '14px';

            getAssignmentButton.addEventListener('click', () => {
                collectAssignmentInfo(data, assignmentProgress);
            });

            panelContent.appendChild(getAssignmentButton);
            panelContent.appendChild(assignmentProgress);
        }


        for (const [categoryName, data] of Object.entries(categories)) {
            const categoryPanel = document.createElement('div');
            categoryPanel.className = 'category-panel';
            categoryPanel.style.border = '1px solid #ccc';
            categoryPanel.style.margin = '10px 0';
            categoryPanel.style.borderRadius = '5px';
            categoryPanel.style.overflow = 'hidden';

            const headerContainer = document.createElement('div');
            headerContainer.style.display = 'flex';
            headerContainer.style.justifyContent = 'space-between';
            headerContainer.style.alignItems = 'center';
            headerContainer.style.background = '#f0f0f0';
            headerContainer.style.padding = '10px';
            headerContainer.style.cursor = 'pointer';
            headerContainer.style.fontWeight = 'bold';
            headerContainer.style.fontSize = '14px';

            const header = document.createElement('div');
            if (categoryName === '课件') {
                const progress = `${data.completed}/${data.total}`;
                const halfProgress = data.halfCompleted;
                header.textContent = `课件 (已完成: ${progress}, 半完成: ${halfProgress})`;
            } else {
                header.textContent = `${categoryName} (${data.items.length})`;
            }
            headerContainer.appendChild(header);

            const content = document.createElement('div');
            content.className = 'category-content';
            content.style.display = 'none';
            content.style.padding = '10px';

            data.items.forEach(itemData => {
                const taskItem = document.createElement('div');
                taskItem.className = 'task-item';
                taskItem.style.marginBottom = '5px';
                taskItem.style.display = 'flex';
                taskItem.style.alignItems = 'center';
                taskItem.style.justifyContent = 'space-between';

                const leftContent = document.createElement('div');
                leftContent.style.display = 'flex';
                leftContent.style.alignItems = 'center';
                leftContent.style.flex = '1';


                if (categoryName === '课件') {
                    const statusIcon = document.createElement('img');
                    statusIcon.style.width = '16px';
                    statusIcon.style.height = '16px';
                    statusIcon.style.marginRight = '10px';
                    statusIcon.src = completionStatuses[itemData.status || '未完成'];
                    leftContent.appendChild(statusIcon);
                }

                const taskName = document.createElement('span');
                taskName.textContent = itemData.title;
                leftContent.appendChild(taskName);

                itemData.taskNameElement = taskName;


                if (categoryName === '讨论') {
                    const statusLabel = document.createElement('span');
                    statusLabel.textContent = '未回复';
                    statusLabel.style.marginLeft = '10px';
                    statusLabel.style.color = 'red';
                    statusLabel.className = 'reply-status';
                    itemData.replyStatusElement = statusLabel;
                    leftContent.appendChild(statusLabel);
                }

                const buttonsContainer = document.createElement('div');
                buttonsContainer.style.display = 'flex';
                buttonsContainer.style.gap = '5px';


                const itemJumpButton = document.createElement('button');
                itemJumpButton.textContent = '跳转';
                itemJumpButton.style.padding = '2px 8px';
                itemJumpButton.style.fontSize = '12px';
                itemJumpButton.style.cursor = 'pointer';
                itemJumpButton.style.backgroundColor = '#007bff';
                itemJumpButton.style.color = '#fff';
                itemJumpButton.style.border = 'none';
                itemJumpButton.style.borderRadius = '3px';

                itemJumpButton.addEventListener('click', async (e) => {
                    e.stopPropagation();
                    await jumpToContentItem(itemData.originalElement);
                });
                buttonsContainer.appendChild(itemJumpButton);


                if (categoryName === '讨论') {
                    const itemReplyButton = document.createElement('button');
                    itemReplyButton.textContent = '自动回复';
                    itemReplyButton.style.padding = '2px 8px';
                    itemReplyButton.style.fontSize = '12px';
                    itemReplyButton.style.cursor = 'pointer';
                    itemReplyButton.style.backgroundColor = '#4caf50';
                    itemReplyButton.style.color = '#fff';
                    itemReplyButton.style.border = 'none';
                    itemReplyButton.style.borderRadius = '3px';

                    itemReplyButton.addEventListener('click', async (e) => {
                        e.stopPropagation();
                        await performAutoReply(itemData);
                    });
                    buttonsContainer.appendChild(itemReplyButton);
                }


                if (categoryName === '课件') {
                    const queueCheckbox = document.createElement('input');
                    queueCheckbox.type = 'checkbox';
                    queueCheckbox.title = '选择本课件加入自定义队列';
                    itemData.queueCheckbox = queueCheckbox;
                    buttonsContainer.appendChild(queueCheckbox);
                }

                taskItem.appendChild(leftContent);
                taskItem.appendChild(buttonsContainer);
                content.appendChild(taskItem);
            });

            headerContainer.addEventListener('click', () => {
                content.style.display = content.style.display === 'none' ? 'block' : 'none';
            });

            categoryPanel.appendChild(headerContainer);
            categoryPanel.appendChild(content);

            panelContent.appendChild(categoryPanel);
        }
    }

    function createQueueUI(panelContent, categories) {
        const queueContainer = document.createElement('div');
        queueContainer.style.marginTop = '20px';
        queueContainer.style.borderTop = '1px solid #ddd';
        queueContainer.style.paddingTop = '10px';

        const queueTitle = document.createElement('div');
        queueTitle.textContent = '自定义队列管理(仅课件)';
        queueTitle.style.fontWeight = 'bold';
        queueTitle.style.marginBottom = '10px';
        queueContainer.appendChild(queueTitle);

        const queueList = document.createElement('div');
        queueList.id = 'queue-list';
        queueContainer.appendChild(queueList);

        function renderQueueList() {
            queueList.innerHTML = '';
            for (const [qName, qData] of Object.entries(coursewareQueues)) {
                const qDiv = document.createElement('div');
                qDiv.style.marginBottom = '5px';
                qDiv.style.display = 'flex';
                qDiv.style.alignItems = 'center';
                qDiv.style.justifyContent = 'space-between';

                const qInfo = document.createElement('span');
                qInfo.textContent = `${qName} (任务数: ${qData.items.length}, 间隔: ${qData.interval/1000}s)`;
                qDiv.appendChild(qInfo);

                const runBtn = document.createElement('button');
                runBtn.textContent = '运行队列';
                runBtn.style.fontSize = '12px';
                runBtn.style.padding = '2px 5px';
                runBtn.style.cursor = 'pointer';
                runBtn.style.backgroundColor = '#28a745';
                runBtn.style.color = '#fff';
                runBtn.style.border = 'none';
                runBtn.style.borderRadius = '3px';
                runBtn.addEventListener('click', async () => {
                    if (isQueueProcessing) {
                        alert('已有队列在执行,请稍后。');
                        return;
                    }
                    currentQueueName = qName;
                    await startQueueProcessing(qName);
                });
                qDiv.appendChild(runBtn);

                if (qName !== '默认未完成队列') {
                    const deleteBtn = document.createElement('button');
                    deleteBtn.textContent = '删除队列';
                    deleteBtn.style.fontSize = '12px';
                    deleteBtn.style.padding = '2px 5px';
                    deleteBtn.style.cursor = 'pointer';
                    deleteBtn.style.backgroundColor = '#dc3545';
                    deleteBtn.style.color = '#fff';
                    deleteBtn.style.border = 'none';
                    deleteBtn.style.borderRadius = '3px';
                    deleteBtn.addEventListener('click', () => {
                        delete coursewareQueues[qName];
                        renderQueueList();
                    });
                    qDiv.appendChild(deleteBtn);
                }

                queueList.appendChild(qDiv);
            }
        }

        renderQueueList();

        const createQueueForm = document.createElement('div');
        createQueueForm.style.marginTop = '10px';

        const queueNameInput = document.createElement('input');
        queueNameInput.type = 'text';
        queueNameInput.placeholder = '输入新队列名称';
        queueNameInput.style.marginRight = '10px';
        queueNameInput.style.padding = '5px';

        const queueIntervalInput = document.createElement('input');
        queueIntervalInput.type = 'number';
        queueIntervalInput.placeholder = '间隔(秒)';
        queueIntervalInput.value = 240;
        queueIntervalInput.style.marginRight = '10px';
        queueIntervalInput.style.padding = '5px';
        queueIntervalInput.style.width = '60px';

        const createBtn = document.createElement('button');
        createBtn.textContent = '创建队列';
        createBtn.style.padding = '5px 10px';
        createBtn.style.backgroundColor = '#007bff';
        createBtn.style.color = '#fff';
        createBtn.style.border = 'none';
        createBtn.style.borderRadius = '3px';
        createBtn.style.cursor = 'pointer';

        createBtn.addEventListener('click', () => {
            const qName = queueNameInput.value.trim();
            const qInterval = parseInt(queueIntervalInput.value) * 1000;

            if (!qName) {
                alert('请填写队列名称');
                return;
            }

            if (isNaN(qInterval) || qInterval <= 0) {
                alert('间隔时间无效');
                return;
            }

            if (coursewareQueues[qName]) {
                alert('该队列名称已存在,请换一个。');
                return;
            }

            coursewareQueues[qName] = {
                items: [],
                interval: qInterval
            };

            queueNameInput.value = '';
            queueIntervalInput.value = '240';
            renderQueueList();
            refreshQueueSelect();
        });

        createQueueForm.appendChild(queueNameInput);
        createQueueForm.appendChild(queueIntervalInput);
        createQueueForm.appendChild(createBtn);

        const addToQueueContainer = document.createElement('div');
        addToQueueContainer.style.marginTop = '10px';

        const queueSelect = document.createElement('select');
        function refreshQueueSelect() {
            const selected = queueSelect.value;
            queueSelect.innerHTML = '';
            Object.keys(coursewareQueues).forEach(qName => {
                const opt = document.createElement('option');
                opt.value = qName;
                opt.textContent = qName;
                queueSelect.appendChild(opt);
            });
            if (coursewareQueues[selected]) {
                queueSelect.value = selected;
            }
        }

        refreshQueueSelect();
        queueSelect.style.marginRight = '10px';
        queueSelect.style.padding = '5px';

        const addSelectedBtn = document.createElement('button');
        addSelectedBtn.textContent = '添加选中课件到队列';
        addSelectedBtn.style.padding = '5px 10px';
        addSelectedBtn.style.backgroundColor = '#28a745';
        addSelectedBtn.style.color = '#fff';
        addSelectedBtn.style.border = 'none';
        addSelectedBtn.style.borderRadius = '3px';
        addSelectedBtn.style.cursor = 'pointer';

        addSelectedBtn.addEventListener('click', () => {
            const selectedQueue = queueSelect.value;
            const allCheckboxes = document.querySelectorAll('.category-panel .task-item input[type="checkbox"]');
            allCheckboxes.forEach(chk => {
                if (chk.checked) {
                    const listItem = chk.closest('.task-item');
                    const titleSpan = listItem.querySelector('span');
                    const titleText = titleSpan ? titleSpan.textContent.trim() : '';
                    for (const cat of Object.values(categories)) {
                        if (!cat.items) continue;
                        const it = cat.items.find(d => d.title === titleText);
                        if (it) {
                            // 确保是课件才加入队列
                            const catName = Object.entries(categories).find(([k,v])=>v.items.includes(it))?.[0]||'';
                            if (catName === '课件' && !coursewareQueues[selectedQueue].items.includes(it)) {
                                coursewareQueues[selectedQueue].items.push(it);
                            }
                        }
                    }
                    chk.checked = false;
                }
            });
            refreshQueueSelect();
            alert('已添加到队列');
            renderQueueList();
        });

        addToQueueContainer.appendChild(queueSelect);
        addToQueueContainer.appendChild(addSelectedBtn);

        queueContainer.appendChild(createQueueForm);
        queueContainer.appendChild(addToQueueContainer);

        panelContent.appendChild(queueContainer);
    }


    async function startQueueProcessing(queueName) {
        if (!coursewareQueues[queueName]) {
            alert('队列不存在');
            return;
        }

        if (coursewareQueues[queueName].items.length === 0) {
            alert('队列中无课件');
            return;
        }

        isQueueProcessing = true;
        const qData = coursewareQueues[queueName];

        for (const itemData of qData.items) {
            if (document.hidden) break;
            await jumpToContentItem(itemData.originalElement);
            await new Promise(res => setTimeout(res, 1000));

            if (hasPPT(itemData.originalElement)) {
                const pptIframe = itemData.originalElement.querySelector('iframe');
                if (pptIframe) {
                    const pptTaskId = `ppt-${Date.now()}-${Math.random().toString(36).substr(2,5)}`;
                    const iframeSrc = new URL(pptIframe.src);
                    iframeSrc.searchParams.set('pptTaskId', pptTaskId);
                    pptIframe.src = iframeSrc.toString();

                    const pptPromise = window.videoController.createPPTTask(pptTaskId);
                    await pptPromise;
                }
            } else if (hasVideo(itemData.originalElement)) {
                const videoEl = itemData.originalElement.querySelector('#dplayer video') || itemData.originalElement.querySelector('video');
                if (videoEl) {
                    const videoTaskId = `video-${Date.now()}-${Math.random().toString(36).substr(2,5)}`;
                    const videoPromise = window.videoController.handleVideo(videoEl, videoTaskId);
                    await videoPromise;
                }
            }

            await new Promise(res => setTimeout(res, qData.interval));
        }

        isQueueProcessing = false;
        currentQueueName = null;
        alert(`${queueName} 执行完成!`);
    }

    function hasPPT(element) {
        return !!element.querySelector('.slide-img-container');
    }

    function hasVideo(element) {
        return !!element.querySelector('#dplayer') || !!element.querySelector('video');
    }

    function initPptAutoPaging() {
        const progressBarSelector = '.bottom-paging-progress .bar';
        const nextPageButtonSelector = '.slide-img-container.context-menu-disabled .ppt-turn-right-mask';
        const checkInterval = 1000;
        let hasReportedCompletion = false;

        let pptIntervalId = setInterval(() => {
            const pptBar = document.querySelector(progressBarSelector);
            const nextButton = document.querySelector(nextPageButtonSelector);

            if (pptBar) {
                let width = parseFloat(pptBar.style.width) || 0;
                if (width >= 100 && !hasReportedCompletion) {
                    hasReportedCompletion = true;
                    clearInterval(pptIntervalId);
                    window.parent.postMessage({
                        type: 'pptCompleted',
                        status: 'completed',
                        timestamp: Date.now()
                    }, '*');
                    return;
                }
                if (width < 100 && nextButton) {
                    simulateClick(nextButton);
                }
            }
        }, checkInterval);

        pptTimeoutId = setTimeout(() => {
            if (!hasReportedCompletion) {
                hasReportedCompletion = true;
                clearInterval(pptIntervalId);
                window.parent.postMessage({
                    type: 'pptCompleted',
                    status: 'completed',
                    timestamp: Date.now()
                }, '*');
            }
        }, 60000);
    }

    async function initialize() {
        await waitForContentLoaded();
        const items = document.querySelectorAll('.third-level-inner-box');
        const categorized = categorizeItems(items);
        const panelContent = createDisplayPanel();
        populatePanel(panelContent, categorized);
        createQueueUI(panelContent, categorized);
    }


    class VideoController {
        constructor() {
            this.activeVideos = new Map();
            this.pptPromises = new Map();
            this.container = this.createAutoPlayerInterface();
            this.taskContainer = this.container.querySelector('#autoplay-task-container');
            this.activePPTs = new Map();

            document.addEventListener('visibilitychange', () => this.handleVisibilityChange());
            window.addEventListener('message', (event) => this.handleMessage(event), false);
        }

        createAutoPlayerInterface() {
            if (document.getElementById('autoplay-control-panel')) return document.getElementById('autoplay-control-panel');

            const container = document.createElement('div');
            container.id = 'autoplay-control-panel';
            container.style.cssText = `
                position: fixed;
                bottom: 20px;
                right: 20px;
                width: 300px;
                height: 400px;
                background: rgba(0, 0, 0, 0.8);
                color: white;
                padding: 15px;
                border-radius: 8px;
                font-family: Arial, sans-serif;
                z-index: 9999;
                box-shadow: 0 2px 10px rgba(0,0,0,0.3);
                overflow-y: auto;
            `;

            container.innerHTML = `
                <div style="font-weight:bold;font-size:16px;margin-bottom:10px;">视频/PPT自动播放面板</div>
                <div id="autoplay-task-container"></div>
            `;

            document.body.appendChild(container);
            return container;
        }

        handleMessage(event) {
            if (event.origin !== `https://${IFRAME_PAGE_HOST}`) return;
            const data = event.data;
            if (!data.type) return;

            if (data.type === 'pptCompleted') {
                this.updateTaskUI(data.taskId, 100, 'completed');
                this.activePPTs.delete(data.taskId);
                if (this.pptPromises.has(data.taskId)) {
                    this.pptPromises.get(data.taskId).resolve();
                    this.pptPromises.delete(data.taskId);
                }
            } else if (data.type === 'pptProgress') {
                this.updateTaskUI(data.taskId, data.progress, 'playing');
                if (this.activePPTs.has(data.taskId)) {
                    const pptTask = this.activePPTs.get(data.taskId);
                    pptTask.progress = data.progress;
                }
            }
        }

        createTaskElement(taskId, title = `任务 #${taskId}`) {
            const taskDiv = document.createElement('div');
            taskDiv.id = `task-${taskId}`;
            taskDiv.className = 'task-item';
            taskDiv.style.cssText = `
                margin-bottom: 10px;
                padding: 8px;
                background: rgba(255, 255, 255, 0.1);
                border-radius: 4px;
            `;

            taskDiv.innerHTML = `
                <div style="font-weight:bold;">${title}</div>
                <div class="task-status">状态: 初始化中</div>
                <div style="margin-top:5px;position:relative;height:5px;background:#444;">
                    <div class="progress-fill" style="height:5px;width:0%;background:#28a745;"></div>
                </div>
            `;

            this.taskContainer.appendChild(taskDiv);
            return taskDiv;
        }

        updateTaskUI(taskId, progress, status) {
            const taskElement = document.querySelector(`#task-${taskId}`);
            if (taskElement) {
                const progressFill = taskElement.querySelector('.progress-fill');
                const statusText = taskElement.querySelector('.task-status');

                if (progressFill) {
                    progressFill.style.width = `${progress}%`;
                }
                if (statusText) {
                    statusText.textContent = `状态: ${status} (${progress.toFixed(1)}%)`;
                }
            }
        }

        createPPTTask(taskId) {
            this.createTaskElement(taskId, `PPT任务 #${taskId}`);
            this.activePPTs.set(taskId, {
                id: taskId,
                progress: 0,
                status: 'playing'
            });

            let resolveFunc;
            const promise = new Promise((resolve) => {
                resolveFunc = resolve;
            });
            this.pptPromises.set(taskId, { resolve: resolveFunc });
            return promise;
        }

        handleVideo(video, taskId) {
            return new Promise(async (resolve, reject) => {
                if (!video) {
                    reject(new Error('未找到视频元素'));
                    return;
                }

                this.createTaskElement(taskId, `视频任务 #${taskId}`);

                try {
                    video.muted = true;
                    video.autoplay = true;
                    video.playsInline = true;
                    video.setAttribute('webkit-playsinline', 'true');

                    const applyPlaybackRate = () => {
                        const playbackRate = parseFloat(localStorage.getItem('videoPlaybackSpeed')) || 3;
                        video.playbackRate = playbackRate;
                    };

                  
                    const onLoadedMetadata = () => {
                        applyPlaybackRate();
                    };
                    video.addEventListener('loadedmetadata', onLoadedMetadata, { once: true });

                   
                    const onCanPlay = () => {
                        applyPlaybackRate();
                    };
                    video.addEventListener('canplay', onCanPlay, { once: true });

                    const onTimeUpdate = () => {
                        if (!video.duration) return;
                        const progress = (video.currentTime / video.duration) * 100;
                        this.updateTaskUI(taskId, progress, 'playing');

                        if (progress >= 99.9) {
                            this.updateTaskUI(taskId, 100, 'completed');
                            video.removeEventListener('timeupdate', onTimeUpdate);
                        
                            video.removeEventListener('loadedmetadata', onLoadedMetadata);
                            video.removeEventListener('canplay', onCanPlay);
                            resolve();
                        }
                    };

                    video.addEventListener('timeupdate', onTimeUpdate);

                    await video.play();
                  
                    applyPlaybackRate();

                    this.updateTaskUI(taskId, 0, 'playing');
                } catch (error) {
                    console.error('视频播放错误:', error);
                    this.updateTaskUI(taskId, 0, 'error');
                    reject(error);
                }
            });
        }


        handleVisibilityChange() {}
    }

    if (window.location.hostname === MAIN_PAGE_HOST) {
        window.videoController = new VideoController();
      
        const observer = new MutationObserver((mutations) => {
            mutations.forEach((mutation) => {
                mutation.addedNodes.forEach((node) => {
                    if (node.nodeType === 1) {
                        const videoPlayer = node.id === 'dplayer' ? node : node.querySelector('#dplayer');
                        if (videoPlayer && !videoPlayer.dataset.autoplayInitialized) {
                            videoPlayer.dataset.autoplayInitialized = 'true';
                            const videoTaskId = `video-${Date.now()}-${Math.random().toString(36).substr(2,5)}`;
                            window.videoController.handleVideo(videoPlayer.querySelector('video'), videoTaskId);
                        }

                        const pptIframe = (node.tagName === 'IFRAME') ? node : node.querySelector('iframe');
                        if (pptIframe && !pptIframe.dataset.pptInitialized && pptIframe.src.includes('preview.cqooc.com')) {
                            pptIframe.dataset.pptInitialized = 'true';
                            const pptTaskId = `ppt-${Date.now()}-${Math.random().toString(36).substr(2,5)}`;
                            const iframeSrc = new URL(pptIframe.src);
                            iframeSrc.searchParams.set('pptTaskId', pptTaskId);
                            pptIframe.src = iframeSrc.toString();
                            window.videoController.createPPTTask(pptTaskId);
                        }
                    }
                });
            });
        });
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });

        initialize();

    } else if (window.location.hostname === IFRAME_PAGE_HOST) {
        initPptAutoPaging();
    }

})();


(function() {
    'use strict';

    const API_URL = 'https://api.siliconflow.cn/v1/chat/completions';
    const API_KEY = 'sk-bxignvnkxpnoswzugchqmygyfwebfggbntiicrqjsipgvpoe';
    const MODEL = 'Qwen/Qwen2.5-7B-Instruct';
    const MAX_TOKENS = 1024;
    const MAX_SUBMIT_RETRIES = 5;


    const controlPanel = document.createElement('div');
    controlPanel.id = 'customControlPanel';
    controlPanel.style.position = 'fixed';
    controlPanel.style.top = '20px';
    controlPanel.style.right = '20px';
    controlPanel.style.width = '400px';
    controlPanel.style.background = '#ffffff';
    controlPanel.style.border = '1px solid #ccc';
    controlPanel.style.borderRadius = '10px';
    controlPanel.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.1)';
    controlPanel.style.zIndex = '10000';
    controlPanel.style.fontFamily = 'Arial, sans-serif';
    controlPanel.style.fontSize = '14px';
    controlPanel.style.transition = 'all 0.3s ease';
    controlPanel.style.color = '#333';
    controlPanel.style.display = 'flex';
    controlPanel.style.flexDirection = 'column';


    let isDragging = false;
    let offsetX, offsetY;
    let animationFrame;

    controlPanel.addEventListener('mousedown', function(e) {
        if (e.target.classList.contains('panel-header')) {
            isDragging = true;
            offsetX = e.clientX - controlPanel.offsetLeft;
            offsetY = e.clientY - controlPanel.offsetTop;
            e.preventDefault();
        }
    });

    document.addEventListener('mousemove', function(e) {
        if (isDragging) {
            if (animationFrame) cancelAnimationFrame(animationFrame);
            animationFrame = requestAnimationFrame(() => {
                controlPanel.style.left = (e.clientX - offsetX) + 'px';
                controlPanel.style.top = (e.clientY - offsetY) + 'px';
                controlPanel.style.right = 'auto';
            });
        }
    });

    document.addEventListener('mouseup', function() {
        isDragging = false;
    });


    const panelHeader = document.createElement('div');
    panelHeader.className = 'panel-header';
    panelHeader.style.backgroundColor = '#6200EE';
    panelHeader.style.padding = '12px 16px';
    panelHeader.style.cursor = 'move';
    panelHeader.style.borderTopLeftRadius = '10px';
    panelHeader.style.borderTopRightRadius = '10px';
    panelHeader.style.display = 'flex';
    panelHeader.style.justifyContent = 'space-between';
    panelHeader.style.alignItems = 'center';
    panelHeader.style.userSelect = 'none';

    const panelTitle = document.createElement('div');
    panelTitle.innerText = ' - 作业区 - ';
    panelTitle.style.color = '#FFFFFF';
    panelTitle.style.fontWeight = 'bold';
    panelHeader.appendChild(panelTitle);


    const minimizeButton = document.createElement('button');
    minimizeButton.innerHTML = '&#x2212;';
    minimizeButton.title = '最小化';
    minimizeButton.style.background = 'transparent';
    minimizeButton.style.border = 'none';
    minimizeButton.style.color = '#FFFFFF';
    minimizeButton.style.cursor = 'pointer';
    minimizeButton.style.fontSize = '20px';
    minimizeButton.style.lineHeight = '20px';
    minimizeButton.style.padding = '0';
    minimizeButton.style.margin = '0';
    minimizeButton.style.width = '24px';
    minimizeButton.style.height = '24px';
    minimizeButton.style.display = 'flex';
    minimizeButton.style.alignItems = 'center';
    minimizeButton.style.justifyContent = 'center';
    minimizeButton.style.transition = 'transform 0.2s';

    minimizeButton.addEventListener('mouseenter', () => {
        minimizeButton.style.transform = 'scale(1.2)';
    });
    minimizeButton.addEventListener('mouseleave', () => {
        minimizeButton.style.transform = 'scale(1)';
    });

    minimizeButton.addEventListener('click', () => {
        if (contentContainer.style.display === 'none') {
            contentContainer.style.display = 'block';
            minimizeButton.innerHTML = '&#x2212;';
            controlPanel.style.width = '400px';
        } else {
            contentContainer.style.display = 'none';
            minimizeButton.innerHTML = '&#x25B6;';
            controlPanel.style.width = '45px';
        }
    });

    panelHeader.appendChild(minimizeButton);
    controlPanel.appendChild(panelHeader);


    const contentContainer = document.createElement('div');
    contentContainer.style.padding = '16px';
    contentContainer.style.display = 'block';
    contentContainer.style.flex = '1';
    controlPanel.appendChild(contentContainer);


    const instructions = document.createElement('div');
    instructions.id = 'instructions';
    instructions.style.marginBottom = '20px';
    instructions.style.maxHeight = '200px';
    instructions.style.overflowY = 'auto';
    instructions.style.padding = '12px';
    instructions.style.backgroundColor = '#f9f9f9';
    instructions.style.borderRadius = '8px';
    instructions.style.border = '1px solid #ddd';
instructions.innerHTML = '<strong>说明:</strong><br>' +
    '1. 把两个开始自动完成的按钮点开,然后进入您想完成的作业或测试页面,系统将会自动完成。<br>' +
    '2. 目前支持单选、多选、判断和论述题。<br>' +
    '3. 如果题目或答案中包含图片,本次答案不准确,仅能处理纯文本问题。<br>'+'4. 用的是免费模型,如果你对精确度有更高要求,可以来找我<br>'+'5. 含论述题时,可能需要手动点击论述题的框它才会认为是输入完成才会自动提交<br>' +
    '6. 多选题可能会漏选,这时候刷新一下也许会解决<br>' + '7. 自动提交可能会在第二次才生效<br>' + '8. 虽然我是作者,但是有些问题我也不知道,刷新能解决80%的问题<br>' +'9. 毕竟是大模型回答,科学性和常识性的OK,其余像什么酒吧的场景就不行了。<br>' + '10. 我是反对刷题的哈,仅供学习用途-_-。';

    contentContainer.appendChild(instructions);


    const autoAnswerSection = document.createElement('div');
    autoAnswerSection.style.marginBottom = '20px';

    const autoAnswerTitle = document.createElement('div');
    autoAnswerTitle.innerText = '自动完成测验和考试';
    autoAnswerTitle.style.fontWeight = 'bold';
    autoAnswerTitle.style.marginBottom = '10px';
    autoAnswerTitle.style.color = '#6200EE';
    autoAnswerSection.appendChild(autoAnswerTitle);


    function createButton(text, bgColor, hoverColor, textColor) {
        const button = document.createElement('button');
        button.innerText = text;
        button.style.margin = '8px 0';
        button.style.padding = '10px 16px';
        button.style.width = '100%';
        button.style.backgroundColor = bgColor;
        button.style.border = 'none';
        button.style.borderRadius = '8px';
        button.style.cursor = 'pointer';
        button.style.color = textColor;
        button.style.fontSize = '14px';
        button.style.transition = 'background-color 0.3s, transform 0.2s';
        button.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.1)';
        button.style.display = 'flex';
        button.style.alignItems = 'center';
        button.style.justifyContent = 'center';
        button.style.fontWeight = '500';
        button.addEventListener('mouseover', () => {
            button.style.backgroundColor = hoverColor;
            button.style.transform = 'translateY(-2px)';
        });
        button.addEventListener('mouseout', () => {
            button.style.backgroundColor = bgColor;
            button.style.transform = 'translateY(0)';
        });
        return button;
    }


    const startAnswerButton = createButton('开始自动完成', '#6200EE', '#3700B3', '#FFFFFF');
    autoAnswerSection.appendChild(startAnswerButton);


    const toggleAutoSubmitButton = createButton('开启自动提交', '#03DAC6', '#018786', '#000000');
    autoAnswerSection.appendChild(toggleAutoSubmitButton);

    contentContainer.appendChild(autoAnswerSection);


    const autoCompleteSection = document.createElement('div');

    const autoCompleteTitle = document.createElement('div');
    autoCompleteTitle.innerText = '自动完成作业';
    autoCompleteTitle.style.fontWeight = 'bold';
    autoCompleteTitle.style.marginBottom = '10px';
    autoCompleteTitle.style.color = '#6200EE';
    autoCompleteSection.appendChild(autoCompleteTitle);


    const startCompleteButton = createButton('开始自动完成', '#03A9F4', '#0288D1', '#FFFFFF');
    autoCompleteSection.appendChild(startCompleteButton);


    const toggleAutoSaveButton = createButton('开启自动保存', '#FF9800', '#F57C00', '#FFFFFF');
    autoCompleteSection.appendChild(toggleAutoSaveButton);

    contentContainer.appendChild(autoCompleteSection);

    document.body.appendChild(controlPanel);


    let autoSubmitting = false;
    let answering = false;
    let answerObserver = null;
    let submitRetryCount = 0;


    let autoSave = false;
    let completing = false;
    let completeObserver = null;


    function log(message, type = 'info') {
        const timestamp = new Date().toLocaleTimeString();
        console.log(`[${timestamp}][自动任务脚本] ${message}`);
    }



    startAnswerButton.addEventListener('click', () => {
        if (!answering) {
            answering = true;
            startAnswerButton.innerText = '停止自动完成';
            startAnswerButton.style.backgroundColor = '#3700B3';
            log('开始自动完成测验和考试');
            observeQuestions();
        } else {
            answering = false;
            startAnswerButton.innerText = '开始自动完成';
            startAnswerButton.style.backgroundColor = '#6200EE';
            log('停止自动完成测验和考试');
            disconnectAnswerObserver();
        }
    });

    toggleAutoSubmitButton.addEventListener('click', () => {
        autoSubmitting = !autoSubmitting;
        toggleAutoSubmitButton.innerText = autoSubmitting ? '关闭自动提交' : '开启自动提交';
        toggleAutoSubmitButton.style.backgroundColor = autoSubmitting ? '#018786' : '#03DAC6';
        log(`自动提交功能已${autoSubmitting ? '开启' : '关闭'}`);
        if (autoSubmitting) {
            checkAndSubmit();
        }
    });


    function observeQuestions() {
        if (answerObserver) return; // 避免重复启动

        answerObserver = new MutationObserver(mutationCallback);
        answerObserver.observe(document.body, { childList: true, subtree: true });
        initialScanAnswer();
    }


    function disconnectAnswerObserver() {
        if (answerObserver) {
            answerObserver.disconnect();
            answerObserver = null;
        }
    }

    function initialScanAnswer() {
        log('执行初始扫描以查找现有问题');
        const questionNodes = document.querySelectorAll('.question-item:not([data-answered="true"])');
        log(`找到 ${questionNodes.length} 个未回答的问题节点`);
        questionNodes.forEach(node => {
            handleQuestionNode(node);
        });
    }


    function mutationCallback(mutationsList) {
        for (let mutation of mutationsList) {
            if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                mutation.addedNodes.forEach(node => {
                    if (node.nodeType === 1) { // 元素节点
                        if (node.classList.contains('question-item')) {
                            log('检测到新问题节点');
                            handleQuestionNode(node);
                        }
                        // 递归检查子节点
                        const questionChildren = node.querySelectorAll('.question-item');
                        questionChildren.forEach(child => {
                            log('检测到子问题节点');
                            handleQuestionNode(child);
                        });
                    }
                });
            }
        }
    }

    function hasIncompleteQuestions() {
        const incompleteDots = document.querySelectorAll('.index-dot-item-inner:not(.index-dot-item-inner-active)');
        return incompleteDots.length > 0;
    }


    function getIncompleteQuestionElements() {
        const incompleteDots = document.querySelectorAll('.index-dot-item-inner:not(.index-dot-item-inner-active)');
        let incompleteQuestions = [];

        incompleteDots.forEach(dot => {
            const questionNumber = dot.innerText.trim();
            if (questionNumber) {
                const questionElement = Array.from(document.querySelectorAll('.question-item')).find(item => {
                    const title = item.querySelector('.single-select-title, .multiple-select-title, .bol-select-title, .essay-select-title');
                    return title && title.innerText.includes(`${questionNumber}、`);
                });
                if (questionElement) {
                    incompleteQuestions.push(questionElement);
                } else {
                    log(`无法找到对应题号 ${questionNumber} 的问题元素`);
                }
            }
        });

        log(`找到 ${incompleteQuestions.length} 个未完成的问题元素`);
        return incompleteQuestions;
    }


    function handleQuestionNode(node) {
        if (node.getAttribute('data-answered') === 'true') {
            log('该问题已处理,跳过');
            return;
        }

        if (node.querySelector('.single-select-container')) {
            processSingleChoice(node);
        } else if (node.querySelector('.multiple-select-container')) {
            processMultipleChoice(node);
        } else if (node.querySelector('.bol-select-container')) {
            processTrueFalse(node);
        } else if (node.querySelector('.essay-select-container')) {
            processEssayQuestion(node);
        } else {
            log('检测到未知题型,停止自动化并等待用户手动处理');
            stopAnswerAutomation();
        }
    }


    function processSingleChoice(node) {
        const questionElement = node.querySelector('.single-select-title');
        if (!questionElement) {
            log('未找到单选题的问题文本元素');
            return;
        }
        const questionText = questionElement.innerText.trim();
        log(`处理单选题:${questionText}`);

        const optionsElements = node.querySelectorAll('.single-option-item');
        if (optionsElements.length === 0) {
            log('未找到单选题的选项元素');
            return;
        }

        let optionsText = '';
        let optionMap = {};

        optionsElements.forEach(option => {
            const indexElement = option.querySelector('.index');
            const titleElement = option.querySelector('.title');
            if (indexElement && titleElement) {
                const optionLetter = indexElement.innerText.trim();
                const optionContent = titleElement.innerText.trim();
                optionsText += `${optionLetter}. ${optionContent}\n`;
                optionMap[optionLetter.toUpperCase()] = option;
            } else {
                log('单选题的选项元素缺少 .index 或 .title 子元素');
            }
        });

        log(`构造的单选题选项文本:\n${optionsText}`);

        const prompt = `请根据以下问题选择一个最合适的答案,并仅回复答案的选项字母(如A、B、C或D),不要添加任何其他字符或符号:
问题:${questionText}
答案选项:
${optionsText}
回答:`;

        log(`发送API请求,提示语:\n${prompt}`);

        getAnswerFromAPI(prompt).then(answer => {
            log(`模型回答:${answer}`);
            const match = answer.toUpperCase().trim().match(/[A-D]/);
            if (match && match[0]) {
                const selectedLetter = match[0];
                log(`解析后的选项字母:${selectedLetter}`);

                if (optionMap[selectedLetter]) {
                    const selectedOption = optionMap[selectedLetter];
                    simulateClick(selectedOption);
                    log(`已尝试选择单选题的选项 ${selectedLetter}`);

                    setTimeout(() => {
                        const isSelected = selectedOption.classList.contains('selected') || selectedOption.classList.contains('active');
                        if (isSelected) {
                            log(`成功选择单选题的选项 ${selectedLetter}`);
                            node.setAttribute('data-answered', 'true');
                            markQuestionAsAnswered(selectedLetter);
                            if (autoSubmitting) {
                                setTimeout(() => checkAndSubmit(), 2000);
                            }
                        } else {
                            log(`未能成功选择单选题的选项 ${selectedLetter}`);
                        }
                    }, 1000);
                } else {
                    log(`模型返回的单选题选项字母无效或不存在:${selectedLetter}`);
                }
            } else {
                log(`无法解析模型返回的单选题答案:${answer}`);
            }
        }).catch(err => {
            log(`获取单选题答案时出错:${err}`);
        });
    }


    function processMultipleChoice(node) {
        const questionElement = node.querySelector('.multiple-select-title');
        if (!questionElement) {
            log('未找到多选题的问题文本元素');
            return;
        }
        const questionText = questionElement.innerText.trim();
        log(`处理多选题:${questionText}`);

        const optionsElements = node.querySelectorAll('.multiple-option-item');
        if (optionsElements.length === 0) {
            log('未找到多选题的选项元素');
            return;
        }

        let optionsText = '';
        let optionMap = {};

        optionsElements.forEach(option => {
            const indexElement = option.querySelector('.index');
            const titleElement = option.querySelector('.title');
            if (indexElement && titleElement) {
                const optionLetter = indexElement.innerText.trim();
                const optionContent = titleElement.innerText.trim();
                optionsText += `${optionLetter}. ${optionContent}\n`;
                optionMap[optionLetter.toUpperCase()] = option;
            } else {
                log('多选题的选项元素缺少 .index 或 .title 子元素');
            }
        });

        log(`构造的多选题选项文本:\n${optionsText}`);

        const prompt = `请根据以下问题选择所有合适的答案,并仅回复答案的选项字母,用逗号分隔(如A,B,C),不要添加任何其他字符或符号:
问题:${questionText}
答案选项:
${optionsText}
回答:`;

        log(`发送API请求,提示语:\n${prompt}`);

        getAnswerFromAPI(prompt).then(answer => {
            log(`模型回答:${answer}`);
            const matches = answer.toUpperCase().trim().match(/[A-D]/g);
            if (matches && matches.length > 0) {
                const selectedLetters = Array.from(new Set(matches));
                log(`解析后的多选题选项字母:${selectedLetters.join(',')}`);

                selectedLetters.forEach(letter => {
                    if (optionMap[letter]) {
                        const selectedOption = optionMap[letter];
                        simulateClick(selectedOption);
                        log(`已尝试选择多选题的选项 ${letter}`);
                    } else {
                        log(`模型返回的多选题选项字母无效或不存在:${letter}`);
                    }
                });

                setTimeout(() => {
                    let allSelected = true;
                    selectedLetters.forEach(letter => {
                        const option = optionMap[letter];
                        if (!option.classList.contains('selected') && !option.classList.contains('active')) {
                            allSelected = false;
                            log(`未能成功选择多选题的选项 ${letter}`);
                        }
                    });

                    if (allSelected) {
                        log(`成功选择多选题的选项 ${selectedLetters.join(',')}`);
                        node.setAttribute('data-answered', 'true');
                        markMultipleQuestionsAsAnswered(selectedLetters);
                        if (autoSubmitting) {
                            setTimeout(() => checkAndSubmit(), 2000);
                        }
                    } else {
                        log(`部分多选题选项未能成功选择`);
                    }
                }, 1000);
            } else {
                log(`无法解析模型返回的多选题答案:${answer}`);
            }
        }).catch(err => {
            log(`获取多选题答案时出错:${err}`);
        });
    }


    function processTrueFalse(node) {
        const questionElement = node.querySelector('.bol-select-title');
        if (!questionElement) {
            log('未找到判断题的问题文本元素');
            return;
        }
        const questionText = questionElement.innerText.trim();
        log(`处理判断题:${questionText}`);

        const optionsElements = node.querySelectorAll('.bol-option-item');
        if (optionsElements.length !== 2) {
            log('判断题应有两个选项,跳过');
            return;
        }

        let optionsText = '';
        let optionMap = {};

        optionsElements.forEach(option => {
            const titleElement = option.querySelector('.title');
            if (titleElement) {
                const optionContent = titleElement.innerText.trim();
                optionsText += `${optionContent}\n`;
                optionMap[optionContent.toLowerCase()] = option;
            } else {
                log('选项元素缺少 .title 子元素');
            }
        });

        log(`构造的选项文本:\n${optionsText}`);

        const prompt = `请根据以下判断题选择一个最合适的答案,并仅回复答案的选项文本(如“对”或“错”),不要添加任何其他字符或符号:
问题:${questionText}
答案选项:
${optionsText}
回答:`;

        log(`发送API请求,提示语:\n${prompt}`);

        getAnswerFromAPI(prompt).then(answer => {
            log(`模型回答:${answer}`);
            const match = answer.trim().match(/^(对|错)$/i);
            if (match && match[1]) {
                const selectedText = match[1].toLowerCase();
                log(`解析后的选项文本:${selectedText}`);

                if (optionMap[selectedText]) {
                    const selectedOption = optionMap[selectedText];
                    simulateClick(selectedOption);
                    log(`已尝试选择选项 ${selectedText}`);

                    setTimeout(() => {
                        const isSelected = selectedOption.classList.contains('selected') || selectedOption.classList.contains('active');
                        if (isSelected) {
                            log(`成功选择选项 ${selectedText}`);
                            node.setAttribute('data-answered', 'true');
                            markTrueFalseQuestionAsAnswered(selectedText);
                            if (autoSubmitting) {
                                setTimeout(() => checkAndSubmit(), 2000);
                            }
                        } else {
                            log(`未能成功选择选项 ${selectedText}`);
                        }
                    }, 1000);
                } else {
                    log(`模型返回的选项文本无效或不存在:${selectedText}`);
                }
            } else {
                log(`无法解析模型返回的答案:${answer}`);
            }
        }).catch(err => {
            log(`获取答案时出错:${err}`);
        });
    }


    function processEssayQuestion(node) {
        const questionElement = node.querySelector('.essay-select-title');
        if (!questionElement) {
            log('未找到论述题的问题文本元素');
            return;
        }
        const questionText = questionElement.innerText.trim();
        log(`处理论述题:${questionText}`);

        const textareaElement = node.querySelector('.essay-option-item textarea');
        if (!textareaElement) {
            log('未找到论述题的文本区域');
            return;
        }

        const saveButton = node.querySelector('.submit-inner-box');

        const prompt = `请根据以下论述题提供一个详细且全面的回答,确保回答清晰、有逻辑并涵盖所有关键点:
问题:${questionText}
回答:`;

        log(`发送API请求,提示语:\n${prompt}`);

        getAnswerFromAPI(prompt).then(answer => {
            log(`模型回答:${answer}`);
            fillAnswer(textareaElement, answer);
            node.setAttribute('data-answered', 'true');
            log('已填充答案并标记任务为已处理');
            if (autoSave) {
                saveAnswer(saveButton, node);
            }
            if (autoSubmitting) {
                setTimeout(() => checkAndSubmit(), 5000);
            }
        }).catch(err => {
            log(`获取论述题答案时出错:${err}`);
        });
    }


    function simulateClick(optionElement) {
        const titleElement = optionElement.querySelector('.index, .title');
        if (titleElement) {
            const events = ['mousedown', 'mouseup', 'click'];
            events.forEach(eventType => {
                const event = new MouseEvent(eventType, {
                    view: window,
                    bubbles: true,
                    cancelable: true
                });
                titleElement.dispatchEvent(event);
            });
            log(`已模拟点击选项标题`);
        } else {
            log('未找到选项标题元素,无法模拟点击');
        }
    }


    async function getAnswerFromAPI(prompt) {
        const options = {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${API_KEY}`,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                model: MODEL,
                messages: [
                    { role: 'user', content: prompt }
                ],
                stream: false,
                max_tokens: MAX_TOKENS
            })
        };

        try {
            const response = await fetch(API_URL, options);
            if (!response.ok) {
                throw new Error(`API请求失败,状态码:${response.status}`);
            }

            const data = await response.json();
            if (data.choices && data.choices.length > 0 && data.choices[0].message && data.choices[0].message.content) {
                const answer = data.choices[0].message.content.trim();
                return answer;
            } else {
                throw new Error('API返回的数据格式不正确');
            }
        } catch (error) {
            log(`API调用出错:${error.message}`);
            throw error;
        }
    }


    function submitAnswers() {
        const submitButton = document.querySelector('.submit-button, .submit-btn, .confirm-btn');
        if (submitButton) {
            const isDisabled = submitButton.disabled || submitButton.classList.contains('disabled');
            if (!isDisabled) {
                submitButton.click();
                log('已自动点击初始提交按钮');
                handleConfirmationModal();
                setupSubmissionErrorObserver();
            } else {
                log('提交按钮被禁用,开始轮询等待提交条件满足');
                waitAndSubmit();
            }
        } else {
            log('未找到提交按钮');
        }
    }


    function handleConfirmationModal() {
        const modalCheckInterval = 1000;
        const maxModalRetries = 10;
        let modalAttempts = 0;

        const modalIntervalId = setInterval(() => {
            const confirmButton = document.querySelector('.ant-modal-content .ant-modal-confirm-btns .ant-btn-primary');
            if (confirmButton) {
                confirmButton.click();
                log('已自动点击确认模态框的提交按钮');
                clearInterval(modalIntervalId);
            } else {
                modalAttempts++;
                log(`未找到确认模态框的提交按钮,已尝试 ${modalAttempts} 次`);
                if (modalAttempts >= maxModalRetries) {
                    log('未能找到确认模态框的提交按钮,停止尝试');
                    clearInterval(modalIntervalId);
                }
            }
        }, modalCheckInterval);
    }


    function waitAndSubmit() {
        const retryInterval = 5000;
        const maxRetries = 12;
        let attempts = 0;

        const intervalId = setInterval(() => {
            const submitButton = document.querySelector('.submit-button, .submit-btn, .confirm-btn');
            if (submitButton && !submitButton.disabled && !submitButton.classList.contains('disabled')) {
                submitButton.click();
                log('已自动点击提交按钮');
                handleConfirmationModal();
                setupSubmissionErrorObserver();
                clearInterval(intervalId);
            } else {
                attempts++;
                log(`提交按钮仍不可用,已尝试 ${attempts} 次`);
                if (attempts >= maxRetries) {
                    log('达到最大重试次数,停止轮询提交');
                    clearInterval(intervalId);
                }
            }
        }, retryInterval);
    }


    function stopAnswerAutomation() {
        answering = false;
        completing = false;
        disconnectAnswerObserver();
        disconnectCompleteObserver();
        startAnswerButton.innerText = '开始自动完成';
        startAnswerButton.style.backgroundColor = '#6200EE';
        startCompleteButton.innerText = '开始自动完成';
        startCompleteButton.style.backgroundColor = '#03A9F4';
        toggleAutoSubmitButton.innerText = '开启自动提交';
        toggleAutoSubmitButton.style.backgroundColor = '#03DAC6';
        toggleAutoSaveButton.innerText = '开启自动保存';
        toggleAutoSaveButton.style.backgroundColor = '#FF9800';
        alert('检测到未知题型,自动化已停止。请手动提交并处理这些题目。');
        log('检测到未知题型,自动化已停止。');
    }


    function markQuestionAsAnswered(selectedLetter) {
        const questionElement = Array.from(document.querySelectorAll('.question-item')).find(item => {
            const title = item.querySelector('.single-select-title, .multiple-select-title, .bol-select-title, .essay-select-title');
            return title && title.innerText.includes(`${selectedLetter}、`);
        });

        if (questionElement) {
            const questionNumberMatch = questionElement.querySelector('.single-select-title, .multiple-select-title, .bol-select-title, .essay-select-title').innerText.match(/(\d+)、/);
            if (questionNumberMatch && questionNumberMatch[1]) {
                const questionNumber = questionNumberMatch[1];
                const dotElement = Array.from(document.querySelectorAll('.index-dot-item-inner')).find(dot => dot.innerText.trim() === questionNumber);
                if (dotElement) {
                    dotElement.classList.add('index-dot-item-inner-active');
                    log(`已标记题号 ${questionNumber} 为已完成`);
                }
            }
        }
    }


    function markMultipleQuestionsAsAnswered(selectedLetters) {
        selectedLetters.forEach(letter => {
            markQuestionAsAnswered(letter);
        });
    }


    function markTrueFalseQuestionAsAnswered(selectedText) {
        const questionElement = Array.from(document.querySelectorAll('.question-item')).find(item => {
            const title = item.querySelector('.bol-select-title');
            return title && title.innerText.includes(selectedText === '对' ? '对' : '错');
        });

        if (questionElement) {
            const questionNumberMatch = questionElement.querySelector('.bol-select-title').innerText.match(/(\d+)、/);
            if (questionNumberMatch && questionNumberMatch[1]) {
                const questionNumber = questionNumberMatch[1];
                const dotElement = Array.from(document.querySelectorAll('.index-dot-item-inner')).find(dot => dot.innerText.trim() === questionNumber);
                if (dotElement) {
                    dotElement.classList.add('index-dot-item-inner-active');
                    log(`已标记判断题号 ${questionNumber} 为已完成`);
                }
            }
        }
    }


    function markEssayQuestionAsAnswered(questionNumber) {
        const dotElement = Array.from(document.querySelectorAll('.index-dot-item-inner')).find(dot => dot.innerText.trim() === questionNumber);
        if (dotElement) {
            dotElement.classList.add('index-dot-item-inner-active');
            log(`已标记论述题号 ${questionNumber} 为已完成`);
        }
    }


    function checkAndSubmit() {
        if (hasIncompleteQuestions()) {
            log('存在未完成的题目,准备回答这些题目');
            const incompleteQuestions = getIncompleteQuestionElements();
            if (incompleteQuestions.length > 0) {
                incompleteQuestions.forEach(question => {
                    handleQuestionNode(question);
                });
                setTimeout(() => {
                    checkAndSubmit();
                }, 3000);
            }
        } else {
            log('所有题目已完成,准备提交');
            submitAnswers();
        }
    }


    function setupSubmissionErrorObserver() {
        const messageContainer = document.querySelector('.ant-message');
        if (!messageContainer) {
            log('未找到消息容器,无法设置错误消息观察器');
            return;
        }

        const errorObserver = new MutationObserver((mutationsList) => {
            for (let mutation of mutationsList) {
                if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                    mutation.addedNodes.forEach(node => {
                        if (node.nodeType === 1) {
                            const errorSpan = node.querySelector('.ant-message-error span');
                            if (errorSpan) {
                                const errorText = errorSpan.innerText;
                                log(`检测到提交错误消息:${errorText}`);
                                const match = errorText.match(/最小提交作答时间为(\d+)分钟/);
                                if (match && match[1]) {
                                    const waitMinutes = parseInt(match[1], 10);
                                    const waitMilliseconds = waitMinutes * 60 * 1000;
                                    log(`需要等待 ${waitMinutes} 分钟后再提交`);
                                    submitRetryCount++;
                                    if (submitRetryCount > MAX_SUBMIT_RETRIES) {
                                        log('已达到最大提交重试次数,停止自动提交');
                                        errorObserver.disconnect();
                                        return;
                                    }
                                    setTimeout(() => {
                                        log('等待时间已到,重新尝试提交');
                                        submitAnswers();
                                    }, waitMilliseconds);
                                } else {
                                    log('无法解析等待时间,停止自动提交');
                                }
                            }
                        }
                    });
                }
            }
        });

        const config = { childList: true, subtree: true };
        errorObserver.observe(messageContainer, config);
        log('已设置提交错误消息观察器');
    }



    startCompleteButton.addEventListener('click', () => {
        if (!completing) {
            completing = true;
            startCompleteButton.innerText = '停止自动完成';
            startCompleteButton.style.backgroundColor = '#0288D1';
            log('开始自动完成作业');
            observeTextTasks();

            if (autoSave) {
                setTimeout(() => {
                    checkAndSubmit();
                }, 1000);
            }
        } else {
            completing = false;
            startCompleteButton.innerText = '开始自动完成';
            startCompleteButton.style.backgroundColor = '#03A9F4';
            log('停止自动完成作业');
            disconnectCompleteObserver();
        }
    });


    toggleAutoSaveButton.addEventListener('click', () => {
        autoSave = !autoSave;
        toggleAutoSaveButton.innerText = autoSave ? '关闭自动保存' : '开启自动保存';
        toggleAutoSaveButton.style.backgroundColor = autoSave ? '#F57C00' : '#FF9800';
        log(`自动点击保存功能已${autoSave ? '开启' : '关闭'}`);

        if (autoSave && completing) {
            checkAndSubmit();
        }
    });


    function observeTextTasks() {
        if (completeObserver) return;
        completeObserver = new MutationObserver(mutationCallbackComplete);
        completeObserver.observe(document.body, { childList: true, subtree: true });
        initialScanComplete();
    }


    function disconnectCompleteObserver() {
        if (completeObserver) {
            completeObserver.disconnect();
            completeObserver = null;
        }
    }


    function initialScanComplete() {
        log('执行初始扫描以查找现有的文本任务');
        const textTaskNodes = document.querySelectorAll('.question-container:not([data-processed="true"])');
        log(`找到 ${textTaskNodes.length} 个未处理的文本任务节点`);
        textTaskNodes.forEach(node => {
            handleTextTaskNode(node);
        });
    }


    function mutationCallbackComplete(mutationsList) {
        for (let mutation of mutationsList) {
            if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                mutation.addedNodes.forEach(node => {
                    if (node.nodeType === 1) { // 元素节点
                        if (node.classList.contains('question-container')) {
                            log('检测到新文本任务节点');
                            handleTextTaskNode(node);
                        }

                        const textTaskChildren = node.querySelectorAll('.question-container');
                        textTaskChildren.forEach(child => {
                            log('检测到子文本任务节点');
                            handleTextTaskNode(child);
                        });
                    }
                });
            }
        }
    }


    function getIncompleteTextTaskElements() {
        const incompleteTasks = document.querySelectorAll('.question-container:not([data-processed="true"])');
        log(`找到 ${incompleteTasks.length} 个未完成的文本任务元素`);
        return Array.from(incompleteTasks);
    }


    function handleTextTaskNode(node) {
        if (node.getAttribute('data-processed') === 'true') {
            log('该文本任务已处理,跳过');
            return;
        }

        const titleElement = node.querySelector('.question-title');
        const contentElement = node.querySelector('.announce-box .text-box p');
        const editorElement = node.querySelector('.editor-box [contenteditable="true"]');
        const saveButton = node.querySelector('.submit-inner-box');

        if (!titleElement || !contentElement || !editorElement || !saveButton) {
            log('未找到完整的文本任务元素,跳过');
            return;
        }

        const taskTitle = titleElement.innerText.trim();
        const taskContent = contentElement.innerText.trim();
        log(`处理文本任务:${taskTitle} - ${taskContent}`);

        const prompt = `请根据以下任务内容完成作答,并直接返回答案文本,不要添加任何额外的解释或内容:
任务标题:${taskTitle}
任务内容:${taskContent}
答案:`;

        log(`发送API请求,提示语:\n${prompt}`);

        getAnswerFromAPI(prompt).then(answer => {
            log(`模型回答:${answer}`);
            fillAnswer(editorElement, answer);
            node.setAttribute('data-processed', 'true');
            log('已填充答案并标记任务为已处理');
            if (autoSave) {
                saveAnswer(saveButton, node);
            }

            if (autoSave) {
                setTimeout(() => {
                    checkAndSubmit();
                }, 1000);
            }
        }).catch(err => {
            log(`获取答案时出错:${err}`);
        });
    }


    function fillAnswer(editorElement, answer) {
        editorElement.focus();
        editorElement.innerHTML = '';
        editorElement.innerText = answer;
        log('已将答案填充到编辑器');

        const inputEvent = new Event('input', { bubbles: true });
        editorElement.dispatchEvent(inputEvent);
    }


    function saveAnswer(saveButton, node) {
        if (saveButton) {
            saveButton.click();
            log('已自动点击保存按钮');
            // 立即尝试提交
            setTimeout(() => {
                checkAndSubmit();
            }, 1000);
        } else {
            log('未找到保存按钮,无法自动点击');
        }
    }


    window.addEventListener('load', () => {
        log('页面加载完成,准备初始化脚本');
        if (answering) {
            observeQuestions();
        }
        if (completing) {
            observeTextTasks();
        }
    });

})();