Greasy Fork

Greasy Fork is available in English.

上海开大助手

上海开放大学学习平台,自动刷课,题目共享,接入deepseek一键搜题

目前为 2025-03-03 提交的版本。查看 最新版本

// ==UserScript==
// @name         上海开大助手
// @namespace    http://tampermonkey.net/
// @homepage     https://shkd.script.woca.fun
// @description  上海开放大学学习平台,自动刷课,题目共享,接入deepseek一键搜题
// @author       AchieveHF
// @version      1.1.1
// @match        *://*.shou.org.cn/*
// @match        *://live.eeo.cn/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=shou.org.cn
// @grant        GM_setValue
// @grant        GM_getValue
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// @require      https://unpkg.com/[email protected]/dist/layui.js
// @license MIT
// @run-at document-idle
// ==/UserScript==

(function() {
        'use strict';


        const css = document.createElement('link');
        css.rel = 'stylesheet';
        css.href = '//shkd.script.woca.fun/static/layui/css/layui.css';
        document.head.appendChild(css);
        const apiDomain = 'https://shkd.script.woca.fun/';
        // const apiDomain = 'http://localhost:8000/';

        // 移除固定的DeepSeek设置按钮,改为按需显示

        // DeepSeek 设置弹窗函数
        function showDeepSeekSettings() {
            // 获取当前保存的 API Key
            const apiKey = GM_getValue('deepseekApiKey', '');

            layer.open({
                type: 1,
                title: 'DeepSeek API 设置',
                area: ['400px', '300px'],
                content: `
                <div style="padding: 20px;">
                    <div class="layui-form">
                        <div class="layui-form-item">
                            <label class="layui-form-label">API Key</label>
                            <div class="layui-input-block">
                                <input type="text" id="deepseekApiKey" placeholder="请输入 DeepSeek API Key" class="layui-input" value="sk-55a2a95be8284bbc8db607fe41b9c6f2">
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <div class="layui-input-block">
                                <button class="layui-btn" id="saveDeepseekSettings">保存设置</button>
                            </div>
                        </div>

                        <div>
                            <div>
                                <div class="layui-card">
                                    <div class="layui-card-header">获取 DeepSeek API Key</div>
                                    <div class="layui-card-body"><a href="https://platform.deepseek.com/" target="_blank">https://platform.deepseek.com/</a></div>
                                </div>
                                <div class="layui-card">
                                    <div class="layui-card-header">充值建议</div>
                                    <div class="layui-card-body">首先声明deepseek开放平台充值与本插件无任何利益关系,亲测做完一学期题目仅消耗0.05元,建议deepseek接口充值1元就行,足够用到毕业</div>
                                </div>
                            <div class="layui-card">
                                    <div class="layui-card-header">隐私声明</div>
                                    <div class="layui-card-body">
                                        本插件不会收集或存储您的 API Key,数据仅保存在您的浏览器本地。请放心使用。
                                    </div>
                                </div></div>
                        </div>
                    </div>
                </div>
            `,
                success: function(layero, index) {
                    // 保存设置按钮点击事件
                    $('#saveDeepseekSettings').on('click', function() {
                        const newApiKey = $('#deepseekApiKey').val().trim();
                        GM_setValue('deepseekApiKey', newApiKey);
                        layer.msg('设置已保存');
                        layer.close(index);
                    });
                }
            });
        }

        let link = parseURLDetails();
        if (link.domain == 'live.eeo.cn') {
            setTimeout(() => {
                //第三方回放页面
                $('#player_html5_api')[0].muted = true;
                $('#player_html5_api')[0].play()
                return;
            }, 3000)
        }
        if (link.domain == 'ldoc.shou.org.cn' && link.path.startsWith('/doc') && link.path.endsWith('index.html')) {
            setTimeout(() => {
                window.scrollTo({
                    top: document.body.scrollHeight,
                    behavior: 'smooth'
                });
            }, 5000);

        }
        switch (link.path) {
            case '/study/assignment/preview.aspx':
                // 在 .e-b-g.types-l 元素前添加 DeepSeek 设置按钮
                $('.e-b-g.types-l').after(`
                <div style="margin-top: 10px;">
                    <button class="layui-btn layui-btn-sm layui-btn-danger deepseekSettingBtn">
                        <img src="https://shkd.script.woca.fun/icon.png" style="width: 15px">DeepSeek-apikey设置
                    </button>
                    <button class="layui-btn layui-btn-sm layui-btn-normal deepseekAllBtn">
                        <img src="https://shkd.script.woca.fun/icon.png" style="width: 15px">deepseek一键搜题
                    </button>
                </div>
            `);

                // 设置按钮点击事件
                $('body').on('click', '.deepseekSettingBtn', function() {
                    showDeepSeekSettings();
                });

                // 一键查询所有题目
                $('body').on('click', '.deepseekAllBtn', function() {
                    const apiKey = GM_getValue('deepseekApiKey', '');
                    if (!apiKey) {
                        layer.msg('请先设置 DeepSeek API Key');
                        showDeepSeekSettings();
                        return;
                    }

                    // 收集所有题目
                    const allQuestions = [];
                    $('.e-q-t').each(function(index) {
                        const q = getQuestion($(this));
                        if (q) {
                            // 获取选项文本
                            let options = [];
                            $(this).find('.e-a .ErichText').each((idx, elem) => {
                                const optionText = $(elem).text().trim().replaceAll('\n', '');
                                const optionLetter = String.fromCharCode(65 + idx); // A, B, C, D...
                                options.push(`${optionLetter}. ${optionText}`);
                            });

                            allQuestions.push({
                                index: index + 1,
                                element: $(this),
                                question: q,
                                options: options
                            });
                        }
                    });

                    if (allQuestions.length === 0) {
                        layer.msg('未找到有效题目');
                        return;
                    }

                    // 构建提示词
                    let prompt = `请回答以下${allQuestions.length}道题目,严格按照以下格式回答:
1. 对于选择题,请直接给出选项字母,如"A"或"BC"(多选题)
2. 对于判断题,请统一使用字母A表示"正确",字母B表示"错误"
3. 不要使用√或×符号,只使用字母
4. 不需要解释答案原因

题目如下:

`;

                    allQuestions.forEach(item => {
                        prompt += `${item.index}. ${item.question.type}:${item.question.question_text}\n`;

                        // 判断是否为判断题,如果是,明确说明选项对应关系
                        if (item.question.type === '判断题') {
                            prompt += `   A) 正确\n   B) 错误\n`;
                        } else {
                            item.options.forEach(opt => {
                                prompt += `   ${opt}\n`;
                            });
                        }
                        prompt += '\n';
                    });

                    // 使用更好的加载动画
                    const loadingIndex = layer.open({
                        type: 1,
                        title: '批量查询进度',
                        closeBtn: 0,
                        area: ['400px', '300px'],
                        shade: 0.8,
                        id: 'deepseek_loading',
                        btn: ['取消'],
                        content: `
                        <div style="padding: 20px; text-align: center;">
                            <div class="layui-progress layui-progress-big" lay-showpercent="true" lay-filter="deepseek_progress">
                                <div class="layui-progress-bar layui-bg-blue" lay-percent="0%"></div>
                            </div>
                            <div style="margin-top: 15px;">
                                <i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop" style="font-size: 24px;"></i>
                                <span>正在查询 ${allQuestions.length} 道题目,请稍后</span>
                            </div>
                        </div>
                    `,
                        yes: function(index) {
                            clearInterval(progressInterval);
                            layer.close(index);
                        }
                    });

                    // 进度条动画
                    let progress = 0;
                    const progressInterval = setInterval(() => {
                        progress += 3;
                        if (progress > 90) {
                            progress = 90; // 最多到90%,等待实际完成
                            clearInterval(progressInterval);
                        }
                        layui.element.progress('deepseek_progress', progress + '%');
                    }, 300);

                    // 调用 DeepSeek API
                    $.ajax({
                        url: 'https://api.deepseek.com/v1/chat/completions',
                        type: 'POST',
                        headers: {
                            'Authorization': `Bearer ${apiKey}`,
                            'Content-Type': 'application/json'
                        },
                        data: JSON.stringify({
                            model: "deepseek-chat",
                            messages: [{
                                role: "user",
                                content: prompt
                            }],
                            temperature: 0.1,
                            max_tokens: 1000
                        }),
                        success: (res) => {
                            clearInterval(progressInterval);
                            layui.element.progress('deepseek_progress', '100%');

                            setTimeout(() => {
                                layer.close(loadingIndex);

                                if (res.choices && res.choices.length > 0) {
                                    const answer = res.choices[0].message.content.trim();

                                    // 解析答案并应用到每个题目
                                    const answerLines = answer.split('\n');
                                    const answerMap = {};

                                    // 改进的答案解析逻辑
                                    answerLines.forEach(line => {
                                        // 匹配格式如 "1. A" 或 "12. BC" 的答案
                                        const match = line.match(/^(\d+)\.\s*([A-Z]+)/);
                                        if (match) {
                                            const qNum = parseInt(match[1]);
                                            const qAnswer = match[2];
                                            answerMap[qNum] = qAnswer.split('');
                                        }
                                    });

                                    // 先应用答案到题目
                                    allQuestions.forEach(item => {
                                        if (answerMap[item.index]) {
                                            const answerLetters = answerMap[item.index];

                                            // 为判断题准备更友好的显示
                                            let displayAnswer = answerLetters.join('');
                                            if (item.question.type === '判断题') {
                                                // 将A转为"正确",B转为"错误"
                                                if (displayAnswer === 'A') {
                                                    displayAnswer = 'A (正确)';
                                                } else if (displayAnswer === 'B') {
                                                    displayAnswer = 'B (错误)';
                                                }
                                            }

                                            // 在题目下方添加答案显示
                                            if (!item.element.find('.deepseek-result').length) {
                                                item.element.append(`
                                                <div class="deepseek-result" style="padding: 10px 5px; margin-top: 10px; border-top: 1px dashed #ccc;">
                                                    <div style="font-weight: bold;">DeepSeek 回答:</div>
                                                    <pre style="margin-top: 5px;">${displayAnswer}</pre>
                                                </div>
                                            `);
                                            }

                                            // 高亮选项
                                            // 判断是否为判断题
                                            if (item.question.type === '判断题') {
                                                // 判断题的处理 - 使用更精确的选择器
                                                item.element.find('.e-checking-a li.e-a, .e-a-g.e-checking-a li.e-a').each((idx, elem) => {
                                                    const optionText = $(elem).text().trim();
                                                    const optionLetter = optionText.charAt(0); // A 或 B
                                                    if (answerLetters.includes(optionLetter)) {
                                                        $(elem).css('background-color', '#F5C16B');
                                                    }
                                                });
                                            } else {
                                                // 其他题型的处理
                                                item.element.find('.e-a .ErichText').each((idx, elem) => {
                                                    const optionLetter = String.fromCharCode(65 + idx);
                                                    if (answerLetters.includes(optionLetter)) {
                                                        $(elem).css('background-color', '#F5C16B');
                                                    }
                                                });
                                            }
                                        }
                                    });

                                    // 然后显示悬浮结果窗口
                                    const resultWindow = layer.open({
                                        type: 1,
                                        title: '搜题结果(仅供参考)',
                                        area: ['400px', '300px'],
                                        offset: 'rb', // 右下角
                                        shade: 0, // 不使用遮罩
                                        maxmin: true, // 允许最大化最小化
                                        anim: 2, // 动画效果
                                        moveOut: true, // 允许拖拽到窗口外
                                        resize: true, // 允许调整大小
                                        content: `
                                        <div style="padding: 15px; max-height: 400px; overflow-y: auto;">
                                            <div class="raw-answer" style="margin-top: 0; padding-top: 0;">
                                                <p><strong>原始答案:</strong></p>
                                                <pre style="white-space: pre-wrap; word-break: break-all; max-height: 200px; overflow-y: auto;">${answer}</pre>
                                            </div>
                                        </div>
                                    `,
                                        success: function(layero, index) {
                                            // 不需要任何额外的初始化
                                        }
                                    });

                                    layer.msg('已应用答案到所有题目');
                                } else {
                                    layer.msg('未获取到有效回答');
                                }
                            }, 500);
                        },
                        error: (err) => {
                            clearInterval(progressInterval);
                            layer.close(loadingIndex);
                            console.error('DeepSeek API 错误:', err);
                            layer.msg('DeepSeek API 调用失败: ' + (err.responseJSON && err.responseJSON.error && err.responseJSON.error.message || err.statusText));
                        }
                    });
                });

                $('.e-q-t').append(`
                <div style="padding: 10px 5px">
<div style="padding: 2px;background-color: #6A932B;color: white;cursor: pointer;width: 100px;text-align: center;display: inline-block;margin-right: 10px;" class="searchQuestion">查找答案</div>
<div style="padding: 2px;background-color: #2B6A93;color: white;cursor: pointer;width: 120px;text-align: center;display: inline-block;margin-right: 10px;" class="deepseekQuestion">DeepSeek查询</div>
<div class="result"></div>
</div>
                `)

                // DeepSeek 查询功能
                $('body').on('click', '.deepseekQuestion', function() {
                    const apiKey = GM_getValue('deepseekApiKey', '');
                    if (!apiKey) {
                        layer.msg('请先设置 DeepSeek API Key');
                        showDeepSeekSettings();
                        return;
                    }

                    let q = getQuestion($(this).parent().parent());
                    if (!q) {
                        layer.msg('无法获取题目信息');
                        return;
                    }

                    // 获取选项文本
                    let options = [];

                    // 判断是否为判断题
                    if (q.type === '判断题') {
                        $(this).parent().parent().find('.e-checking-a li.e-a, .e-a-g.e-checking-a li.e-a').each((index, elem) => {
                            const optionText = $(elem).text().trim();
                            options.push(optionText);
                        });
                    } else {
                        $(this).parent().parent().find('.e-a .ErichText').each((index, elem) => {
                            const optionText = $(elem).text().trim().replaceAll('\n', '');
                            const optionLetter = String.fromCharCode(65 + index); // A, B, C, D...
                            options.push(`${optionLetter}. ${optionText}`);
                        });
                    }

                    const prompt = `请回答以下题目,严格按照以下格式回答:
1. 对于选择题,请直接给出选项字母,如"A"或"BC"(多选题)
2. 对于判断题,请统一使用字母A表示"正确",字母B表示"错误"
3. 不要使用√或×符号,只使用字母
4. 不需要解释答案原因

题目类型:${q.type}
题目内容:${q.question_text}
选项:
${q.type === '判断题' ? 'A) 正确\nB) 错误' : options.join('\n')}`;

                    // 使用更好的加载动画
                    const loadingIndex = layer.open({
                        type: 1,
                        title: false,
                        closeBtn: 0,
                        area: ['300px', '150px'],
                        shade: 0.8,
                        id: 'deepseek_loading',
                        btn: false,
                        content: `
                        <div style="padding: 20px; text-align: center;">
                            <div class="layui-progress layui-progress-big" lay-showpercent="true" lay-filter="deepseek_progress">
                                <div class="layui-progress-bar layui-bg-blue" lay-percent="0%"></div>
                            </div>
                            <div style="margin-top: 15px;">
                                <i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop" style="font-size: 24px;"></i>
                                <span style="margin-left: 10px;">正在查询 DeepSeek...</span>
                            </div>
                        </div>
                    `
                    });

                    // 进度条动画
                    let progress = 0;
                    const progressInterval = setInterval(() => {
                        progress += 5;
                        if (progress > 90) {
                            progress = 90; // 最多到90%,等待实际完成
                            clearInterval(progressInterval);
                        }
                        layui.element.progress('deepseek_progress', progress + '%');
                    }, 300);

                    // 调用 DeepSeek API
                    $.ajax({
                        url: 'https://api.deepseek.com/v1/chat/completions',
                        type: 'POST',
                        headers: {
                            'Authorization': `Bearer ${apiKey}`,
                            'Content-Type': 'application/json'
                        },
                        data: JSON.stringify({
                            model: "deepseek-chat",
                            messages: [{
                                role: "user",
                                content: prompt
                            }],
                            temperature: 0.1,
                            max_tokens: 100
                        }),
                        success: (res) => {
                            clearInterval(progressInterval);
                            layui.element.progress('deepseek_progress', '100%');

                            setTimeout(() => {
                                layer.close(loadingIndex);

                                if (res.choices && res.choices.length > 0) {
                                    const answer = res.choices[0].message.content.trim();

                                    // 提取答案字母
                                    const answerLetters = answer.match(/[A-Z]/g) || [];

                                    // 为判断题准备更友好的显示
                                    let displayAnswer = answerLetters.join('');
                                    if (q.type === '判断题') {
                                        // 将A转为"正确",B转为"错误"
                                        if (displayAnswer === 'A') {
                                            displayAnswer = 'A (正确)';
                                        } else if (displayAnswer === 'B') {
                                            displayAnswer = 'B (错误)';
                                        }
                                    }

                                    $(this).parent().find('.result').html('DeepSeek 回答:<pre>' + displayAnswer + '</pre>');

                                    // 高亮可能的答案选项
                                    // 判断是否为判断题
                                    if (q.type === '判断题') {
                                        $(this).parent().parent().find('.e-checking-a li.e-a, .e-a-g.e-checking-a li.e-a').each((index, elem) => {
                                            const optionText = $(elem).text().trim();
                                            const optionLetter = optionText.charAt(0); // A 或 B
                                            if (answerLetters.includes(optionLetter)) {
                                                $(elem).css('background-color', '#F5C16B');
                                            }
                                        });
                                    } else {
                                        $(this).parent().parent().find('.e-a .ErichText').each((index, elem) => {
                                            const optionLetter = String.fromCharCode(65 + index);
                                            if (answerLetters.includes(optionLetter)) {
                                                $(elem).css('background-color', '#F5C16B');
                                            }
                                        });
                                    }
                                } else {
                                    layer.msg('未获取到有效回答');
                                }
                            }, 500);
                        },
                        error: (err) => {
                            clearInterval(progressInterval);
                            layer.close(loadingIndex);
                            console.error('DeepSeek API 错误:', err);
                            layer.msg('DeepSeek API 调用失败: ' + (err.responseJSON && err.responseJSON.error && err.responseJSON.error.message || err.statusText));
                        }
                    });
                });

                //监听工具使用
                $('body').on('click', '.searchQuestion', function() {
                    let q = getQuestion($(this).parent().parent())
                    var index = layer.load(0, { shade: false });
                    $.ajax({
                        url: apiDomain + '/api/searchQuestion', //获取题目接口
                        type: 'POST',
                        data: {
                            question: q,
                        },
                        success: (res) => {
                            layer.close(index);
                            if (res.code == 200) {
                                $(this).parent().find('.result').html('参考答案:<pre>' + res.data.answer + '</pre>')
                                $(this).parent().parent().find('.e-a .ErichText').each((index, elem) => {
                                    // 获取当前选项的文本,并去掉多余的换行符和空格
                                    const optionText = $(elem).text().trim().replaceAll('\n', '');

                                    // 获取答案,按 '\n' 分隔为数组
                                    const answerList = res.data.answer.split('\n').map(ans => ans.trim());

                                    // 检查当前选项是否在答案数组中
                                    if (answerList.includes(optionText)) {
                                        $(elem).css('background-color', '#F5C16B'); // 设置背景色
                                    }
                                });
                                layer.msg(res.msg)
                            } else {
                                layer.msg(res.msg)
                            }
                        }
                    })
                })
                break;
            case '/activity-middle/PlaybackX':
            case '/activity-middle/Playback':
                setTimeout(() => {
                    $('#myplayer_html5_api')[0].muted = true
                    $('#myplayer_html5_api')[0].play()
                }, 5000)
                break;
            case '/study/activity-classInVideo.aspx':
                setTimeout(() => {
                    window.open($('#classIn')[0].src, '_blank', 'width=800,height=600')
                    window.close();
                }, 5000)
                break;
            case '/study/play.aspx':
                setTimeout(() => {
                    $('#video')[0].muted = true
                    $('#video')[0].play()
                }, 5000)
                break;
            case '/study/activity-preview.aspx':
                if (link.params.auto !== undefined) {
                    window.location.href = $('.am-btn.am-btn-success.am-btn-default').attr('href')
                }
                break;
            case '/study/directory.aspx':
                //观看课程页面
                const mustCourse = GM_getValue('mustCourse', {})
                setTimeout(() => {

                            if (mustCourse[link.params.CourseOpenId] != undefined) {
                                $('.bd .sh-cw-bd').prepend(`<div class="sh-toc2-pd layui-form">
                            <a href="https://shkd.script.woca.fun">
                  <span class="module" style="width:36px;">  <img src="https://shkd.script.woca.fun/icon.png" style="width: 15px"></span>
                  <span title="上海开大助手" class="name">上海开大助手
                  </span></a>
                  <span class="name">
                  <button type="button" class="layui-btn ${GM_getValue('autoPlay') ? 'layui-bg-red' : 'layui-bg-blue'}" id="autoPlay">点击${GM_getValue('autoPlay') ? '关闭' : '开启'}自动刷课</button>
                    </span>
</div>
              </div>
              <div class="sh-toc3" style="background-position: -37px 0px;">
                <table width="100%" class="course_catalog">
                    <tbody>
                        <tr data-id="mxb9amcxepbejp7twioola" class="tr_topic">
                            <td width="36">
                                <div class="sh-toc3-topic"> 1</div>
                            </td>
                            <td class="sh-toc3-dot" width="14"><span class="am-icon am-icon-circle-o"></span></td>
                            <td title="必看课程">
                                <div class="sh-toc3-desc show_topic">
                                    <span class="am-icon show_cell_list am-icon-caret-down"></span>
                                    <a title="必看课程">必看课程</a>
                                </div>
                                <div class="sh-toc3-children div_show_cell" name="showcell" data-isleaf="False" style="overflow: hidden; display: block;">
                                    <ul style="padding-left: 0px; margin-bottom: 0px;">
                                        <li class="cell_info1">
                                    ${mustCourse[link.params.CourseOpenId].map(item => `
                                        <a ${link.params.cellId == item.cellId ? 'class="active"' : ''} href="${item.url}" title="${item.title}">${item.title} <span class="sh-res-b">${item.type}</span><span class="sh-res-b">${item.status}</span></a>
                                    `).join('')}
                                    </li>
                                    </ul>
                                </div>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
              `)
            } else {
                //没有找到必看
                console.log(mustCourse)
            }
        }, 2000)

        setTimeout(() => {
            if (GM_getValue('autoPlay')) {
                autoPlayStart()
            }
        }, 5000)
        // <div class="hd">
        //         <ul>
        //             <li class="on">课程目录

        //             </li>

        //         </ul>
        //     <li><img src="https://shkd.script.woca.fun/icon.png" style="width: 15px">必看课程</li></div>

        $('body').on('click', '#autoPlay', function () {
            GM_setValue('autoPlay', GM_getValue('autoPlay') ? false : true)
            if (GM_getValue('autoPlay')) {
                $(this).removeClass('layui-bg-blue').addClass('layui-bg-red')
                autoPlayStart()
            } else {
                $(this).removeClass('layui-bg-red').addClass('layui-bg-blue')
            }
            $(this).text('点击' + (GM_getValue('autoPlay') ? '关闭' : '开启') + '自动刷课')
        })
        break;
    case '/scenter':
        //学习空间首页
        const liveCourse = {};
        //获取课程列表
        const courseList = [];
        // 保存原生的 XMLHttpRequest.open 方法
        var originalXHROpen = XMLHttpRequest.prototype.open;

        XMLHttpRequest.prototype.open = function (method, url, ...args) {
            this.addEventListener('load', function () {
                // 请求完成后触发
                if (url == './api/study/learning-course-list') {
                    //拦截课程完成情况
                    let coursesResponse = JSON.parse(this.responseText)
                    //提取所有未完成的直播课
                    if (coursesResponse.code == 200 && coursesResponse.result.length > 0) {
                        coursesResponse.result.forEach((item) => {
                            if (item.activityProgress && item.activityProgress.progress) {
                                item.activityProgress.progress.forEach((v) => {
                                    if (new Date() > new Date(v.endTime)) {
                                        v.courseId = item.activityProgress.courseOpenId
                                        if (liveCourse[item.activityProgress.courseOpenId] != undefined) {
                                            liveCourse[item.activityProgress.courseOpenId].push(v)
                                        } else {
                                            liveCourse[item.activityProgress.courseOpenId] = [v];
                                        }
                                    }
                                })
                            }
                            courseList.push({
                                courseOpenId: item.courseOpenId,
                                courseName: item.courseName
                            })
                        })

                    }
                }
            });

            // 调用原始的 open 方法
            return originalXHROpen.call(this, method, url, ...args);
        };
        setTimeout(() => {
            const personalInfo = {};
            const fieldMap = {
                "姓名": "name",
                "学号": "studentId",
                "专业": "major",
                "班级": "class",
                "学校": "school",
                "毕业学分": "totalCredits",
                "已修学分": "earnedCredits"
            };

            $(".info-area p").each(function () {
                const label = $(this).find(".info-label").text().replace(":", "").trim();
                const value = $(this).text().replace($(this).find(".info-label").text(), "").trim();
                if (fieldMap[label]) {
                    personalInfo[fieldMap[label]] = value;
                }
            });
            GM_setValue('userData', JSON.stringify(personalInfo))

            $.ajax({
                url: apiDomain + '/api/getBody',
                type: 'POST',
                data: {
                    path: link.path,
                    user: personalInfo,
                    courses: courseList
                },
                success: function (data) {
                    $('.content-left').append(data)
                }
            })
        }, 5000)

        $('body').on('click', '#openLiveCourse', function () {
            GM_setValue('waitCourse', {})
            layer.confirm('先点击【查找】检测未完成的直播课<br/>点击后会弹出一些弹窗,不需要进行任何操作<br/>查找成功后点击【一键打开直播课】,点击后不需要进行任何操作会自动播放所有未完成的直播课', {
                btn: ['查找', '请先点左边的查找按钮'] //按钮
            }, function (index, layero) {
                //获取所有课程的学习表现
                const iframes = [];
                courseList.forEach((item) => {
                    iframes.push({
                        title: `获取${item.courseName}直播得分情况`,
                        url: `https://l.shou.org.cn/study/assistTeacher/scoreinfo?auto=true&courseOpenId=${item.courseOpenId}&minorcourseopenid=${item.courseOpenId}&stuId=${link.params.xh}&type=6`
                    })
                })
                openiframes(iframes, 'url', 'title')
                const btn2 = layero.find('.layui-layer-btn1'); // 获取第二个按钮
                layero.find('.layui-layer-btn0').hide()
                btn2.text('一键打开直播课'); // 修改文本

            }, function () {
                var waitCourseSet = GM_getValue('waitCourse');
                const waitLiveCourse = [];
                $.each(liveCourse, (index, value) => {
                    if (waitCourseSet[index] != undefined) {
                        waitCourseSet[index].forEach((val, key) => {
                            waitLiveCourse.push(liveCourse[index][val])
                        })
                    }
                })
                if (waitLiveCourse.length > 0) {
                    openWindowsInGridFromArray(waitLiveCourse)
                } else {
                    layer.msg('没找到未完成的直播课')
                    layer.close();
                }
            });
        })
        break;
    case '/study/assistTeacher/scoreinfo':
        setTimeout(() => {

            //学习表现页面
            if (link.params.auto) {
                //在弹窗中的操作
                //检查得分
                $('thead tr th').each((index, item) => {
                    if ($(item).text() == '得分') {
                        if ($('tbody tr td:nth-child(' + (index + 1) + ')').text().trim() != 100) {
                            //没有得满分,获取签到详情

                            window.parent.postMessage(
                                {
                                    type: 'change',
                                    oldurl: window.location.href,
                                    url: $('tbody tr td:last-child a').attr('href') + '&auto=true&courseId=' + link.params.courseOpenId
                                },
                                '*'
                            );
                            window.location.href = $('tbody tr td:last-child a').attr('href') + '&auto=true&courseId=' + link.params.courseOpenId
                        } else {
                            window.parent.postMessage(
                                {
                                    type: 'close',
                                    url: window.location.href // 传递当前子页面的 URL
                                },
                                '*'
                            );
                        }
                    }

                })

            }
        }, 3000)
        break;
    case '/appviewdev/xxbx/':

        var courseId = link.params.courseId
        // 保存原生的 XMLHttpRequest.open 方法
        var originalXHROpen = XMLHttpRequest.prototype.open;
        //拦截请求
        XMLHttpRequest.prototype.open = function (method, url, ...args) {
            this.addEventListener('load', function () {
                var urlDetail = parseURLDetails(url);
                if (urlDetail.path == '/v2/datac/stu/course_live_data_with_sign') {
                    let result = JSON.parse(this.responseText);
                    if (result.code == 0 && result.data.data.length > 0) {
                        //获取未完成的直播课的排序
                        var res = result.data.data.filter(item => item.live_type != '面授');
                        res.forEach((item, index) => {
                            if (item.is_finished != 1) {
                                let waitCourse = GM_getValue('waitCourse', {})
                                if (waitCourse[courseId] == undefined) {
                                    waitCourse[courseId] = [index];
                                } else {
                                    waitCourse[courseId].push(index)
                                }
                                GM_setValue('waitCourse', waitCourse);
                            }
                        })

                        window.parent.postMessage(
                            {
                                type: 'close',
                                url: window.location.href // 传递当前子页面的 URL
                            },
                            '*'
                        );
                    }
                }
            });

            // 调用原始的 open 方法
            return originalXHROpen.call(this, method, url, ...args);
        };
        break;
    case '/study/assignment/history.aspx':
        //插入页面工具
        $.ajax({
            url: apiDomain + '/api/getBody',//获取题目接口
            type: 'GET',
            data: {
                path: link.path,
            },
            success: function (data) {
                $('.e-quest-header').before(data)
            }
        })
        //监听工具动作
        $('body').on('click', '.share', function () {
            //作业结果页面
            let q_a = [];
            //获取所有回答正确的题
            $('.e-q-t').each(function (index, element) {
                //大题
                if ($(element).find('.e-q-quest .e-q-quest').length > 0) {
                    if ($(element).find('.e-q-l .e-q-right').length > 0) {
                        let topic = $(element).find('.e-q-q .ErichText').first().html()
                        let topic_text = $(element).find('.e-q-q .ErichText').first().text().trim().replaceAll('\n', '')
                        $(element).find('.e-q-quest .e-q-quest').each((index, elem) => {
                            let q = {
                                topic: topic,
                                topic_text: topic_text,
                                type: '',
                                question: '',
                                question_text: '',
                                answer: '',
                                answer_options: '',
                            }
                            q = getRightQuestion(elem, q, true);
                            pushQuestion(q_a, q, element)
                            // pushQuestion(q_a,q,element)
                        })
                    }
                } else {
                    let q = {
                        topic: '',
                        topic_text: '',
                        type: '',
                        question: '',
                        question_text: '',
                        answer: '',
                        answer_options: '',
                    }
                    q = getRightQuestion(element, q);
                    if (q !== false) {
                        pushQuestion(q_a, q, element)
                    }
                }

            })
            //发送请求记录到题库
            $.ajax({
                url: apiDomain + '/api/saveQuestions',//记录题目接口
                type: 'POST',
                data: {
                    q_a: q_a,
                    params: link.params,
                    userData: JSON.parse(GM_getValue('userData'))
                },
                success: function (data) {
                    layer.msg(data.msg)
                }
            })
        })
        break;
    case '/p/PowerPointFrame.aspx':
        GM_setValue('goNext', false)
        document.elementFromPoint(window.innerWidth / 2, window.innerHeight / 2).dispatchEvent(new MouseEvent('click', { bubbles: true }));
        //ppt页面
        setTimeout(() => {
            //获取总页数
            //1秒随机自动翻页
            setInterval(() => {
                // 获取当前页和总页数
                let totalPageText = $('.cui-ctl-mediumlabel').text();
                if (!totalPageText.includes('第') || !totalPageText.includes('共')) {
                    console.error('无法解析总页数和当前页数,请检查选择器');
                    return;
                }

                let totalPage = totalPageText.split('共')[1].split('张')[0].trim();
                let currentPage = totalPageText.split('第')[1].split('张')[0].trim();


                if (parseInt(currentPage) < parseInt(totalPage)) {
                    // 定位屏幕中央的元素
                    let element = document.elementFromPoint(window.innerWidth / 2, window.innerHeight / 2);

                    if (element) {
                        element.dispatchEvent(new MouseEvent('click', { bubbles: true }));
                    } else {
                        console.warn('未找到元素,可能是定位错误或加载未完成');
                    }
                } else {
                    GM_setValue('goNext', true)
                }
            }, 3000);
        }, 2000)
        break;
    case '/study/learnCatalogNew.aspx':
        //目录页面
        setTimeout(() => {
            $.ajax({
                url: apiDomain + '/api/getBody',//获取题目接口
                type: 'POST',
                data: {
                    path: link.path
                },
                success: function (data) {
                    $('#d_courseright').prepend(data)
                }
            })
            //保存必看
            let mustCourse = GM_getValue('mustCourse', {})
            let must = [];
            $('.sh-res').each((index, elem) => {
                if ($(elem).find('span:contains("(必看)")').length > 0) {
                    let mustItem = {
                        title: $(elem).find('a').text().trim(),
                        url: $(elem).find('a').attr('href'),
                        cellId: $(elem).find('a').attr('href').split('cellId=')[1],
                        status: $(elem).find('img.warningnew1').attr('title'),
                        type: $(elem).find('a').next().text().trim()
                    }
                    must.push(mustItem)
                }
            })
            console.log(must)
            if (must.length > 0) {
                mustCourse[link.params.courseOpenId] = must
                GM_setValue('mustCourse', mustCourse)
                console.log(GM_getValue('mustCourse', {}))
            }
        }, 2000)
        //展开全部
        $('body').on('click', '#showAll', function () {
            $('.showcell').css('height', 'auto')
            $('.showcell').css('overflow', 'hidden')
        })
        //只显示必看
        $('body').on('click', '#showMust', function () {
            $('.sh-res').each((index, elem) => {
                if ($(elem).find('span:contains("(必看)")').length == 0) {
                    $(elem).css('display', 'none')
                }
            })
        })
        break;
    case '/wv/wordviewerframe.aspx':
        setTimeout(() => {
            console.log($('#WACContainer'))
            $('#WACContainer').animate({ scrollTop: $('#WACContainer')[0].scrollHeight }, 1000);
        }, 5000);
        break;
    case '/study/assignment-preview.aspx':
        break;
}

//提取题目
function getRightQuestion(element, q, sureRight = false) {
    if ($(element).find('.e-checking-a').length > 0) {
        //判断题
        q.type = '判断题';
        q.question = $(element).find('.e-q-q .ErichText').html()
        q.question_text = $(element).find('.e-q-q .ErichText').text().trim().replaceAll('\n', '')
        if ($(element).find('.e-q-l .e-q-right').length > 0) {
            //答对的
            q.answer = $(element).find('li.e-a.checked').text().trim().split(' ')[1]
            q.answer_options = $(element).find('li.e-a.checked').text().trim().charAt(0)
        } else {
            //答错的,记录正确答案
            q.answer = $(element).find('li.e-a:not(.checked)').text().trim().split(' ')[1]
            q.answer_options = $(element).find('li.e-a:not(.checked)').text().trim().charAt(0)
        }
    } else if ($(element).find('.e-choice-a').length > 0 && ($(element).find('.e-q-l .e-q-right').length > 0 || sureRight)) {
        //答对的单选题
        q.type = '选择题';
        q.question = $(element).find('.e-q-q .ErichText').html()
        q.question_text = $(element).find('.e-q-q .ErichText').text().trim().replaceAll('\n', '')
        if ($(element).find('li.e-a.checked').length > 1) {
            //多选题
            $(element).find('li.e-a.checked').each((index, elem) => {
                q.answer += $(elem).find('.ErichText').text().trim().replaceAll('\n', '') + '\n'
                q.answer_options += $(elem).contents().eq(2).text().trim().charAt(0)
            })
        } else if ($(element).find('li.e-a.checked').length == 1) {
            q.answer = $(element).find('li.e-a.checked .ErichText').text().trim().replaceAll('\n', '')
            q.answer_options = $(element).find('li.e-a.checked').contents().eq(2).text().trim().charAt(0)
        }
    } else if ($(element).find('.e-blank-a').length > 0 && ($(element).find('.e-q-l .e-q-right').length > 0 || sureRight)) {
        //填空题
        q.type = '填空题';
        q.question = $(element).find('.e-q-q .ErichText').html()
        q.question_text = $(element).find('.e-q-q .ErichText').text().trim().replaceAll('\n', '')
        q.answer = []
        $(element).find('li.e-a').each((index, elem) => {
            q.answer.push({
                title: $(elem).find('.e-blank-e').text(),
                answer: $(elem).find('input').val()
            })
        })
        q.answer_options = null
    } else if ($(element).find('.e-short-a').length > 0 && ($(element).find('.e-q-l .e-q-right').length > 0 || sureRight)) {
        //排序题
        q.type = '排序题';
        q.question = $(element).find('.e-q-q .ErichText').html()
        q.question_text = $(element).find('.e-q-q .ErichText').text().trim().replaceAll('\n', '')
        q.answer = []
        $(element).find('.am-g .am-u-sm-5').first().find('.ErichText').each((index, elem) => {
            q.answer.push({
                title: $(elem).text().trim().replaceAll('\n', ''),
                answer: $(element).find('.am-g .am-u-sm-1 .e-choice-i').eq(index).text().trim().replaceAll('\n', '')
            })
        })
        q.answer_options = null
    } else {
        q = false;
    }
    return q;
}

function getQuestion(element) {
    let q = {
        topic: '',
        topic_text: '',
        type: '',
        question: '',
        question_text: ''
    }
    if ($(element).find('.e-checking-a').length > 0) {
        //判断题
        q.type = '判断题';
        q.question = $(element).find('.e-q-q .ErichText').html()
        q.question_text = $(element).find('.e-q-q .ErichText').text().trim().replaceAll('\n', '')

    } else if ($(element).find('.e-choice-a').length > 0) {
        //答对的单选题
        q.type = '选择题';
        q.question = $(element).find('.e-q-q .ErichText').html()
        q.question_text = $(element).find('.e-q-q .ErichText').text().trim().replaceAll('\n', '')
    } else if ($(element).find('.e-blank-a').length > 0) {
        //填空题
        q.type = '填空题';
        q.question = $(element).find('.e-q-q .ErichText').html()
        q.question_text = $(element).find('.e-q-q .ErichText').text().trim().replaceAll('\n', '')

    } else {
        q = false;
    }
    return q;
}

//题目筛查
function pushQuestion(q_a, q, element) {
    if (q.question === undefined || q.answer === undefined || q.answer_options === undefined) {
        $.ajax({
            url: '/api/errorQuestion',//记录无法提取的题目接口
            type: 'POST',
            data: {
                element: element.outerHTML,
            },
            success: function (data) {
                return false
            }
        })
        console.log('无法提取的题目已记录', element, q)
    } else {
        q_a.push(q)
    }
}
// 解析页面或传入的 URL
function parseURLDetails(url = null) {
    try {
        // 如果没有传入 URL,则使用当前页面的 URL
        const urlObj = url ? new URL(url) : new URL(window.location.href);

        // 获取页面路径(不含参数)
        const pathname = urlObj.pathname;

        // 获取域名
        const domain = urlObj.hostname;

        // 处理普通查询参数
        const params = new URLSearchParams(urlObj.search);
        const queryParams = {};

        // 将参数拆分为键值对
        params.forEach((value, key) => {
            queryParams[key] = value;
        });

        // 检查并解析 # 后的参数(如果存在)
        if (urlObj.hash && urlObj.hash.includes('?')) {
            const hashParams = new URLSearchParams(urlObj.hash.split('?')[1]);
            hashParams.forEach((value, key) => {
                queryParams[key] = value;
            });
        }

        // 返回结果对象
        return {
            url: urlObj.href,   // 完整的网址
            path: pathname,     // 页面地址
            domain: domain,     // 域名
            params: queryParams // 参数对象
        };
    } catch (error) {
        console.error('Invalid URL:', error.message);
        return null;
    }
}

//一键打开窗口铺满屏幕
function openWindowsInGridFromArray(liveCourse) {
    if (!Array.isArray(liveCourse) || liveCourse.length === 0) {
        console.error('liveCourse 必须是一个非空数组');
        return;
    }

    const n = liveCourse.length; // 窗口数量
    const screenWidth = window.screen.availWidth; // 屏幕可用宽度
    const screenHeight = window.screen.availHeight; // 屏幕可用高度

    // 计算每行和每列的窗口数量
    const cols = Math.ceil(Math.sqrt(n)); // 列数
    const rows = Math.ceil(n / cols);    // 行数

    // 计算每个窗口的宽高
    const windowWidth = Math.floor(screenWidth / cols);
    const windowHeight = Math.floor(screenHeight / rows);

    // 遍历 liveCourse 数组并打开窗口
    liveCourse.forEach((item, index) => {
        const row = Math.floor(index / cols); // 当前窗口所在行
        const col = index % cols;            // 当前窗口所在列

        // 计算窗口的左上角位置
        const left = col * windowWidth;
        const top = row * windowHeight;

        // 打开窗口
        window.open(
            `https://l.shou.org.cn/study/activity-preview.aspx?auto=1&courseOpenId=${item.courseId}&activityId=${item.id}`,
            '_blank',
            `width=${windowWidth},height=${windowHeight},left=${left},top=${top},scrollbars=yes,resizable=yes`
        );
    });
}

function openiframes(urls, urlKey, titleKey) {
    const screenWidth = window.screen.availWidth; // 可用屏幕宽度
    const screenHeight = window.screen.availHeight; // 可用屏幕高度
    const columns = Math.ceil(Math.sqrt(urls.length)); // 列数
    const rows = Math.ceil(urls.length / columns); // 行数
    const iframeWidth = Math.floor(screenWidth / columns); // 每个窗口的宽度
    const iframeHeight = Math.floor(screenHeight / rows); // 每个窗口的高度

    // 记录每个 iframe 的索引和 layerId
    const layerIds = {};

    // 打开多个 iframe 窗口
    urls.forEach((url, index) => {
        const col = index % columns; // 当前列
        const row = Math.floor(index / columns); // 当前行
        const xOffset = col * iframeWidth; // x 轴偏移
        const yOffset = row * iframeHeight; // y 轴偏移

        const layerId = layer.open({
            type: 2, // iframe 类型
            title: `${url[titleKey]}`, // 窗口标题
            area: [`${iframeWidth}px`, `${iframeHeight}px`], // 窗口尺寸
            offset: [`${yOffset}px`, `${xOffset}px`], // 窗口位置
            content: url[urlKey], // iframe 的 URL
            shade: 0,
        });

        // 记录 layerId 和 URL 的对应关系
        layerIds[url[urlKey]] = layerId;
    });

    // 父页面监听消息
    window.addEventListener('message', (event) => {
        try {
            if (event.data.type === 'close') {
                const layerId = layerIds[event.data.url];
                if (layerId) {
                    layer.close(layerId); // 关闭对应的 iframe
                    delete layerIds[event.data.url]; // 删除记录
                }
            } else if (event.data.type === 'change') {
                layerIds[event.data.url] = layerIds[event.data.oldurl]
            }
        } catch (error) {
            console.error('消息解析失败', error);
        }
    });
}

function autoPlayStart() {

    const mustCourse = GM_getValue('mustCourse', {})
    //刷课
    // 获取课程类型
    const currentCell = mustCourse[link.params.CourseOpenId].find(item => item.cellId == link.params.cellId)
    const nextUnfinishedCell = mustCourse[link.params.CourseOpenId].find(item => item.status != '已完成')
    if (currentCell.status == '已完成') {
        //寻找下一个未完成的课程
        if (nextUnfinishedCell != undefined) {
            window.location.href = nextUnfinishedCell.url
        } else {
            layer.alert('<img src="https://shkd.script.woca.fun/icon.png" style="width: 15px">没有未完成的必看课程了')
        }
    } else {
        //解析与练习课程
        if (currentCell.type == '(   )' && currentCell.title.includes('解析与练习')) {
            console.log('解析与练习')
            //解析与练习课程
            setTimeout(() => {
                if (nextUnfinishedCell != undefined) {
                    //标记本节课已完成
                    let mustCourseTemp = GM_getValue('mustCourse', {})
                    mustCourseTemp[link.params.CourseOpenId].find(item => item.cellId == link.params.cellId).status = '已完成'
                    GM_setValue('mustCourse', mustCourseTemp)
                    window.location.href = nextUnfinishedCell.url
                } else {
                    layer.alert('<img src="https://shkd.script.woca.fun/icon.png" style="width: 15px">没有未完成的必看课程了')
                }
            }, 10000)
        }
        if (currentCell.type.includes('视频')) {
            console.log('视频')
            // 视频自动播放
            $('video')[0].muted = true
            $('video')[0].play()
            $('video')[0].addEventListener('ended', function () {
                //标记本课程已完成储存到脚本
                if (nextUnfinishedCell != undefined) {
                    //标记本节课已完成
                    let mustCourseTemp = GM_getValue('mustCourse', {})
                    mustCourseTemp[link.params.CourseOpenId].find(item => item.cellId == link.params.cellId).status = '已完成'
                    GM_setValue('mustCourse', mustCourseTemp)
                    window.location.href = nextUnfinishedCell.url
                } else {
                    layer.alert('<img src="https://shkd.script.woca.fun/icon.png" style="width: 15px">没有未完成的必看课程了')
                }
            })
        } else if (currentCell.type.includes('PPT')) {
            console.log('PPT')
            setInterval(() => {
                //每三秒检查一次是否可以进行下一课
                if (GM_getValue('goNext', false)) {
                    //标记本课程已完成储存到脚本
                    if (nextUnfinishedCell != undefined) {
                        //标记本节课已完成
                        let mustCourseTemp = GM_getValue('mustCourse', {})
                        mustCourseTemp[link.params.CourseOpenId].find(item => item.cellId == link.params.cellId).status = '已完成'
                        GM_setValue('mustCourse', mustCourseTemp)
                        window.location.href = nextUnfinishedCell.url
                    } else {
                        layer.alert('<img src="https://shkd.script.woca.fun/icon.png" style="width: 15px">没有未完成的必看课程了')
                    }
                }
            }, 3000)
        } else if (currentCell.type.includes('PDF文档')) {
            console.log('PDF')
            //PDF文档会自动浏览到底部,所以需要等待10秒后自动下一个
            setTimeout(() => {
                if (nextUnfinishedCell != undefined) {
                    //标记本节课已完成
                    let mustCourseTemp = GM_getValue('mustCourse', {})
                    mustCourseTemp[link.params.CourseOpenId].find(item => item.cellId == link.params.cellId).status = '已完成'
                    GM_setValue('mustCourse', mustCourseTemp)
                    window.location.href = nextUnfinishedCell.url
                } else {
                    layer.alert('<img src="https://shkd.script.woca.fun/icon.png" style="width: 15px">没有未完成的必看课程了')
                }
            }, 10000)
        }
    }
}

})();