Greasy Fork

Greasy Fork is available in English.

上海开大助手

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

// ==UserScript==
// @name         上海开大助手
// @namespace    http://tampermonkey.net/
// @homepage     https://shkd.script.woca.fun
// @description  上海开放大学学习平台,自动刷课,题目共享,接入deepseek一键搜题
// @author       AchieveHF
// @version      1.1.8
// @match        *://shkd.script.woca.fun/*
// @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 scriptVersion = GM_info.script.version;
    // 将版本号保存到localStorage中供官网使用
    localStorage.setItem('shkd_script_version', scriptVersion);
    const link = parseURLDetails();

    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/';
    // DeepSeek 设置弹窗函数
    function showDeepSeekSettings() {
        // 获取当前保存的 API Key
        const apiKey = GM_getValue('deepseekApiKey', '');

        layer.open({
            type: 1,
            title: 'DeepSeek API 设置',
            area: ['50%', '50%'],
            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="">
                        </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-body"><a href="https://platform.deepseek.com/api_keys" target="_blank" style="color: #009688;">获取 DeepSeek API Key</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);
                });
            }
        });
    }

    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/continuation.aspx':
        case '/study/assignment/preview.aspx':
            let showAnswer = true;
            //添加设置按钮
            $('.e-q-panel').first().before(`
                <div style="margin-top: 10px;">
                    <button class="layui-btn layui-btn-sm layui-btn-primary deepseekSettingBtn">
                        <img src="https://shkd.script.woca.fun/icon.png" style="width: 15px">DeepSeek-apikey设置
                    </button>
                </div>
            `);
            //做作业页面
            //收集题目
            getQuestions();

            $('body').on('click', '.deepseekSettingBtn', function () {
                showDeepSeekSettings();
            });

            $('body').on('click', '.deepseekQuestion', function () {
                const questiontext = $(this).closest('.e-q-body').find('.e-q-quest').first().text().replace(/\s+/g, ' ').trim();
                if (questiontext == '') {
                    layer.msg('暂时未适配此题型');
                    $(this).parent().remove();
                    return;
                }
                //大题情况要携带题干
                const prompt = `我给你传题目内容,你给我返回正确的答案,尽量通过我发给你的题目内容中的选项来回答,我通过你返回的答案来回选正确答案,不需要解释题目,直接发给我答案,任何解释都不要,只要返回答案,答案从题目的选项中提取,如果是大题回答的答案每题用换行标签'<br/>'隔开,题目为:【${questiontext}】`
                const apiKey = GM_getValue('deepseekApiKey', '');
                if (!apiKey) {
                    layer.msg('请先设置 DeepSeek API Key');
                    showDeepSeekSettings();
                    return;
                }
                $(this).html(`
                    <img src="https://www.deepseek.com/favicon.ico" style="width: 18px">思考中...
                `);
                $.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) => {
                        console.log(res);
                        const answer = res.choices[0].message.content.trim();
                        $(this).closest('.e-q-body').find('.e-q-r').append(`
                            <div class="answer-display" style="margin-top: 10px; padding: 8px; background-color: #f0f8ff; border-left: 4px solid #1e9fff; border-radius: 4px;">
                                <div style="font-weight: bold; color: #1e9fff;">
                                    <img src="https://www.deepseek.com/favicon.ico" style="width: 18px">参考答案:
                                </div>
                                <div style="margin-top: 5px;">${answer}</div>
                            </div>
                        `);
                        //todo:记录deepseek返回的答案

                        //清除按钮
                        $(this).closest('.e-q-body').find('.deepseekQuestion').remove();
                    },
                    error: (err) => {
                        showDeepSeekSettings();
                        //恢复答题按钮
                        $(this).html(`
                            <img src="https://www.deepseek.com/favicon.ico" style="width: 18px">deepseek回答
                        `);
                        layer.msg('DeepSeek API 调用失败: ' + (err.responseJSON && err.responseJSON.error && err.responseJSON.error.message || err.statusText));
                    }
                });
            });
            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':
            //作业结果页面
            //收集正确题目
            getAnswers();
            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)
                    }
                })
                if (must.length > 0) {
                    mustCourse[link.params.courseOpenId] = must
                    GM_setValue('mustCourse', 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(() => {
                $('#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-choice-q').length > 0) {


        } else 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('视频') || currentCell.type.includes('音频')) {
                // 视频自动播放
                $('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')) {
                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('文档')) {
                //文档会自动浏览到底部,所以需要等待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)
            }else{
                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)
            }
        }
    }

    //渲染答题工具
    function QuestionAnalysis() {
        //查询本业面所有题目类型标题
        let questionTypeList = [];
        $('.types-l').find('a').each(function (key, item) {
            questionTypeList.push($(item).attr('title').trim())
        })
        console.log(questionTypeList)
        $('.typebox').each(function (key, item) {
            $(item).attr('typeTitle', questionTypeList[key])
        })
        //支持的题目类型
        let doQuestionType = [];
        // 获取库中支持的题型
        $.ajax({
            url: apiDomain + 'api/questionType',
            type: 'GET',
            success: function (data) {
                doQuestionType = data.data.reduce((acc, item) => {
                    acc[item.id] = item;
                    return acc;
                }, {});
                console.log(doQuestionType)

                //本业面的所有题目类型id
                let questionTypeIds = [];
                //获取页面所有题目
                $('.e-q-body').each(function (key, item) {

                    //获取题目类型
                    let questionType = $(item).data('questiontype');
                    if (!questionTypeIds.includes(questionType)) {
                        questionTypeIds.push(questionType);
                    }
                    //查看是否是大题
                    if ($(item).find('.e-q-quest').length == 1) {
                        //正常题目
                        if (doQuestionType[questionType]['status'] == 1) {
                            //支持查询的题型
                            $(item).find('.e-q-quest').eq(0).append(
                                `
                                    <div style="padding: 10px 5px">
                                        <button type="button" class="searchAnswer layui-btn layui-btn-sm" data-questionType="${questionType}"><i class="layui-icon layui-icon-search"></i>搜索答案</button>
                                        <button type="button" class="deepseekQuestion layui-btn layui-btn-sm layui-bg-blue" data-questionType="${questionType}">deepseek答题</button>
                                        <div class="searchResult"></div>
                                        <div class="deepseekResult"></div>
                                    </div>
                                    `
                            )
                        } else {
                            //不支持的题型,通过接口反馈
                            $.ajax({
                                url: apiDomain + 'api/errorQuestion',
                                type: 'POST',
                                data: {
                                    element: item.outerHTML,
                                    questionType: questionType
                                },
                                success: function (data) {
                                    console.log(data)
                                }
                            })
                        }
                    } else {
                        //大题

                    }
                })
                console.log(questionTypeIds)
            }
        })
    }

    function getQuestions() {
        //获取页面所有题目
        const questions = [];
        const mainQuestions = [];

        //获取所有子题目
        $('form').each(function (key, item) {
            //排序题忽略
            if ($(item).find('.e-a-g.e-short-a').length > 0) {
                return;
            }
            const hiddenInputs = $(item).find('input[type="hidden"]');
            const formQuestion = {};
            formQuestion.action = $(item).attr('action');
            //获取题目标识
            hiddenInputs.each(function () {
                const name = $(this).attr('name');
                if (name !== 'answer') {
                    const value = $(this).val();
                    formQuestion[name] = value;
                }
            });
            if (formQuestion['subQuestionId'] !== undefined && formQuestion['studentWorkId'] !== undefined) {
                // 说明这个题目是大题内的子题目
                // 先确定这个大题题干是否已经获取了
                let mainQuestion = mainQuestions.find(item => item.studentWorkId == formQuestion['studentWorkId']);
                if (!mainQuestion) {
                    // 获取大题的题干
                    let questionBody = $(item).prevAll('.e-q-q').first();
                    if (questionBody.length > 0) { // 确保questionBody存在
                        let questionType = $(item).closest('.e-q-body').data('questiontype');
                        mainQuestion = {
                            question: questionBody.find('.ErichText').text().trim(),
                            question_html: questionBody.find('.ErichText').html().trim(),
                            studentWorkId: formQuestion['studentWorkId'],
                            questionType: questionType
                        };
                        mainQuestions.push(mainQuestion);
                    }
                }
            }
            //获取题目内容
            formQuestion.question = $(item).find('.e-q-q .ErichText').text().trim();
            formQuestion.question_html = $(item).find('.e-q-q .ErichText').html().trim();
            //获取选项
            formQuestion.options = [];
            if ($(item).find('.e-a-g ul li').length > 0) {
                $(item).find('.e-a-g ul li').each(function (key, items) {
                    let option = {};
                    if ($(items).find('.ErichText').length > 0) {
                        option.content = $(items).find('.ErichText').text().trim();
                        option.content_html = $(items).find('.ErichText').html().trim();
                    } else {
                        option.content = $(items).text().trim();
                    }
                    option.index = $(items).data('index');
                    if ($(items).attr('role')) {
                        option.role = $(items).attr('role');
                    }
                    if ($(items).data('subquestiontype')) {
                        option.subQuestionType = $(items).data('subquestiontype');
                    }
                    formQuestion.options.push(option)
                })
            } else {
                return;
            }
            questions.push(formQuestion);
        })

        //把题目上传到题库
        $.ajax({
            url: apiDomain + 'api/getQuestions',
            type: 'POST',
            data: {
                questions: JSON.stringify(questions),
                userData: JSON.parse(GM_getValue('userData')),
                link: link,
                mainQuestions: JSON.stringify(mainQuestions)
            },
            success: function (data) {
                if (data.questionHasAnswer.length > 0) {
                    //遍历题目,如果题目存在正确答案,则渲染到页面上去
                    data.questionHasAnswer.forEach(item => {
                        // 查找匹配的题目
                        $('form').each(function () {
                            const questionText = $(this).find('.e-q-q .ErichText').text().trim();
                            if(questionText == ''){
                                //获取题号
                                const questionNum = $(this).find('.e-q-no').text().trim().split('、')[0];
                            }
                            if (questionText === item.question) {
                                // 创建答案显示区域
                                if (!$(this).find('.e-q-quest').parent().find('.answer-display').length) {
                                    $(this).find('.e-q-quest').parent().append(`
                                        <div class="answer-display" style="margin-top: 10px; padding: 8px; background-color: #f0f8ff; border-left: 4px solid #1e9fff; border-radius: 4px;width: 98%;">
                                            <div style="font-weight: bold; color: #1e9fff;">
                                                <img src="https://shkd.script.woca.fun/icon.png" style="width: 18px">参考答案:
                                            </div>
                                            <div style="margin-top: 5px;">${item.answer}</div>
                                        </div>
                                    `);
                                }

                                // 高亮正确选项
                                if (item.answer_index !== undefined) {
                                    $(this).find(`.e-a-g ul li[data-index="${item.answer_index}"]`).css({
                                        'background-color': '#f0f8ff',
                                        'border-left': '2px solid #1e9fff'
                                    });
                                }
                            }
                        });
                    });
                    //大题中题目没有题干部分
                    $('form').each(function (index,formitem) {
                        const questionText = $(this).find('.e-q-q .ErichText').text().trim();
                        if(questionText == ''){
                            const mainQuestionText = $(this).prevAll('.e-q-q').first().find('.ErichText').text().trim();
                            //获取题号
                            const questionNum = $(this).find('.e-q-no').text().trim().split('、')[0];
                            data.mainQuestionHasAnswer.forEach(item => {
                                if(item.main_question == mainQuestionText){
                                    item.answers.forEach(answer => {
                                        if(answer.question_num == questionNum){
                                            $(this).find('.e-q-quest').parent().append(`
                                                <div class="answer-display" style="margin-top: 10px; padding: 8px; background-color: #f0f8ff; border-left: 4px solid #1e9fff; border-radius: 4px;width: 98%;">
                                                    <div style="font-weight: bold; color: #1e9fff;">
                                                        <img src="https://shkd.script.woca.fun/icon.png" style="width: 18px">参考答案:
                                                    </div>
                                                    <div style="margin-top: 5px;">${answer.answer}</div>
                                                </div>
                                            `);
                                        }
                                    })
                                }
                            })
                        }
                    });
                    
                    // 如果有答案,显示提示消息
                    layer.msg(`<img src="https://shkd.script.woca.fun/icon.png" style="width: 30px">已为您找到 ${data.questionHasAnswer.length} 道题的参考答案`, {
                        time: 3000
                    });
                }


                    //没有答案的显示deepseek答题按钮
                $('form').each(function () {
                    const questionText = $(this).find('.e-q-q .ErichText').text().trim();
                    if (!$(this).find('.answer-display').length) {
                        //只有独立题目form中有这个结构e-q-r
                        if ($(this).find('.e-q-r').length > 0) {
                            $(this).find('.e-q-r').append(`
                                <div style="padding: 0 0 0 40px;">
                            <button type="button" class="deepseekQuestion layui-btn layui-btn-primary layui-border-blue layui-btn-sm">
                                <img src="https://www.deepseek.com/favicon.ico" style="width: 18px">deepseek回答
                                </button>
                                </div>
                            `);
                        } else {
                            //大题
                            // 除了听力题
                            if ($(this).closest('.e-q-body').data('questiontype') == 11) {
                                return;
                            }
                            if ($(this).closest('.e-q-body').find('.deepseekQuestion').length == 0) {
                                $(this).closest('.e-q-body').find('.e-q-r').first().append(`
                                    <div style="padding: 0 0 0 40px;">
                                    <button type="button" class="deepseekQuestion layui-btn layui-btn-primary layui-border-blue layui-btn-sm">
                                        <img src="https://www.deepseek.com/favicon.ico" style="width: 18px">deepseek回答
                                    </button>
                                    </div>
                                `);
                            }
                        }
                    }
                });

            }
        })
    }

    function getAnswers() {
        //获取页面所有题目
        const questions = [];
        const mainQuestions = [];

        //获取所有子题目
        $('form').each(function (key, item) {
            //排序题忽略
            if ($(item).find('.e-a-g.e-short-a').length > 0) {
                return;
            }
            const hiddenInputs = $(item).find('input[type="hidden"]');
            const formQuestion = {};
            formQuestion.action = $(item).attr('action');
            //获取题目标识
            hiddenInputs.each(function () {
                const name = $(this).attr('name');
                if (name !== 'answer') {
                    const value = $(this).val();
                    formQuestion[name] = value;
                }
            });
            if ($(item).find('.e-q-r').length == 0) {
                // 说明这个题目是大题内的子题目
                // 先确定这个大题题干是否已经获取了
                let mainQuestion = mainQuestions.find(item => item.studentWorkId == formQuestion['studentWorkId']);
                if (!mainQuestion) {
                    // 获取大题的题干
                    let questionBody = $(item).prevAll('.e-q-q').first();
                    if (questionBody.length > 0) { // 确保questionBody存在
                        let questionType = $(item).closest('.e-q-body').data('questiontype');
                        mainQuestion = {
                            question: questionBody.find('.ErichText').text().trim(),
                            question_html: questionBody.find('.ErichText').html().trim(),
                            studentWorkId: formQuestion['studentWorkId'],
                            questionType: questionType
                        };
                        mainQuestions.push(mainQuestion);
                    }
                }
            }
            //获取题目内容
            formQuestion.question = $(item).find('.e-q-q .ErichText').text().trim();
            formQuestion.question_html = $(item).find('.e-q-q .ErichText').html().trim();
            //题号
            formQuestion.question_num = $(item).find('.e-q-no').text().trim().split('、')[0];
            //获取选项
            formQuestion.options = [];
            if ($(item).find('.e-a-g ul li').length > 0) {
                $(item).find('.e-a-g ul li').each(function (key, items) {
                    let option = {};
                    if ($(items).find('.ErichText').length > 0) {
                        option.content = $(items).find('.ErichText').text().trim();
                        option.content_html = $(items).find('.ErichText').html().trim();
                    } else {
                        option.content = $(items).text().trim();
                    }
                    option.index = $(items).data('index');
                    if ($(items).attr('role')) {
                        option.role = $(items).attr('role');
                    }
                    if ($(items).data('subquestiontype')) {
                        option.subQuestionType = $(items).data('subquestiontype');
                    }
                    formQuestion.options.push(option)
                })
            } else {
                return;
            }
            //获取答案
            //查看是否显示了参考答案
            if($(item).find('.e-a-ans').length > 0){
                formQuestion.answer = $(item).find('.e-a-ans .e-ans-r').text().trim();
            }else{
                //查看是否回答正确
                //判断题目是否回答正确
                if ($(item).find('.e-q-right').length > 0) {
                    formQuestion.answer_index = $(item).find('.e-a.checked').data('index');

                    // 获取正确答案内容
                    if ($(item).find('.e-a.checked .ErichText').length > 0) {
                        formQuestion.answer = $(item).find('.e-a.checked .ErichText').text().trim();
                        formQuestion.answer_html = $(item).find('.e-a.checked .ErichText').html().trim();
                    } else {
                        formQuestion.answer = $(item).find('.e-a.checked').text().trim();
                        formQuestion.answer_html = $(item).find('.e-a.checked').html().trim();
                    }
                } else if ($(item).parent().data('questiontype') == 3) {
                    const correctAnswer = $(item).find('.e-a').not('.checked');
                    if (correctAnswer.length > 0) {
                        formQuestion.answer_index = correctAnswer.data('index');
                        if (correctAnswer.find('.ErichText').length > 0) {
                            formQuestion.answer = correctAnswer.find('.ErichText').text().trim();
                            formQuestion.answer_html = correctAnswer.find('.ErichText').html().trim();
                        } else {
                            formQuestion.answer = correctAnswer.text().trim();
                            formQuestion.answer_html = correctAnswer.html().trim();
                        }
                    }
                }
            }
            questions.push(formQuestion);
        })
        console.log({
            questions: questions,
            mainQuestions: mainQuestions
        })
        //把题目发送到后端
        $.ajax({
            url: apiDomain + 'api/saveAnswers',
            type: 'POST',
            data: {
                questions: JSON.stringify(questions),
                userData: JSON.parse(GM_getValue('userData')),
                link: link,
                mainQuestions: JSON.stringify(mainQuestions)
            },
            success: function (data) {
                console.log(data)
            }
        })
    }
})();