51CTO题目助手

支持复制题目到剪贴板(可选是否带提示词),支持设置提示词

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         51CTO题目助手
// @namespace    http://tampermonkey.net/
// @homepage	 https://github.com/minivv/tampermonkey
// @version      0.1
// @description  支持复制题目到剪贴板(可选是否带提示词),支持设置提示词
// @author       minivv
// @match        https://rk.51cto.com/t/n/exam/answer/*
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @icon         https://linux.do/uploads/default/optimized/3X/9/d/9dd49731091ce8656e94433a26a3ef36062b3994_2_32x32.png
// @license      Apache-2.0
// ==/UserScript==

(function() {
    'use strict';

    // --- 默认配置 ---
    const DEFAULT_PROMPT = "请作为一名资深的IT技术专家和讲师,详细分析以下选择题。请按以下结构进行解答:\n1.  题目分析:解释题目考查的核心知识点。\n2.  正确选项解析:详细说明正确选项为什么正确,并提供相关的背景知识和例子。\n3.  错误选项分析:逐个分析其他选项为什么错误。\n4.  知识点总结:总结与该题目相关的关键概念和学习要点。\n5.  扩展思考:如果适用,可以提出一些相关的扩展问题或实际应用场景。\n请确保解释清晰、准确、易于理解。题目内容如下:";
    const DEFAULT_COPY_WITH_PROMPT = true;

    // --- 全局变量 ---
    let userPrompt = '';
    let copyWithPrompt = DEFAULT_COPY_WITH_PROMPT;

    // --- 加载设置 ---
    function loadSettings() {
        userPrompt = GM_getValue('userPrompt', DEFAULT_PROMPT);
        copyWithPrompt = GM_getValue('copyWithPrompt', DEFAULT_COPY_WITH_PROMPT);
    }
    // --- 保存设置 ---
    function saveSettings(newPrompt, newCopyWithPrompt) {
        userPrompt = newPrompt;
        copyWithPrompt = newCopyWithPrompt;
        GM_setValue('userPrompt', userPrompt);
        GM_setValue('copyWithPrompt', copyWithPrompt);
    }

    // --- 弹窗编辑提示词和开关 ---
    function showPromptDialog() {
        const dialog = document.createElement('div');
        dialog.style.position = 'fixed';
        dialog.style.left = '50%';
        dialog.style.top = '50%';
        dialog.style.transform = 'translate(-50%, -50%)';
        dialog.style.background = '#fff';
        dialog.style.border = '1px solid #ccc';
        dialog.style.borderRadius = '8px';
        dialog.style.zIndex = 99999;
        dialog.style.padding = '24px 20px 16px 20px';
        dialog.style.boxShadow = '0 4px 24px rgba(0,0,0,0.15)';
        dialog.style.minWidth = '600px';
        dialog.innerHTML = `
            <div style="font-weight:bold;font-size:16px;margin-bottom:10px;">设置</div>
            <label style="display:block;margin-bottom:5px;">提示词:</label>
            <textarea id="tmk-prompt" style="width:100%;height:150px;border:1px solid #ccc;">${userPrompt}</textarea>
            <label style="display:block;margin:10px 0 4px 0;">
              <input type="checkbox" id="tmk-copywithprompt" ${copyWithPrompt ? 'checked' : ''}> 复制时自动带提示词
            </label>
            <div style="text-align:right;margin-top:10px;">
                <button id="tmk-save" style="margin-right:10px;">保存</button>
                <button id="tmk-cancel">取消</button>
            </div>
        `;
        document.body.appendChild(dialog);
        document.getElementById('tmk-save').onclick = function() {
            const newPrompt = document.getElementById('tmk-prompt').value;
            const newCopyWithPrompt = document.getElementById('tmk-copywithprompt').checked;
            saveSettings(newPrompt, newCopyWithPrompt);
            document.body.removeChild(dialog);
            showTip('设置已保存!');
        };
        document.getElementById('tmk-cancel').onclick = function() {
            document.body.removeChild(dialog);
        };
    }

    // --- 获取当前题目文本 ---
    function getCurrentQuestionText(card) {
        let questionText = "";
        const titleElement = card.querySelector('.exam-item-title p');
        if (titleElement) {
            questionText += titleElement.innerText.trim() + "\n";
        }
        const options = card.querySelectorAll('.exam-item-content .el-radio-group .el-radio');
        if (options.length > 0) {
            options.forEach(option => {
                const label = option.querySelector('.el-radio__label');
                if (label) questionText += label.innerText.trim() + "\n";
            });
        }
        return questionText.trim();
    }

    // --- 复制题目到剪贴板 ---
    function copyQuestion(card) {
        const question = getCurrentQuestionText(card);
        let text = question;
        if (copyWithPrompt) {
            text = userPrompt + "\n\n" + question;
        }
        navigator.clipboard.writeText(text).then(() => {
            showTip('题目已复制到剪贴板!');
        }).catch(err => {
            showTip('复制失败: ' + err, true);
        });
    }

    // --- 显示临时提示 ---
    function showTip(msg, isErr) {
        let tip = document.createElement('div');
        tip.textContent = msg;
        tip.style.position = 'fixed';
        tip.style.left = '50%';
        tip.style.top = '20%';
        tip.style.transform = 'translateX(-50%)';
        tip.style.background = isErr ? '#d93025' : '#28a745';
        tip.style.color = '#fff';
        tip.style.padding = '10px 24px';
        tip.style.borderRadius = '6px';
        tip.style.fontSize = '16px';
        tip.style.zIndex = 99999;
        document.body.appendChild(tip);
        setTimeout(() => { tip.remove(); }, 1800);
    }

    // --- 插入按钮到每道题 ---
    function insertButtons() {
        // 查找每道题的操作按钮组
        document.querySelectorAll('.exam-item-card-inner').forEach(card => {
            const opBar = card.querySelector('.card-header-operation.flex');
            if (!opBar || opBar.querySelector('.tmk-copy-btn')) return; // 已插入则跳过
            // 复制题目按钮
            const copyBtn = document.createElement('div');
            copyBtn.className = 'card-operation-item tmk-copy-btn';
            copyBtn.innerHTML = `<button type="button" class="el-button is-link"><span><img src="https://cdn-icons-png.flaticon.com/128/11238/11238246.png" style="width:16px;vertical-align:middle;">复制题目</span></button>`;
            copyBtn.onclick = function(e) {
                e.stopPropagation();
                copyQuestion(card);
            };
            // 编辑提示词按钮
            const promptBtn = document.createElement('div');
            promptBtn.className = 'card-operation-item tmk-prompt-btn';
            promptBtn.innerHTML = `<button type="button" class="el-button is-link"><span><img src="https://cdn-icons-png.flaticon.com/128/2040/2040510.png" style="width:16px;vertical-align:middle;">编辑提示词</span></button>`;
            promptBtn.onclick = function(e) {
                e.stopPropagation();
                showPromptDialog();
            };
            // 插入到操作栏
            opBar.appendChild(copyBtn);
            opBar.appendChild(promptBtn);
        });
    }

    // --- 添加样式使按钮一致 ---
    GM_addStyle(`
      .tmk-copy-btn, .tmk-prompt-btn { display:inline-block; }
      .tmk-copy-btn .el-button, .tmk-prompt-btn .el-button { padding: 4px 0px; font-size: 14px; }
      .tmk-copy-btn .el-button img, .tmk-prompt-btn .el-button img { margin-right: 2px; }
    `);

    // --- 初始化 ---
    function init() {
        loadSettings();
        insertButtons();
        // 监听动态加载(如切换题目时)
        const observer = new MutationObserver(() => insertButtons());
        observer.observe(document.body, { childList: true, subtree: true });
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

})();