Greasy Fork

Greasy Fork is available in English.

iTalent 在线考试自动答题助手(带题库上传)

自动检测 cloud.italent.cn 考试题目并查询答案,高亮显示正确答案 + 支持题库上传功能

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

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         iTalent 在线考试自动答题助手(带题库上传)
// @namespace    https://yangtaoer.com.cn/
// @version      1.5
// @description  自动检测 cloud.italent.cn 考试题目并查询答案,高亮显示正确答案 + 支持题库上传功能
// @author       yang
// @match        https://cloud.italent.cn/*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @connect      yangtaoer.com.cn
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    const CONFIG = {
        apiUrl: 'https://yangtaoer.com.cn/exam/api/parse',
        uploadUrl: 'https://yangtaoer.com.cn/exam/api/upload',
        checkInterval: 2000,
        targetKeyword: 'RestGetExamResultAndAnalysisByResultID',
    };

    let knownQuestions = new Set();
    let paused = false;
    let cachedResultJson = null; // 保存捕获到的题库数据

    // === UI面板 ===
    const panel = document.createElement('div');
    panel.innerHTML = `
        <div id="exam-helper-panel">
            <button id="exam-helper-toggle">⏸ 暂停检测</button>
            <button id="exam-helper-clear">🧹 清空标记</button>
            <button id="exam-helper-upload">📤 上传题库</button>
            <span id="exam-helper-status">状态:运行中</span>
        </div>
    `;
    document.body.appendChild(panel);

    GM_addStyle(`
        #exam-helper-panel {
            position: fixed;
            top: 80px;
            right: 30px;
            background: rgba(0,0,0,0.75);
            color: #fff;
            padding: 10px 15px;
            border-radius: 10px;
            z-index: 999999;
            font-size: 14px;
            box-shadow: 0 0 10px rgba(0,0,0,0.4);
        }
        #exam-helper-panel button {
            margin: 2px 5px;
            background: #2e8b57;
            color: white;
            border: none;
            padding: 5px 10px;
            border-radius: 5px;
            cursor: pointer;
        }
        #exam-helper-panel button:hover {
            background: #3cb371;
        }
        .exam-highlight {
            background-color: #38e42c !important;
            position: relative;
        }
        .exam-highlight::after {
            content: "√";
            color: red;
            font-weight: bold;
            margin-left: 5px;
        }
    `);

    // === UI交互 ===
    document.getElementById('exam-helper-toggle').onclick = () => {
        paused = !paused;
        document.getElementById('exam-helper-toggle').innerText = paused ? '▶ 开始检测' : '⏸ 暂停检测';
        document.getElementById('exam-helper-status').innerText = `状态:${paused ? '暂停' : '运行中'}`;
    };

    document.getElementById('exam-helper-clear').onclick = () => {
        document.querySelectorAll('.exam-highlight').forEach(e => e.classList.remove('exam-highlight'));
        knownQuestions.clear();
        console.log('✅ [答题助手] 已清空标记与缓存');
        showToast('✅ 已清空标记与缓存');
    };

    // === 上传按钮逻辑 ===
    document.getElementById('exam-helper-upload').onclick = () => {
        if (!cachedResultJson) {
            showToast('⚠️ 未检测到任何 “RestGetExamResultAndAnalysisByResultID” 请求数据!', 'warn');
            console.warn('未捕获到目标请求数据');
            return;
        }

        showToast('⏳ 正在上传题库,请稍候...');
        GM_xmlhttpRequest({
            method: 'POST',
            url: CONFIG.uploadUrl,
            headers: { 'Content-Type': 'application/json' },
            data: JSON.stringify(cachedResultJson),
            onload: res => {
                if (res.status === 200) {
                    showToast('✅ 题库上传成功!');
                    console.log('上传响应:', res.responseText);
                } else {
                    showToast('❌ 上传失败,请检查网络或接口', 'error');
                }
            },
            onerror: err => {
                console.error('上传失败', err);
                showToast('❌ 上传失败,请检查网络', 'error');
            }
        });
    };

    // === Toast 弹窗 ===
    function showToast(msg, type = 'info') {
        const div = document.createElement('div');
        div.innerText = msg;
        div.style.position = 'fixed';
        div.style.bottom = '100px';
        div.style.right = '40px';
        div.style.padding = '10px 20px';
        div.style.background = type === 'error' ? '#ff4d4f' :
            type === 'warn' ? '#faad14' :
                '#52c41a';
        div.style.color = '#fff';
        div.style.borderRadius = '8px';
        div.style.fontSize = '14px';
        div.style.zIndex = 999999;
        div.style.boxShadow = '0 0 6px rgba(0,0,0,0.3)';
        document.body.appendChild(div);
        setTimeout(() => div.remove(), 2500);
    }

    // === 捕获请求 ===
    function interceptRequests() {
        // --- XMLHttpRequest ---
        const _open = XMLHttpRequest.prototype.open;
        const _send = XMLHttpRequest.prototype.send;

        XMLHttpRequest.prototype.open = function (...args) {
            this._url = args[1];
            return _open.apply(this, args);
        };

        XMLHttpRequest.prototype.send = function (...args) {
            this.addEventListener('load', function () {
                try {
                    if (this._url && this._url.includes(CONFIG.targetKeyword)) {
                        const text = this.responseText;
                        const json = JSON.parse(text);
                        cachedResultJson = json;
                        console.log('🎯 捕获到 RestGetExamResultAndAnalysisByResultID 请求响应:', json);
                        showToast('✅ 已捕获考试结果数据,可上传题库');
                    }
                } catch (e) {
                    console.warn('捕获请求解析失败:', e);
                }
            });
            return _send.apply(this, args);
        };

        // --- fetch ---
        const _fetch = window.fetch;
        window.fetch = async function (...args) {
            const response = await _fetch(...args);
            const url = args[0];
            if (typeof url === 'string' && url.includes(CONFIG.targetKeyword)) {
                try {
                    const clone = response.clone();
                    const text = await clone.text();
                    const json = JSON.parse(text);
                    cachedResultJson = json;
                    console.log('🎯 捕获到 fetch 请求响应:', json);
                    showToast('✅ 已捕获考试结果数据,可上传题库');
                } catch (e) {
                    console.warn('fetch 响应解析失败:', e);
                }
            }
            return response;
        };
    }

    // === 抓题逻辑 ===
    function extractQuestions() {
        const titles = Array.from(document.getElementsByClassName('exam-topic-item-title-name'));
        const result = [];

        titles.forEach(el => {
            const text = el.innerText.trim();
            if (text && !knownQuestions.has(text)) {
                knownQuestions.add(text);
                result.push(text);
            }
        });
        return result;
    }

    function highlightAnswer(index, answers) {
        const wrapper = document.getElementsByClassName('exam-options-wrapper')[index];
        if (!wrapper) return;

        answers.forEach(ans => {
            let matched = false;
            wrapper.childNodes.forEach(node => {
                try {
                    const content = node.childNodes[1]?.childNodes[0]?.innerText?.trim();
                    if (content === ans) {
                        node.classList.add('exam-highlight');
                        matched = true;
                    }
                } catch {}
            });
            if (!matched) console.warn(`⚠️ 题号 ${index + 1}: 未匹配答案 ${ans}`);
        });
    }

    function queryAnswers(questions) {
        if (questions.length === 0) return;
        console.log(`🔍 新检测到 ${questions.length} 道题,正在查询...`);

        GM_xmlhttpRequest({
            method: 'POST',
            url: CONFIG.apiUrl,
            headers: { 'Content-Type': 'application/json' },
            data: JSON.stringify(questions),
            onload: res => {
                try {
                    const data = JSON.parse(res.responseText).data || [];
                    data.forEach((e, i) => e.answer.length && highlightAnswer(i, e.answer));
                } catch (err) {
                    console.error('❌ 解析接口返回错误', err);
                }
            },
            onerror: err => console.error('❌ 查询接口请求失败', err)
        });
    }

    // === 定时检测题目 ===
    setInterval(() => {
        if (paused) return;
        const newQuestions = extractQuestions();
        if (newQuestions.length > 0) queryAnswers(newQuestions);
    }, CONFIG.checkInterval);

    interceptRequests();
    console.log('✅ [iTalent 答题助手 v1.5] 已启动(含题库上传增强)');
})();