3-课程配置检查

【猫厂专用】自动检查课程配置是否符合规范,修复了讲义链接格式检查规则

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         3-课程配置检查
// @namespace    http://tampermonkey.net/
// @version      3.2.0
// @description  【猫厂专用】自动检查课程配置是否符合规范,修复了讲义链接格式检查规则
// @author       大生
// @match        https://tyca.codemao.cn/tanyue-course-warehouse/course/info?courseId=*
// @grant        none
// @icon         https://tyca.codemao.cn/favicon.ico
// @license      MPL-2.0
// ==/UserScript==

(function () {
    'use strict';

    // 检查脚本更新
    function checkForUpdates() {
        const currentVersion = GM_info.script.version || '3.0';
        const updateURL = 'https://raw.githubusercontent.com/bpjanson/Vibe_Coding/main/web_scripts/3-%E9%85%8D%E8%AF%BE%E6%A3%80%E6%9F%A5.js';

        fetch(updateURL)
            .then(response => response.text())
            .then(text => {
                // 从远程脚本中提取版本号
                const versionMatch = text.match(/@version\s+(\d+\.\d+)/);
                if (versionMatch && versionMatch[1]) {
                    const latestVersion = versionMatch[1];
                    if (compareVersions(latestVersion, currentVersion) > 0) {
                        showUpdateNotification(currentVersion, latestVersion, updateURL);
                    }
                }
            })
            .catch(error => {
                console.log('检查更新失败:', error);
            });
    }

    // 版本号比较函数
    function compareVersions(v1, v2) {
        const parts1 = v1.split('.').map(Number);
        const parts2 = v2.split('.').map(Number);
        const length = Math.max(parts1.length, parts2.length);

        for (let i = 0; i < length; i++) {
            const num1 = parts1[i] || 0;
            const num2 = parts2[i] || 0;

            if (num1 > num2) return 1;
            if (num1 < num2) return -1;
        }

        return 0;
    }

    // 显示更新通知
    function showUpdateNotification(currentVersion, latestVersion, updateURL) {
        // 创建更新通知容器
        const notification = document.createElement('div');
        notification.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            width: 300px;
            background: #fff;
            border: 1px solid #ddd;
            border-radius: 8px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
            z-index: 1000000;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            font-size: 14px;
        `;

        // 创建通知内容
        notification.innerHTML = `
            <div style="padding: 16px;">
                <div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 12px;">
                    <h3 style="margin: 0; font-size: 16px; color: #333;">脚本有更新</h3>
                    <button id="closeNotification" style="background: none; border: none; font-size: 20px; cursor: pointer; padding: 0; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center;">×</button>
                </div>
                <div style="margin-bottom: 16px; line-height: 1.5;">
                    <p style="margin: 0 0 8px 0;">当前版本: <strong>v${currentVersion}</strong></p>
                    <p style="margin: 0 0 12px 0;">最新版本: <strong style="color: #28a745;">v${latestVersion}</strong></p>
                    <p style="margin: 0; color: #666;">有新功能和修复可用,建议及时更新。</p>
                </div>
                <div style="display: flex; gap: 8px;">
                    <a href="${updateURL}" target="_blank" style="flex: 1; text-align: center; padding: 8px 12px; background: #007bff; color: white; text-decoration: none; border-radius: 4px; font-size: 13px; transition: background 0.2s;">查看更新</a>
                    <button id="updateLater" style="flex: 1; padding: 8px 12px; background: #f8f9fa; color: #333; border: 1px solid #ddd; border-radius: 4px; cursor: pointer; font-size: 13px; transition: background 0.2s;">稍后提醒</button>
                </div>
            </div>
        `;

        // 添加到页面
        document.body.appendChild(notification);

        // 绑定关闭事件
        notification.querySelector('#closeNotification').addEventListener('click', () => {
            document.body.removeChild(notification);
        });

        // 绑定稍后提醒事件
        notification.querySelector('#updateLater').addEventListener('click', () => {
            document.body.removeChild(notification);
        });
    }

    // 检查编程步骤的配置情况
    const programmingSteps = {
        type: 13,
        requiredFields: [
            { field: 'tipsV2List', message: '提示卡', check: true },
            { field: 'taskV2', message: '任务卡', check: true },
            { field: 'pythonRule', message: '正则检测', check: true },
            { field: 'fastInput', message: '快捷输入', check: true },
            { field: 'isGuideWork', message: '提交作品', check: false }
        ],
        // 是否必须存在编程步骤
        mustExist: true,
        mustExistMessage: "上课环节必须配置编程步骤"
    };
    const questionStrps = {
        type: 22,
        requiredFields: [
            { field: 'questionId', message: '题目ID', check: false },
            { field: 'questionName', message: '题目名称', check: false },
            { field: 'knowledgeArr', message: '知识点标签', check: false },
        ],
        // 是否必须标记知识点
        mustknowledgeArr: 3,
        mustknowledgeArrMessage: "至少配置3个带知识点标签的题目"
    };

    // 单数课配置规则
    const singleCourseRules = {
        "课前直播": {
            fields: [
                { key: 'sort', expected: 1, message: "环节顺序应为 1" },
                { key: 'beforeUnlockTime', expected: 1200, message: "开播规则应为:开课前 20 分钟" },
                { key: 'remindTimeBeforeUnlock', expected: 86400, message: "通知规则应为:开课前 1 天" }
            ]
        },
        "上课": {
            fields: [
                { key: 'sort', expected: 2, message: "环节顺序应为 2" },
                { key: 'unlockCondition', expected: "AFTER_START_COURSE", message: "解锁规则应为:开课后解锁" },
                { key: 'showComment', expected: 0, message: "移动端不展示评语" },
                { key: 'pcShowComment', expected: 0, message: "PC端不展示评语" },
                { key: 'complete', expected: 1, message: "该环节应为:完课环节" },
                { key: 'direction', expected: 0, message: "该环节应为:横屏显示" }
            ],
            checkProgrammingSteps: programmingSteps,
            checkquestionStrps: questionStrps,
            // 是否检查打点步骤
            checkKeyPointSteps: true,
            // 是否要求不提交作品
            checkSubmitWorks: {
                type: 13,
                allZero: true,
                message: "单数课不需要提交作品"
            },
            // 检查步骤是否为空
            stepsNotEmpty: true
        }
    };

    // 双数课配置规则
    const doubleCourseRules = {
        "上课": {
            fields: [
                { key: 'sort', expected: 1, message: "环节顺序应为 1" },
                { key: 'unlockCondition', expected: "AFTER_START_COURSE", message: "解锁规则应为:开课后解锁" },
                { key: 'showComment', expected: 1, message: "移动端需展示评语" },
                { key: 'pcShowComment', expected: 1, message: "PC端需展示评语" },
                { key: 'complete', expected: 1, message: "该环节应为:完课环节" },
                { key: 'direction', expected: 0, message: "该环节应为:横屏显示" }
            ],
            checkProgrammingSteps: programmingSteps,
            checkquestionStrps: questionStrps,
            // 是否检查打点步骤
            checkKeyPointSteps: true,
            // 是否要求提交作品
            checkSubmitWorks: {
                type: 13,
                anyOne: true,
                message: "双数课需要提交作品"
            },
            // 检查步骤是否为空
            stepsNotEmpty: true
        },
        "课后练习": {
            fields: [
                { key: 'sort', expected: 2, message: "环节顺序应为 2" },
                { key: 'unlockCondition', expected: "AFTER_START_COURSE", message: "解锁规则应为:开课后解锁" },
                { key: 'showComment', expected: 0, message: "移动端不展示评语" },
                { key: 'pcShowComment', expected: 0, message: "PC端不展示评语" },
                { key: 'complete', expected: 0, message: "该环节应为:非完课环节" },
                { key: 'direction', expected: 1, message: "该环节应为:竖屏显示" }
            ],
            checkWeeklyList: {
                requiredFields: [
                    { field: 'questionId', message: '题目ID', check: false },
                    { field: 'name', message: '题目名称', check: false },
                    { field: 'knowledgeArr', message: '知识点标签', check: false }
                ],
                // 是否必须标记知识点
                mustknowledgeArr: -1,
                mustknowledgeArrMessage: "全部周测题目都需要带知识点标签"
            },
            // 检查周测连接配置
            checkWeeklyTest: true
        },
        "笔记打卡": {
            fields: [
                { key: 'sort', expected: 3, message: "环节顺序应为 3" },
                { key: 'unlockCondition', expected: "AFTER_COMPLETE_COURSE", message: "解锁规则应为:完课后解锁" },
                { key: 'complete', expected: 0, message: "该环节应为:非完课环节" }
            ]
        },
        "电子讲义": {
            fields: [
                { key: 'sort', expected: 4, message: "环节顺序应为 4" },
                { key: 'unlockCondition', expected: "AFTER_COMPLETE_COURSE", message: "解锁规则应为:完课后解锁" },
                { key: 'complete', expected: 0, message: "该环节应为:非完课环节" },
                { key: 'direction', expected: 1, message: "该环节应为:竖屏显示" }
            ],
            // 检讲义测连接配置
            checkUrl: true
        },
        "学习报告": {
            fields: [
                { key: 'sort', expected: 5, message: "环节顺序应为 5" },
                { key: 'unlockCondition', expected: "AFTER_COMPLETE_COURSE", message: "解锁规则应为:完课后解锁" },
                { key: 'complete', expected: 0, message: "该环节应为:非完课环节" }
            ]
        },

    };

    // 全局变量
    let courseId = null;
    let courseData = null;
    let stepsData = {};

    // 通用样式
    const STYLES = {
        container: `
            position: fixed !important;
            right: 20px !important;
            top: 40vh !important;
            transform: translateY(-50%) !important;
            z-index: 999999 !important;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
        `,
        button: `
            width: 50px !important;
            height: 50px !important;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
            border: none !important;
            border-radius: 50% !important;
            display: flex !important;
            align-items: center !important;
            justify-content: center !important;
            cursor: pointer !important;
            box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3) !important;
            transition: all 0.2s ease !important;
            font-size: 15px !important;
            font-weight: bold !important;
            color: white !important;
            transform: scale(1) !important;
        `,
        menu: `
            position: absolute !important;
            right: 50px !important;
            top: 50% !important;
            transform: translateY(-50%) !important;
            background: transparent !important;
            border-radius: 6px !important;
            padding: 8px !important;
            display: none !important;
            min-width: 120px !important;
            z-index: 1000000 !important;
        `,
        menuButton: `
            width: 100% !important;
            padding: 10px 16px !important;
            border: none !important;
            background: linear-gradient(135deg, #6A72D9 0%, #8B95E5 100%) !important;
            border-radius: 6px !important;
            cursor: pointer !important;
            transition: all 0.2s !important;
            font-size: 13px !important;
            font-weight: 500 !important;
            text-align: center !important;
            min-height: 32px !important;
            color: white !important;
            box-shadow: 0 2px 6px rgba(106, 114, 217, 0.3) !important;
        `
    };

    // 工具函数
    const utils = {
        getCourseId() {
            const urlParams = new URLSearchParams(window.location.search);
            return urlParams.get('courseId');
        },

        createElement(tag, styles, content = '') {
            const element = document.createElement(tag);
            if (styles) element.style.cssText = styles;
            if (content) element.innerHTML = content;
            return element;
        },

        addHoverEffect(element, normalBg, hoverBg) {
            element.addEventListener('mouseenter', () => {
                element.style.background = hoverBg;
            });
            element.addEventListener('mouseleave', () => {
                element.style.background = normalBg;
            });
        }
    };

    // 通用API调用函数
    async function fetchAPI(url, errorMessage) {
        try {
            const response = await fetch(url, {
                method: 'GET',
                credentials: 'include',
                headers: {
                    'Accept': 'application/json, text/plain, */*',
                    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8'
                }
            });

            if (response.ok) {
                const data = await response.json();
                if (data.success && data.data) {
                    return data.data;
                }
            }
            return null;
        } catch (error) {
            console.error(errorMessage, error);
            return null;
        }
    }

    // API调用函数
    const fetchCourseLinks = (courseId) =>
        fetchAPI(`https://codecamp-teaching-system.codemao.cn/ty-courses/${courseId}/link`, '获取课程数据失败:');

    const fetchCourseSteps = (courseId, linkId) =>
        fetchAPI(`https://codecamp-teaching-system.codemao.cn/ty-courses/${courseId}/link/${linkId}/step`, '获取课程步骤失败:');

    // 新增:获取周测题目详情的API调用函数
    const fetchWeeklyTestQuestions = (paperId) =>
        fetchAPI(`https://codecamp-teaching-system.codemao.cn/paper/${paperId}`, '获取周测题目失败:');

    // 从周测URL中提取paperId
    function extractPaperIdFromUrl(url) {
        if (!url) return null;
        const match = url.match(/paperId=(\d+)/);
        return match ? match[1] : null;
    }

    // 创建周测题目表格
    function createWeeklyQuestionsTable(questions) {
        const table = utils.createElement('div', `
            border: 1px solid #e1e5e9 !important;
            border-radius: 6px !important;
            overflow: hidden !important;
            font-size: 12px !important;
            margin-top: 8px !important;
        `);

        // 表头
        const headerColumns = ['题目ID', '题目名称', '知识点标签'];
        const header = utils.createElement('div', `
            display: grid !important;
            grid-template-columns: 1fr 2fr 2fr !important;
            background: #f8f9fa !important;
            font-weight: 600 !important;
            border-bottom: 1px solid #e1e5e9 !important;
        `);

        headerColumns.forEach(headerText => {
            const cell = utils.createElement('div', 'padding: 8px 6px !important; border-right: 1px solid #e1e5e9 !important;', headerText);
            header.appendChild(cell);
        });

        table.appendChild(header);

        // 数据行
        questions.forEach((question, index) => {
            const row = utils.createElement('div', `
                display: grid !important;
                grid-template-columns: 1fr 2fr 2fr !important;
                ${index % 2 === 0 ? 'background: #fafafa !important;' : 'background: white !important;'}
                border-bottom: 1px solid #f0f0f0 !important;
            `);

            // 题目ID(带链接)
            const idCell = utils.createElement('div', 'padding: 8px 6px !important; border-right: 1px solid #e1e5e9 !important;');
            if (question.questionId) {
                const link = utils.createElement('a', `
                    color: #007bff !important;
                    text-decoration: none !important;
                    transition: all 0.2s !important;
                `, question.questionId);

                link.href = `https://tyca.codemao.cn/weekly-test/topic/detail?questionId=${question.questionId}&type=1`;
                link.target = '_blank';
                link.rel = 'noopener noreferrer';

                // 添加悬停效果
                link.addEventListener('mouseenter', () => {
                    link.style.textDecoration = 'underline';
                });
                link.addEventListener('mouseleave', () => {
                    link.style.textDecoration = 'none';
                });

                idCell.appendChild(link);
            } else {
                idCell.textContent = '-';
            }
            row.appendChild(idCell);

            // 题目名称
            const nameCell = utils.createElement('div', `
                padding: 8px 6px !important;
                border-right: 1px solid #e1e5e9 !important;
                word-break: break-all !important;
            `, question.name || '-');
            row.appendChild(nameCell);

            // 知识点标签
            const knowledgeCell = utils.createElement('div', `
                padding: 8px 6px !important;
                border-right: 1px solid #e1e5e9 !important;
                word-break: break-all !important;
                ${(!question.knowledgeArr || question.knowledgeArr.length === 0) ? 'color: #dc3545 !important;' : 'color: #28a745 !important;'}
            `);

            if (question.knowledgeArr && question.knowledgeArr.length > 0) {
                knowledgeCell.textContent = question.knowledgeArr.join(', ');
            } else {
                knowledgeCell.textContent = '缺少知识点标签';
            }
            row.appendChild(knowledgeCell);

            table.appendChild(row);
        });

        return table;
    }

    // 创建悬浮按钮
    function createFloatingButton() {
        if (document.getElementById('course-check-container')) {
            return;
        }

        const container = utils.createElement('div', STYLES.container);
        container.id = 'course-check-container';

        const button = utils.createElement('div', STYLES.button, '检查');
        button.id = 'course-check-btn';

        const menu = utils.createElement('div', STYLES.menu);
        menu.id = 'course-check-menu';

        const singleBtn = utils.createElement('button', STYLES.menuButton + 'margin-bottom: 8px !important;', '单数课');
        const doubleBtn = utils.createElement('button', STYLES.menuButton, '双数课');

        // 添加悬停效果
        utils.addHoverEffect(singleBtn, 'linear-gradient(135deg, #6A72D9 0%, #8B95E5 100%)', 'linear-gradient(135deg, #66CDAA 0%, #87E8DE 100%)');
        utils.addHoverEffect(doubleBtn, 'linear-gradient(135deg, #6A72D9 0%, #8B95E5 100%)', 'linear-gradient(135deg, #66CDAA 0%, #87E8DE 100%)');

        // 菜单显示/隐藏逻辑
        let hideTimeout;
        const showMenu = () => {
            clearTimeout(hideTimeout);
            menu.style.display = 'block';
        };
        const hideMenu = () => {
            hideTimeout = setTimeout(() => {
                menu.style.display = 'none';
            }, 50);
        };

        // 事件监听
        button.addEventListener('mouseenter', () => {
            showMenu();
            button.style.background = 'linear-gradient(135deg, #764ba2 0%, #9575cd 100%)';
            button.style.transform = 'scale(1.1)';
            button.style.boxShadow = '0 6px 16px rgba(102, 126, 234, 0.4)';
        });

        button.addEventListener('mouseleave', () => {
            hideMenu();
            button.style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
            button.style.transform = 'scale(1)';
            button.style.boxShadow = '0 4px 12px rgba(102, 126, 234, 0.3)';
        });

        menu.addEventListener('mouseenter', showMenu);
        menu.addEventListener('mouseleave', hideMenu);

        const handleCheck = (rules, courseType) => {
            menu.style.display = 'none';
            courseData = null;
            stepsData = {};
            performCheck(rules, courseType);
        };

        singleBtn.addEventListener('click', () => handleCheck(singleCourseRules, '单数课'));
        doubleBtn.addEventListener('click', () => handleCheck(doubleCourseRules, '双数课'));

        menu.appendChild(singleBtn);
        menu.appendChild(doubleBtn);
        container.appendChild(button);
        container.appendChild(menu);

        if (document.body) {
            document.body.appendChild(container);
        }
    }
    // 执行检查
    async function performCheck(rules, courseType) {
        if (!courseData) {
            courseData = await fetchCourseLinks(courseId);
            if (!courseData) {
                alert('无法获取课程数据,请检查网络连接或重新登录后重试');
                return;
            }
        }

        const results = {};
        let overallPass = true;

        for (const [sectionName, rule] of Object.entries(rules)) {
            const section = courseData.find(item => item.name === sectionName);
            if (!section) {
                results[sectionName] = {
                    found: false,
                    message: `未找到${sectionName}环节`,
                    sectionPass: false
                };
                overallPass = false;
                continue;
            }

            const sectionResult = {
                found: true,
                fieldChecks: [],
                sectionPass: true
            };

            // 检查基础字段
            rule.fields.forEach(field => {
                const actual = section[field.key];
                const expected = field.expected;
                const isMatch = actual === expected;

                sectionResult.fieldChecks.push({
                    key: field.key,
                    message: field.message,
                    expected: expected,
                    actual: actual,
                    isMatch: isMatch
                });

                if (!isMatch) {
                    sectionResult.sectionPass = false;
                    overallPass = false;
                }
            });

            // 获取步骤数据(如果需要)
            if (rule.checkProgrammingSteps || rule.checkquestionStrps || rule.checkKeyPointSteps || rule.checkSubmitWorks || rule.checkWeeklyTest || rule.stepsNotEmpty) {
                if (!stepsData[section.id]) {
                    stepsData[section.id] = await fetchCourseSteps(courseId, section.id);
                }

                const steps = stepsData[section.id];

                if (steps) {
                    // 新增:检查步骤是否为空
                    if (rule.stepsNotEmpty) {
                        const isValid = steps.length > 0;
                        sectionResult.stepsNotEmptyCheck = {
                            isValid: isValid,
                            message: isValid ? '环节已包含步骤' : '环节步骤不能为空'
                        };
                        if (!isValid) {
                            sectionResult.sectionPass = false;
                            overallPass = false;
                        }
                    }

                    // 检查编程步骤
                    if (rule.checkProgrammingSteps) {
                        sectionResult.programmingSteps = checkProgrammingSteps(steps, rule.checkProgrammingSteps);
                        if (!sectionResult.programmingSteps.hasSteps || !sectionResult.programmingSteps.allStepsPass) {
                            sectionResult.sectionPass = false;
                            overallPass = false;
                        }
                    }

                    // 检查题目步骤
                    if (rule.checkquestionStrps) {
                        sectionResult.questionSteps = checkQuestionSteps(steps, rule.checkquestionStrps);
                        if (!sectionResult.questionSteps.isValid) {
                            sectionResult.sectionPass = false;
                            overallPass = false;
                        }
                    }

                    // 检查打点步骤
                    if (rule.checkKeyPointSteps) {
                        sectionResult.keyPointSteps = checkKeyPointSteps(steps);
                        if (!sectionResult.keyPointSteps.hasKeyPoints) {
                            sectionResult.sectionPass = false;
                            overallPass = false;
                        }
                    }

                    // 检查提交作品
                    if (rule.checkSubmitWorks) {
                        sectionResult.submitWorks = checkSubmitWorks(steps, rule.checkSubmitWorks);
                        if (!sectionResult.submitWorks.isValid) {
                            sectionResult.sectionPass = false;
                            overallPass = false;
                        }
                    }

                    // 检查周测
                    if (rule.checkWeeklyTest) {
                        sectionResult.weeklyTest = await checkWeeklyTest(steps, rule.checkWeeklyList);
                        if (!sectionResult.weeklyTest.isValid) {
                            sectionResult.sectionPass = false;
                            overallPass = false;
                        }
                    }
                } else {
                    sectionResult.stepDataError = `无法获取${sectionName}的步骤数据,相关检查已跳过`;
                    sectionResult.sectionPass = false;
                    overallPass = false;
                }
            }

            // 检查URL
            if (rule.checkUrl) {
                sectionResult.urlCheck = checkUrl(section);
                if (!sectionResult.urlCheck.isValid) {
                    sectionResult.sectionPass = false;
                    overallPass = false;
                }
            }

            results[sectionName] = sectionResult;
        }

        showResults(results, overallPass, courseType);
    }

    // 检查编程步骤
    function checkProgrammingSteps(steps, config) {
        const programmingSteps = steps.filter(step => step.type === config.type);

        // 检查是否必须存在编程步骤
        if (config.mustExist && programmingSteps.length === 0) {
            return {
                hasSteps: false,
                message: config.mustExistMessage,
                steps: [],
                allStepsPass: false
            };
        }

        let allStepsPass = true;

        const results = programmingSteps.map(step => {
            const stepResult = {
                name: step.name,
                sort: (step.sort || 0) + 1,
                checks: [],
                stepPass: true
            };

            config.requiredFields.forEach(fieldConfig => {
                let isConfigured = false;
                let value = step.turDetail?.[fieldConfig.field];

                if (fieldConfig.field === 'isGuideWork') {
                    isConfigured = value === 1;
                } else {
                    isConfigured = value !== undefined && value !== null &&
                        (Array.isArray(value) ? value.length > 0 : value !== '');
                }

                stepResult.checks.push({
                    field: fieldConfig.field,
                    message: fieldConfig.message,
                    isConfigured: isConfigured,
                    value: value,
                    check: fieldConfig.check
                });

                // 如果该字段需要检查且未配置,则该步骤不通过
                if (fieldConfig.check && !isConfigured) {
                    stepResult.stepPass = false;
                }
            });

            // 如果任何一个步骤不通过,整体就不通过
            if (!stepResult.stepPass) {
                allStepsPass = false;
            }

            return stepResult;
        });

        return {
            hasSteps: true,
            steps: results,
            allStepsPass: allStepsPass
        };
    }

    // 检查打点步骤
    function checkKeyPointSteps(steps) {
        const keyPointSteps = steps.filter(step => step.isKeyPoint === 1);
        return {
            hasKeyPoints: keyPointSteps.length > 0,
            keyPointSteps: keyPointSteps.map(step => ({
                name: step.name,
                sort: (step.sort || 0) + 1
            }))
        };
    }

    // 检查提交作品
    function checkSubmitWorks(steps, config) {
        const programmingSteps = steps.filter(step => step.type === config.type);
        const submitSteps = programmingSteps.filter(step => step.turDetail?.isGuideWork === 1);

        if (config.allZero) {
            return {
                isValid: submitSteps.length === 0,
                message: config.message,
                count: submitSteps.length
            };
        } else if (config.anyOne) {
            return {
                isValid: submitSteps.length > 0,
                message: config.message,
                count: submitSteps.length
            };
        }

        return { isValid: true, message: config.message, count: submitSteps.length };
    }

    // 检查周测
    async function checkWeeklyTest(steps, config = null) {
        const weeklyTestSteps = steps.filter(step => step.type === 7);
        const hasWeeklyTest = weeklyTestSteps.length >= 1;

        let weeklyTestUrl = null;
        let weeklyQuestions = null;
        let questionsValid = true;
        let questionsMessage = "";

        if (hasWeeklyTest) {
            const weeklyStep = weeklyTestSteps[0];
            weeklyTestUrl = weeklyStep.h5Detail?.url || weeklyStep.url || null;

            // 如果需要检查周测题目详情
            if (config && weeklyTestUrl) {
                const paperId = extractPaperIdFromUrl(weeklyTestUrl);
                if (paperId) {
                    try {
                        const paperData = await fetchWeeklyTestQuestions(paperId);
                        if (paperData && paperData.questions) {
                            weeklyQuestions = paperData.questions.map(q => ({
                                questionId: q.questionId,
                                name: q.name,
                                knowledgeArr: q.knowledgeArr || []
                            }));

                            // 检查知识点标签要求
                            if (config.mustknowledgeArr === -1) {
                                // 所有题目都需要有知识点标签
                                const questionsWithoutKnowledge = weeklyQuestions.filter(q =>
                                    !q.knowledgeArr || q.knowledgeArr.length === 0
                                );

                                if (questionsWithoutKnowledge.length > 0) {
                                    questionsValid = false;
                                    questionsMessage = `有${questionsWithoutKnowledge.length}个题目缺少知识点标签`;
                                } else {
                                    questionsMessage = `所有${weeklyQuestions.length}个题目都已配置知识点标签`;
                                }
                            }
                        } else {
                            questionsValid = false;
                            questionsMessage = "无法获取周测题目数据";
                        }
                    } catch (error) {
                        console.error('获取周测题目失败:', error);
                        questionsValid = false;
                        questionsMessage = "获取周测题目数据失败";
                    }
                } else {
                    questionsValid = false;
                    questionsMessage = "无法从URL中提取paperId";
                }
            }
        }

        const basicValid = hasWeeklyTest && weeklyTestUrl !== null;
        const overallValid = basicValid && (config ? questionsValid : true);

        return {
            isValid: overallValid,
            message: hasWeeklyTest && weeklyTestUrl ? "已配置周测" : "未配置周测",
            url: weeklyTestUrl,
            questions: weeklyQuestions,
            questionsValid: questionsValid,
            questionsMessage: questionsMessage
        };
    }

    // 检查题目步骤
    function checkQuestionSteps(steps, config) {
        const questionSteps = steps.filter(step => step.type === config.type);

        // 统计有知识点标签的题目数量
        let knowledgeArrCount = 0;

        const results = questionSteps.map(step => {
            const stepResult = {
                name: step.name,
                sort: (step.sort || 0) + 1,
                checks: [],
                stepPass: true
            };

            config.requiredFields.forEach(fieldConfig => {
                let value = null;
                let isConfigured = false;

                // 获取题目列表
                const questionList = step.courseQuestionDetail?.questionList || [];

                if (fieldConfig.field === 'questionId') {
                    // 收集所有题目ID
                    value = questionList.map(q => q.questionId).filter(id => id);
                    isConfigured = value.length > 0;
                } else if (fieldConfig.field === 'questionName') {
                    // 收集所有题目名称
                    value = questionList.map(q => q.questionName).filter(name => name && name.trim() !== '');
                    isConfigured = value.length > 0;
                } else if (fieldConfig.field === 'knowledgeArr') {
                    // 收集所有知识点标签
                    const allKnowledgeArr = [];
                    questionList.forEach(q => {
                        if (Array.isArray(q.knowledgeArr) && q.knowledgeArr.length > 0) {
                            allKnowledgeArr.push(...q.knowledgeArr);
                        }
                    });
                    value = [...new Set(allKnowledgeArr)]; // 去重
                    isConfigured = value.length > 0;
                    if (isConfigured) {
                        knowledgeArrCount++;
                    }
                }

                stepResult.checks.push({
                    field: fieldConfig.field,
                    message: fieldConfig.message,
                    isConfigured: isConfigured,
                    value: value,
                    check: fieldConfig.check
                });
            });

            return stepResult;
        });

        // 检查知识点标签数量是否满足要求
        const isValid = knowledgeArrCount >= config.mustknowledgeArr;

        return {
            hasSteps: questionSteps.length > 0,
            steps: results,
            knowledgeArrCount: knowledgeArrCount,
            requiredKnowledgeArr: config.mustknowledgeArr,
            isValid: isValid,
            message: isValid ?
                `已配置${knowledgeArrCount}个带知识点标签的题目` :
                `仅配置${knowledgeArrCount}个带知识点标签的题目,需要至少${config.mustknowledgeArr}个`
        };
    }

    // 检查URL - 验证是否为有效的URL格式
function checkUrl(link) {
    const url = link.url && link.url.trim();
    let isValid = false;
    let message = "未配置讲义";

    if (url) {
        try {
            // 尝试创建URL对象来验证基本格式
            const urlObj = new URL(url);

            // 检查协议是否为http或https
            if (!['http:', 'https:'].includes(urlObj.protocol)) {
                throw new Error('协议必须是http或https');
            }

            // 检查域名有效性:必须包含至少一个点,且不能是纯中文或特殊字符组合
            const hostname = urlObj.hostname;
            if (!hostname.includes('.') || hostname === 'localhost' ||
                /^[\u4e00-\u9fa5]+$/.test(hostname.replace(/[^\u4e00-\u9fa5]/g, '')) && hostname.length <= 10) {
                throw new Error('无效的域名格式');
            }

            isValid = true;
            message = "已配置有效讲义链接";
        } catch (e) {
            // 如果URL格式无效,捕获异常
            isValid = false;
            message = "讲义链接格式无效";
        }
    }

    return {
        isValid: isValid,
        message: message,
        url: url
    };
}

    // 显示检查结果
    function showResults(results, overallPass, courseType) {
        const existingPanel = document.getElementById('course-check-panel');
        if (existingPanel) {
            existingPanel.remove();
        }

        const panel = utils.createElement('div', `
            position: fixed !important;
            right: 20px !important;
            top: 20px !important;
            width: 400px !important;
            max-height: 80vh !important;
            background: white !important;
            border-radius: 12px !important;
            box-shadow: 0 12px 40px rgba(0,0,0,0.2) !important;
            z-index: 999998 !important;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
            overflow: hidden !important;
            border: 1px solid #e1e5e9 !important;
        `);
        panel.id = 'course-check-panel';

        // 头部
        const header = utils.createElement('div', `
            padding: 16px 20px !important;
            background: ${overallPass ? 'linear-gradient(135deg, #4CAF50, #45a049)' : 'linear-gradient(135deg, #f44336, #d32f2f)'} !important;
            color: white !important;
            display: flex !important;
            justify-content: space-between !important;
            align-items: center !important;
        `);

        const title = utils.createElement('h3', 'margin: 0 !important; font-size: 20px !important; font-weight: 600 !important; color: white !important;', `${courseType}检查结果`);
        const status = utils.createElement('span', 'font-size: 20px !important; font-weight: 500 !important;', overallPass ? '✓ 通过' : '✗ 不通过');
        const closeBtn = utils.createElement('button', `
            background: none !important;
            border: none !important;
            color: white !important;
            font-size: 20px !important;
            cursor: pointer !important;
            padding: 0 !important;
            width: 24px !important;
            height: 24px !important;
            display: flex !important;
            align-items: center !important;
            justify-content: center !important;
        `, '×');

        closeBtn.addEventListener('click', () => panel.remove());

        header.appendChild(title);
        header.appendChild(status);
        header.appendChild(closeBtn);

        // 内容区域
        const content = utils.createElement('div', `
            max-height: calc(80vh - 68px) !important;
            overflow-y: auto !important;
            padding: 16px !important;
        `);

        // 生成检查结果
        Object.entries(results).forEach(([sectionName, result]) => {
            const sectionCard = createSectionCard(sectionName, result);
            content.appendChild(sectionCard);
        });

        panel.appendChild(header);
        panel.appendChild(content);
        document.body.appendChild(panel);
    }

    // 创建环节卡片
    function createSectionCard(sectionName, result) {
        const card = utils.createElement('div', `
            border: 1px solid #e1e5e9 !important;
            border-radius: 8px !important;
            margin-bottom: 12px !important;
            overflow: hidden !important;
            background: white !important;
        `);

        const cardHeader = utils.createElement('div', `
            padding: 12px 16px !important;
            cursor: pointer !important;
            display: flex !important;
            justify-content: space-between !important;
            align-items: center !important;
            background: ${result.sectionPass ? '#f8fff8' : '#fff5f5'} !important;
            border-left: 4px solid ${result.sectionPass ? '#28a745' : '#dc3545'} !important;
        `);

        const cardTitle = utils.createElement('div', 'display: flex !important; align-items: center !important; gap: 8px !important;');
        const statusIcon = utils.createElement('span', `
            color: ${result.sectionPass ? '#28a745' : '#dc3545'} !important;
            font-weight: bold !important;
            font-size: 16px !important;
        `, result.sectionPass ? '✓' : '✗');
        const titleText = utils.createElement('span', 'font-weight: 600 !important; font-size: 14px !important;', sectionName);
        const expandIcon = utils.createElement('span', `
            transition: transform 0.2s !important;
            font-size: 12px !important;
            color: #666 !important;
        `, '▼');

        cardTitle.appendChild(statusIcon);
        cardTitle.appendChild(titleText);
        cardHeader.appendChild(cardTitle);
        cardHeader.appendChild(expandIcon);

        const cardBody = utils.createElement('div', `
            padding: 0 16px !important;
            max-height: 0 !important;
            overflow: hidden !important;
            transition: all 0.3s ease !important;
            background: #fafafa !important;
        `);

        // 如果有失败项,默认展开
        if (!result.sectionPass) {
            cardBody.style.maxHeight = '1000px';
            cardBody.style.paddingTop = '12px';
            cardBody.style.paddingBottom = '12px';
            expandIcon.style.transform = 'rotate(180deg)';
        }

        // 点击展开/折叠
        cardHeader.addEventListener('click', () => {
            const isExpanded = cardBody.style.maxHeight !== '0px';
            if (isExpanded) {
                cardBody.style.maxHeight = '0px';
                cardBody.style.paddingTop = '0';
                cardBody.style.paddingBottom = '0';
                expandIcon.style.transform = 'rotate(0deg)';
            } else {
                cardBody.style.maxHeight = '1000px';
                cardBody.style.paddingTop = '12px';
                cardBody.style.paddingBottom = '12px';
                expandIcon.style.transform = 'rotate(180deg)';
            }
        });

        // 添加检查项内容
        if (!result.found) {
            const notFoundMsg = utils.createElement('div', 'color: #dc3545 !important; font-size: 14px !important; padding: 8px 0 !important;', result.message);
            cardBody.appendChild(notFoundMsg);
        } else {
            // 基础字段检查
            if (result.fieldChecks && result.fieldChecks.length > 0) {
                const fieldsSection = createCheckSection('基础信息', result.fieldChecks.map(check => ({
                    label: check.message,
                    status: check.isMatch,
                    detail: `正确值: ${check.expected}, 当前值: ${check.actual}`
                })));
                cardBody.appendChild(fieldsSection);
            }

            // 新增:步骤数量检查
            if (result.stepsNotEmptyCheck) {
                const stepsNotEmptySection = createSimpleSection('步骤数量',
                    result.stepsNotEmptyCheck.message,
                    result.stepsNotEmptyCheck.isValid
                );
                cardBody.appendChild(stepsNotEmptySection);
            }

            // 打点步骤检查
            if (result.keyPointSteps) {
                const keyPointSection = createSimpleSection('步骤打点',
                    result.keyPointSteps.hasKeyPoints ? '存在打点步骤' : '没有打点步骤',
                    result.keyPointSteps.hasKeyPoints
                );

                if (result.keyPointSteps.hasKeyPoints && result.keyPointSteps.keyPointSteps.length > 0) {
                    const stepsList = utils.createElement('div', 'margin-left: 20px !important; font-size: 12px !important; color: #666 !important;');
                    result.keyPointSteps.keyPointSteps.forEach(step => {
                        const stepItem = utils.createElement('div', 'margin: 2px 0 !important;', `${step.sort}⭐${step.name}`);
                        stepsList.appendChild(stepItem);
                    });
                    keyPointSection.appendChild(stepsList);
                }

                cardBody.appendChild(keyPointSection);
            }

            // 题目步骤检查
            if (result.questionSteps) {
                const questionSection = createSimpleSection('课中题目',
                    result.questionSteps.message,
                    result.questionSteps.isValid
                );

                if (result.questionSteps.hasSteps && result.questionSteps.steps.length > 0) {
                    const questionTable = createQuestionStepsSection(result.questionSteps.steps);
                    questionSection.appendChild(questionTable);
                }

                cardBody.appendChild(questionSection);
            }

            if (result.programmingSteps) {
                if (result.programmingSteps.hasSteps) {
                    const programmingSection = createProgrammingStepsSection(result.programmingSteps.steps);
                    cardBody.appendChild(programmingSection);
                } else {
                    const programmingSection = createSimpleSection('编程步骤',
                        result.programmingSteps.message,
                        false
                    );
                    cardBody.appendChild(programmingSection);
                }
            }

            if (result.submitWorks) {
                const submitSection = createSimpleSection('作品提交',
                    `${result.submitWorks.message} (${result.submitWorks.count}个)`,
                    result.submitWorks.isValid
                );
                cardBody.appendChild(submitSection);
            }

            if (result.weeklyTest) {
                const weeklySection = createSimpleSection('周测连接',
                    result.weeklyTest.message,
                    result.weeklyTest.isValid,
                    result.weeklyTest.url
                );

                // 如果有题目详情检查结果,添加题目信息显示
                if (result.weeklyTest.questions) {
                    const questionsStatus = utils.createElement('div', 'margin-top: 8px !important; margin-left: 20px !important;');
                    const statusIcon = utils.createElement('span', `color: ${result.weeklyTest.questionsValid ? '#28a745' : '#dc3545'} !important;`, result.weeklyTest.questionsValid ? '✓' : '✗');
                    const statusText = utils.createElement('span', 'font-size: 13px !important; margin-left: 8px !important;', result.weeklyTest.questionsMessage);

                    questionsStatus.appendChild(statusIcon);
                    questionsStatus.appendChild(statusText);
                    weeklySection.appendChild(questionsStatus);

                    // 添加题目详情表格
                    if (result.weeklyTest.questions.length > 0) {
                        const questionsTable = createWeeklyQuestionsTable(result.weeklyTest.questions);
                        weeklySection.appendChild(questionsTable);
                    }
                }

                cardBody.appendChild(weeklySection);
            }

            if (result.urlCheck) {
                const urlSection = createSimpleSection('讲义链接',
                    result.urlCheck.message,
                    result.urlCheck.isValid,
                    result.urlCheck.url
                );
                cardBody.appendChild(urlSection);
            }
        }

        card.appendChild(cardHeader);
        card.appendChild(cardBody);
        return card;
    }

    // 创建简单检查区域
    function createSimpleSection(title, message, isValid, url = null) {
        const section = utils.createElement('div', 'margin: 12px 0 !important;');
        const sectionTitle = utils.createElement('div', 'font-weight: 600 !important; font-size: 13px !important; margin-bottom: 8px !important; color: #333 !important;', title);
        const status = utils.createElement('div', 'display: flex !important; align-items: center !important; gap: 8px !important;');
        const icon = utils.createElement('span', `color: ${isValid ? '#28a745' : '#dc3545'} !important;`, isValid ? '✓' : '✗');
        const text = utils.createElement('span', 'font-size: 13px !important;', message);

        status.appendChild(icon);
        status.appendChild(text);
        section.appendChild(sectionTitle);
        section.appendChild(status);

        // 如果有URL,添加链接显示
        if (url && url.trim() !== '') {
            const urlContainer = utils.createElement('div', 'margin-top: 8px !important; margin-left: 20px !important;');
            const urlLink = utils.createElement('a', `
                color: #007bff !important;
                text-decoration: none !important;
                font-size: 12px !important;
                word-break: break-all !important;
                display: inline-block !important;
                padding: 4px 8px !important;
                background: #f8f9fa !important;
                border-radius: 4px !important;
                border: 1px solid #e9ecef !important;
                transition: all 0.2s !important;
            `, url);

            urlLink.href = url;
            urlLink.target = '_blank';
            urlLink.rel = 'noopener noreferrer';

            // 添加悬停效果
            urlLink.addEventListener('mouseenter', () => {
                urlLink.style.background = '#e9ecef';
                urlLink.style.textDecoration = 'underline';
            });
            urlLink.addEventListener('mouseleave', () => {
                urlLink.style.background = '#f8f9fa';
                urlLink.style.textDecoration = 'none';
            });

            urlContainer.appendChild(urlLink);
            section.appendChild(urlContainer);
        }

        return section;
    }

    // 创建检查项区域
    function createCheckSection(title, items) {
        const section = utils.createElement('div', 'margin: 12px 0 !important;');
        const sectionTitle = utils.createElement('div', 'font-weight: 600 !important; font-size: 13px !important; margin-bottom: 8px !important; color: #333 !important;', title);
        section.appendChild(sectionTitle);

        items.forEach(item => {
            const itemDiv = utils.createElement('div', 'display: flex !important; align-items: flex-start !important; gap: 8px !important; margin: 4px 0 !important; font-size: 13px !important;');
            const icon = utils.createElement('span', `color: ${item.status ? '#28a745' : '#dc3545'} !important; flex-shrink: 0 !important; margin-top: 1px !important;`, item.status ? '✓' : '✗');
            const content = utils.createElement('div', 'flex: 1 !important;');
            const label = utils.createElement('div', 'margin-bottom: 2px !important;', item.label);
            const detail = utils.createElement('div', 'font-size: 11px !important; color: #666 !important; word-break: break-all !important;', item.detail);

            content.appendChild(label);
            if (item.detail) content.appendChild(detail);
            itemDiv.appendChild(icon);
            itemDiv.appendChild(content);
            section.appendChild(itemDiv);
        });

        return section;
    }

    // 创建编程步骤区域
    function createProgrammingStepsSection(programmingSteps) {
        const section = utils.createElement('div', 'margin: 12px 0 !important;');
        const title = utils.createElement('div', 'font-weight: 600 !important; font-size: 13px !important; margin-bottom: 8px !important; color: #333 !important;', '编程步骤');
        section.appendChild(title);

        const table = utils.createElement('div', `
            border: 1px solid #e1e5e9 !important;
            border-radius: 6px !important;
            overflow: hidden !important;
            font-size: 12px !important;
        `);

        // 表头
        const headerColumns = ['名称', '提示卡', '创作任务', '正则检测', '快捷输入', '提交作品'];
        const header = utils.createElement('div', `
            display: grid !important;
            grid-template-columns: 2fr 1fr 1fr 1fr 1fr 1fr !important;
            background: #f8f9fa !important;
            font-weight: 600 !important;
            border-bottom: 1px solid #e1e5e9 !important;
        `);

        headerColumns.forEach(headerText => {
            const cell = utils.createElement('div', 'padding: 8px 6px !important; border-right: 1px solid #e1e5e9 !important;', headerText);
            header.appendChild(cell);
        });

        table.appendChild(header);

        // 数据行
        programmingSteps.forEach((step, index) => {
            const row = utils.createElement('div', `
                display: grid !important;
                grid-template-columns: 2fr 1fr 1fr 1fr 1fr 1fr !important;
                ${index % 2 === 0 ? 'background: #fafafa !important;' : 'background: white !important;'}
                border-bottom: 1px solid #f0f0f0 !important;
            `);

            const nameCell = utils.createElement('div', 'padding: 8px 6px !important; border-right: 1px solid #e1e5e9 !important; word-break: break-all !important;', `${step.sort}📍${step.name}`);
            row.appendChild(nameCell);

            step.checks.forEach(check => {
                const cell = utils.createElement('div', 'padding: 8px 6px !important; border-right: 1px solid #e1e5e9 !important; text-align: center !important;', check.isConfigured ? '✅' : '❌');
                row.appendChild(cell);
            });

            table.appendChild(row);
        });

        section.appendChild(table);
        return section;
    }

    // 创建题目步骤区域
    function createQuestionStepsSection(questionSteps) {
        const table = utils.createElement('div', `
            border: 1px solid #e1e5e9 !important;
            border-radius: 6px !important;
            overflow: hidden !important;
            font-size: 12px !important;
            margin-top: 8px !important;
        `);

        // 表头
        const headerColumns = ['名称', '题目ID', '题目名称', '知识点标签'];
        const header = utils.createElement('div', `
            display: grid !important;
            grid-template-columns: 2fr 1fr 2fr 2fr !important;
            background: #f8f9fa !important;
            font-weight: 600 !important;
            border-bottom: 1px solid #e1e5e9 !important;
        `);

        headerColumns.forEach(headerText => {
            const cell = utils.createElement('div', 'padding: 8px 6px !important; border-right: 1px solid #e1e5e9 !important;', headerText);
            header.appendChild(cell);
        });

        table.appendChild(header);

        // 数据行
        questionSteps.forEach((step, index) => {
            const row = utils.createElement('div', `
                display: grid !important;
                grid-template-columns: 2fr 1fr 2fr 2fr !important;
                ${index % 2 === 0 ? 'background: #fafafa !important;' : 'background: white !important;'}
                border-bottom: 1px solid #f0f0f0 !important;
            `);

            // 步骤名称
            const nameCell = utils.createElement('div', 'padding: 8px 6px !important; border-right: 1px solid #e1e5e9 !important; word-break: break-all !important;', `${step.sort}📍${step.name}`);
            row.appendChild(nameCell);

            // 题目ID、题目名称、知识点标签
            step.checks.forEach(check => {
                const cell = utils.createElement('div', `
                    padding: 8px 6px !important;
                    border-right: 1px solid #e1e5e9 !important;
                    word-break: break-all !important;
                    ${check.isConfigured ? 'color: #28a745 !important;' : 'color: #dc3545 !important;'}
                `);

                if (check.field === 'questionId') {
                    if (Array.isArray(check.value) && check.value.length > 0) {
                        // 为每个题目ID创建链接
                        check.value.forEach((questionId, index) => {
                            if (index > 0) {
                                cell.appendChild(document.createTextNode(', '));
                            }

                            const link = utils.createElement('a', `
                                color: #007bff !important;
                                text-decoration: none !important;
                                transition: all 0.2s !important;
                            `, questionId);

                            link.href = `https://tyca.codemao.cn/weekly-test/topic/detail?questionId=${questionId}&type=1`;
                            link.target = '_blank';
                            link.rel = 'noopener noreferrer';

                            // 添加悬停效果
                            link.addEventListener('mouseenter', () => {
                                link.style.textDecoration = 'underline';
                            });
                            link.addEventListener('mouseleave', () => {
                                link.style.textDecoration = 'none';
                            });

                            cell.appendChild(link);
                        });
                    } else {
                        cell.textContent = '-';
                    }
                } else if (check.field === 'questionName') {
                    if (Array.isArray(check.value) && check.value.length > 0) {
                        cell.textContent = check.value.join(', ');
                    } else {
                        cell.textContent = '-';
                    }
                } else if (check.field === 'knowledgeArr') {
                    if (Array.isArray(check.value) && check.value.length > 0) {
                        cell.textContent = check.value.join(', ');
                    } else {
                        cell.textContent = '-';
                    }
                }

                row.appendChild(cell);
            });

            table.appendChild(row);
        });

        return table;
    }

    // 初始化
    function init() {
        courseId = utils.getCourseId();
        createFloatingButton();

        if (courseId) {
            fetchCourseLinks(courseId).then(data => {
                courseData = data;
            });
        }

        // 检查脚本更新
        setTimeout(checkForUpdates, 3000);
    }

    // 页面加载完成后初始化
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

})();