您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Vue SPA 页面,每题下方显示答案,支持单选、多选、判断题,特殊字符匹配
// ==UserScript== // @name ICVE 自动显示答案(单选/多选/判断题) // @namespace http://tampermonkey.net/ // @version 1.6 // @description Vue SPA 页面,每题下方显示答案,支持单选、多选、判断题,特殊字符匹配 // @match https://ai.icve.com.cn/preview-exam/* // @grant none // ==/UserScript== (function() { 'use strict'; // ------------------- 工具函数 ------------------- function getAdminToken() { const match = document.cookie.match(/(?:^|;\s*)admin-token=([^;]+)/); return match ? decodeURIComponent(match[1]) : null; } function getExamIdFromUrl() { const parts = window.location.pathname.split("/"); return parts[2]; } function numberToLetter(num) { const letters = "ABCDEFG"; return letters[num] || ""; } function normalizeText(str) { if (!str) return ""; return str .replace(/\s+/g, "") // 去掉空格和换行 .replace(/ /g, "") // 去掉 HTML 空格 .replace(/[^\w\u4e00-\u9fa5]/g, ""); // 只保留中文、字母、数字 } async function fetchExamPaper(examId, token) { const url = `https://ai.icve.com.cn/prod-api/course/exam/paper?id=${examId}&groupId=0`; const res = await fetch(url, { headers: { "Authorization": "Bearer " + token } }); return res.json(); } function extractTaskExamRecord(paperData) { return (paperData && paperData.taskExamRecord) ? paperData.taskExamRecord : null; } function buildGetInfoUrl(taskExamRecord) { const courseInfoId = taskExamRecord.courseInfoId; const taskId = taskExamRecord.id; const examId = taskExamRecord.examId; const studentId = taskExamRecord.userId; return `https://ai.icve.com.cn/prod-api/course/exam/record/getInfo?courseInfoId=${courseInfoId}&taskId=${taskId}&examId=${examId}&studentId=${studentId}&type=2`; } async function fetchExamInfo(getInfoUrl, token) { const res = await fetch(getInfoUrl, { headers: { "Authorization": "Bearer " + token } }); return res.json(); } // ------------------- 插入答案函数 ------------------- function insertAnswerSingle(single, q) { const titleEl = single.querySelector(".single-title-content"); if (!titleEl) return; const singleText = normalizeText(titleEl.textContent); const qText = normalizeText(q.title); if (!singleText.includes(qText)) return; if (single.querySelector(".icve-answer-inserted")) return; const answerLetters = (q.answer || "").split("").map(n => numberToLetter(parseInt(n))).join(""); const ansDiv = document.createElement("div"); ansDiv.className = "icve-answer-inserted"; ansDiv.innerText = "答案:" + answerLetters; ansDiv.style.color = "blue"; ansDiv.style.fontWeight = "bold"; ansDiv.style.marginTop = "4px"; single.appendChild(ansDiv); } function insertAnswerMultiple(single, q) { const titleEl = single.querySelector(".multiple-title-content"); if (!titleEl) return; const singleText = normalizeText(titleEl.textContent); const qText = normalizeText(q.title); if (!singleText.includes(qText)) return; if (single.querySelector(".icve-answer-inserted")) return; const answerLetters = (q.answer || "") .split("") .map(n => numberToLetter(parseInt(n))) .join(","); const ansDiv = document.createElement("div"); ansDiv.className = "icve-answer-inserted"; ansDiv.innerText = "答案:" + answerLetters; ansDiv.style.color = "blue"; ansDiv.style.fontWeight = "bold"; ansDiv.style.marginTop = "4px"; single.appendChild(ansDiv); } function insertAnswerJudge(single, q) { const titleEl = single.querySelector(".judge-title-content"); if (!titleEl) return; const singleText = normalizeText(titleEl.textContent); const qText = normalizeText(q.title); if (!singleText.includes(qText)) return; if (single.querySelector(".icve-answer-inserted")) return; // 判断题答案映射:0->A(正确), 1->B(错误) const answerMap = ["A", "B"]; const answerLetters = answerMap[q.answer] || ""; const ansDiv = document.createElement("div"); ansDiv.className = "icve-answer-inserted"; ansDiv.innerText = "答案:" + answerLetters; ansDiv.style.color = "blue"; ansDiv.style.fontWeight = "bold"; ansDiv.style.marginTop = "4px"; single.appendChild(ansDiv); } // ------------------- 主函数 ------------------- async function main() { const token = getAdminToken(); if (!token) { alert("未找到 admin-token"); return; } const examId = getExamIdFromUrl(); if (!examId) { alert("未找到 examId"); return; } try { const paperData = await fetchExamPaper(examId, token); const taskExamRecord = extractTaskExamRecord(paperData); if (!taskExamRecord) { alert("未找到 taskExamRecord"); return; } const infoUrl = buildGetInfoUrl(taskExamRecord); const infoData = await fetchExamInfo(infoUrl, token); const questions = infoData?.data?.questions || []; const containerParent = document.querySelector("body"); if (!containerParent) return; const observer = new MutationObserver(() => { const singles = containerParent.querySelectorAll("div.single"); singles.forEach(single => questions.forEach(q => insertAnswerSingle(single, q))); const multiples = containerParent.querySelectorAll("div.multiple"); multiples.forEach(single => questions.forEach(q => insertAnswerMultiple(single, q))); const judges = containerParent.querySelectorAll("div.judge"); judges.forEach(single => questions.forEach(q => insertAnswerJudge(single, q))); }); observer.observe(containerParent, { childList: true, subtree: true }); // 处理已渲染的题目 const singles = containerParent.querySelectorAll("div.single"); singles.forEach(single => questions.forEach(q => insertAnswerSingle(single, q))); const multiples = containerParent.querySelectorAll("div.multiple"); multiples.forEach(single => questions.forEach(q => insertAnswerMultiple(single, q))); const judges = containerParent.querySelectorAll("div.judge"); judges.forEach(single => questions.forEach(q => insertAnswerJudge(single, q))); } catch (e) { console.error(e); alert("获取答案失败,请查看控制台"); } } setTimeout(main, 500); })();