Greasy Fork

岐黄天使刷课助手 - 题库模块

岐黄天使刷课助手的题库管理模块,负责题目的获取、存储、显示和复制。

当前为 2025-05-24 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/537077/1594815/%E5%B2%90%E9%BB%84%E5%A4%A9%E4%BD%BF%E5%88%B7%E8%AF%BE%E5%8A%A9%E6%89%8B%20-%20%E9%A2%98%E5%BA%93%E6%A8%A1%E5%9D%97.js

// ==UserScript==
// @name         岐黄天使刷课助手 - 题库模块
// @namespace    http://tampermonkey.net/qhtx-modules
// @version      1.3.0
// @description  岐黄天使刷课助手的题库管理模块,负责题目的获取、存储、显示和复制。
// @author       AI助手
// ==/UserScript==

// 题库模块
(function() {
    'use strict';

    // 显示题目面板
    window.showQuestionPanel = function() {
        // 检查是否已存在题目面板
        if (document.getElementById('qh-question-panel')) {
            document.getElementById('qh-question-panel').style.display = 'block';
            document.getElementById('qh-question-overlay').style.display = 'block';
            return;
        }

        // 创建遮罩层
        const overlay = document.createElement('div');
        overlay.className = 'qh-question-overlay';
        overlay.id = 'qh-question-overlay';
        document.body.appendChild(overlay);

        // 创建题目面板
        const panel = document.createElement('div');
        panel.className = 'qh-question-panel';
        panel.id = 'qh-question-panel';
        panel.innerHTML = `
            <div class="qh-question-title">
                题目和答案
                <span class="qh-question-close" id="qh-question-close">×</span>
            </div>
            <div class="qh-question-content" id="qh-question-content">
                <div style="text-align: center; padding: 20px;">正在获取题目和答案...</div>
            </div>
            <div class="qh-question-status" id="qh-question-status">
                已保存题目: ${window.qh.savedQuestionBank.length} 道
            </div>
            <div class="qh-question-btns">
                <button class="qh-question-btn" id="qh-save-questions-btn">保存题目</button>
                <button class="qh-question-btn" id="qh-copy-questions-btn">复制到剪贴板</button>
            </div>
        `;
        document.body.appendChild(panel);

        // 绑定关闭按钮事件
        document.getElementById('qh-question-close').addEventListener('click', function() {
            document.getElementById('qh-question-panel').style.display = 'none';
            document.getElementById('qh-question-overlay').style.display = 'none';
        });

        // 绑定保存题目按钮事件
        document.getElementById('qh-save-questions-btn').addEventListener('click', function() {
            saveQuestions();
        });

        // 绑定复制题目按钮事件
        document.getElementById('qh-copy-questions-btn').addEventListener('click', function() {
            copyQuestionsToClipboard();
        });

        // 显示面板
        document.getElementById('qh-question-panel').style.display = 'block';
        document.getElementById('qh-question-overlay').style.display = 'block';

        // 获取题目和答案
        getQuestionsAndAnswers();
    };

    // 获取题目和答案
    function getQuestionsAndAnswers() {
        try {
            // 更新状态
            updateStatus('正在获取题目和答案...');

            // 查找题目容器
            const questions = [];
            let questionContainer = null;

            // 尝试在主文档中查找题目
            questionContainer = document.querySelector('.timu');
            if (questionContainer) {
                // 从主文档中获取题目
                const question = extractQuestionFromElement(questionContainer);
                if (question) {
                    questions.push(question);
                }
            } else {
                // 尝试在iframe中查找题目
                const frames = document.querySelectorAll('iframe');
                for (const frame of frames) {
                    try {
                        const frameDoc = frame.contentDocument || frame.contentWindow.document;
                        questionContainer = frameDoc.querySelector('.timu');
                        if (questionContainer) {
                            // 从iframe中获取题目
                            const question = extractQuestionFromElement(questionContainer, frame);
                            if (question) {
                                questions.push(question);
                            }
                            break;
                        }
                    } catch (e) {
                        console.error('无法访问iframe内容:', e);
                    }
                }
            }

            // 如果找到了题目,显示在面板中
            if (questions.length > 0) {
                displayQuestions(questions);
            } else {
                // 如果没有找到题目,尝试查找题目列表
                const questionList = getQuestionList();
                if (questionList.length > 0) {
                    displayQuestions(questionList);
                } else {
                    // 如果仍然没有找到题目,显示错误信息
                    document.getElementById('qh-question-content').innerHTML = `
                        <div style="text-align: center; padding: 20px; color: #f44336;">
                            未找到题目,请确保您在考试或练习页面。
                        </div>
                    `;
                }
            }
        } catch (e) {
            console.error('获取题目和答案出错:', e);
            document.getElementById('qh-question-content').innerHTML = `
                <div style="text-align: center; padding: 20px; color: #f44336;">
                    获取题目出错: ${e.message}
                </div>
            `;
        }
    }

    // 从元素中提取题目信息
    function extractQuestionFromElement(element, iframe = null) {
        try {
            // 获取题目文本
            const questionTextElement = element.querySelector('.subject');
            if (!questionTextElement) return null;

            const questionText = questionTextElement.textContent.trim();
            if (!questionText) return null;

            // 生成唯一ID
            const questionId = generateQuestionId(questionText);

            // 获取选项
            const optionsElements = element.querySelectorAll('.option');
            const options = Array.from(optionsElements).map(option => option.textContent.trim());

            // 获取答案
            let answer = '';
            const answerElement = element.querySelector('.answer');
            if (answerElement) {
                answer = answerElement.textContent.replace('答案:', '').trim();
            }

            // 获取解析
            let analysis = '';
            const analysisElement = element.querySelector('.analysis');
            if (analysisElement) {
                analysis = analysisElement.textContent.replace('解析:', '').trim();
            }

            return {
                id: questionId,
                question: questionText,
                options: options,
                answer: answer,
                analysis: analysis,
                isInIframe: !!iframe,
                iframe: iframe
            };
        } catch (e) {
            console.error('提取题目信息出错:', e);
            return null;
        }
    }

    // 生成题目ID
    function generateQuestionId(questionText) {
        // 使用题目文本的哈希值作为ID
        let hash = 0;
        for (let i = 0; i < questionText.length; i++) {
            const char = questionText.charCodeAt(i);
            hash = ((hash << 5) - hash) + char;
            hash = hash & hash; // 转换为32位整数
        }
        return 'q_' + Math.abs(hash).toString(16);
    }

    // 获取题目列表
    function getQuestionList() {
        const questions = [];

        // 尝试在主文档中查找题目列表
        let questionElements = document.querySelectorAll('.timu');
        if (questionElements.length > 0) {
            // 从主文档中获取题目列表
            for (const element of questionElements) {
                const question = extractQuestionFromElement(element);
                if (question) {
                    questions.push(question);
                }
            }
        } else {
            // 尝试在iframe中查找题目列表
            const frames = document.querySelectorAll('iframe');
            for (const frame of frames) {
                try {
                    const frameDoc = frame.contentDocument || frame.contentWindow.document;
                    questionElements = frameDoc.querySelectorAll('.timu');
                    if (questionElements.length > 0) {
                        // 从iframe中获取题目列表
                        for (const element of questionElements) {
                            const question = extractQuestionFromElement(element, frame);
                            if (question) {
                                questions.push(question);
                            }
                        }
                        break;
                    }
                } catch (e) {
                    console.error('无法访问iframe内容:', e);
                }
            }
        }

        return questions;
    }

    // 显示题目
    function displayQuestions(questions) {
        const contentElement = document.getElementById('qh-question-content');
        if (!contentElement) return;

        // 构建HTML
        let html = '';
        questions.forEach((question, index) => {
            html += `
                <div class="qh-question-item" data-id="${question.id}">
                    <div class="qh-question-text">${index + 1}. ${question.question}</div>
                    <div class="qh-question-options">
                        ${question.options.map((option, i) => `
                            <div class="qh-question-option">${String.fromCharCode(65 + i)}. ${option}</div>
                        `).join('')}
                    </div>
                    <div class="qh-question-answer">答案: ${question.answer || '未知'}</div>
                    ${question.analysis ? `<div class="qh-question-analysis">解析: ${question.analysis}</div>` : ''}
                </div>
            `;
        });

        contentElement.innerHTML = html;

        // 更新状态
        document.getElementById('qh-question-status').textContent = `共 ${questions.length} 道题目,已保存 ${window.qh.savedQuestionBank.length} 道题目`;
    }

    // 保存题目
    function saveQuestions() {
        try {
            // 获取当前显示的题目
            const questionItems = document.querySelectorAll('.qh-question-item');
            if (questionItems.length === 0) {
                alert('没有可保存的题目');
                return;
            }

            // 收集题目
            const questions = [];
            questionItems.forEach(item => {
                const id = item.getAttribute('data-id');
                const questionText = item.querySelector('.qh-question-text').textContent.replace(/^\d+\.\s*/, '');
                const optionElements = item.querySelectorAll('.qh-question-option');
                const options = Array.from(optionElements).map(option => option.textContent.trim());
                const answerText = item.querySelector('.qh-question-answer').textContent.replace('答案:', '').trim();
                
                let analysisText = '';
                const analysisElement = item.querySelector('.qh-question-analysis');
                if (analysisElement) {
                    analysisText = analysisElement.textContent.replace('解析:', '').trim();
                }

                questions.push({
                    id: id,
                    question: questionText,
                    options: options,
                    answer: answerText,
                    analysis: analysisText,
                    updateTime: Date.now()
                });
            });

            // 合并题库
            const newQuestions = [];
            const updatedQuestions = [];

            questions.forEach(newQuestion => {
                // 检查题目是否已存在
                const existingIndex = window.qh.savedQuestionBank.findIndex(q => q.id === newQuestion.id);
                if (existingIndex === -1) {
                    // 新题目
                    window.qh.savedQuestionBank.push(newQuestion);
                    newQuestions.push(newQuestion);
                } else {
                    // 更新已有题目
                    const existingQuestion = window.qh.savedQuestionBank[existingIndex];
                    
                    // 只有在新题目有答案且旧题目没有答案,或者新题目更新时间更新时才更新
                    if ((!existingQuestion.answer && newQuestion.answer) || 
                        (newQuestion.updateTime && (!existingQuestion.updateTime || newQuestion.updateTime > existingQuestion.updateTime))) {
                        window.qh.savedQuestionBank[existingIndex] = newQuestion;
                        updatedQuestions.push(newQuestion);
                    }
                }
            });

            // 保存题库
            GM_setValue('qh-question-bank', window.qh.savedQuestionBank);

            // 更新状态
            document.getElementById('qh-question-status').textContent = `保存成功: 新增 ${newQuestions.length} 道题目, 更新 ${updatedQuestions.length} 道题目, 总计 ${window.qh.savedQuestionBank.length} 道题目`;
            
            // 更新主面板的题库状态
            const statusElement = document.getElementById('qh-question-status');
            if (statusElement) {
                statusElement.textContent = `题库状态: 已保存 ${window.qh.savedQuestionBank.length} 道题目`;
            }

            // 如果启用了远程题库自动同步,则上传题库
            if (window.qh.remoteQuestionBankConfig.enabled && 
                window.qh.remoteQuestionBankConfig.uploadEnabled && 
                typeof uploadQuestionBank === 'function') {
                uploadQuestionBank();
            }
        } catch (e) {
            console.error('保存题目出错:', e);
            alert('保存题目出错: ' + e.message);
        }
    }

    // 复制题目到剪贴板
    function copyQuestionsToClipboard() {
        try {
            // 获取当前显示的题目
            const questionItems = document.querySelectorAll('.qh-question-item');
            if (questionItems.length === 0) {
                alert('没有可复制的题目');
                return;
            }

            // 构建文本
            let text = '';
            questionItems.forEach((item, index) => {
                const questionText = item.querySelector('.qh-question-text').textContent.replace(/^\d+\.\s*/, '');
                const optionElements = item.querySelectorAll('.qh-question-option');
                const options = Array.from(optionElements).map(option => option.textContent.trim());
                const answerText = item.querySelector('.qh-question-answer').textContent.replace('答案:', '').trim();
                
                let analysisText = '';
                const analysisElement = item.querySelector('.qh-question-analysis');
                if (analysisElement) {
                    analysisText = analysisElement.textContent.replace('解析:', '').trim();
                }

                text += `${index + 1}. ${questionText}\n`;
                options.forEach(option => {
                    text += `   ${option}\n`;
                });
                text += `答案: ${answerText}\n`;
                if (analysisText) {
                    text += `解析: ${analysisText}\n`;
                }
                text += '\n';
            });

            // 复制到剪贴板
            GM_setClipboard(text);

            // 更新状态
            document.getElementById('qh-question-status').textContent = `已复制 ${questionItems.length} 道题目到剪贴板`;
        } catch (e) {
            console.error('复制题目出错:', e);
            alert('复制题目出错: ' + e.message);
        }
    }
})();