// ==UserScript==
// @name 超星学习通自动答题(章节)
// @namespace http://tampermonkey.net/
// @version 1.0.0
// @description 学习通章节答题
// @author dmhnb6 (Modified by AI)
// @match *://*.chaoxing.com/*
// @match *://*.edu.cn/*
// @grant GM_xmlhttpRequest
// @connect api.deepseek.com
// @original-author dmhnb6
// @original-license MIT
// @original-script https://scriptcat.org/zh-CN/script-show-page/6071
// ==/UserScript==
(function() {
'use strict';
// ======== 用户配置区 ========
const API_KEY = 'API';
const DELAY = 1000; // 适中的延迟,保证稳定
// ===========================
let isPaused = false;
let isRunning = false;
let currentIdx = 0;
let uiCreated = false;
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
let panel, progressBar, progressText, statusLabel, startBtn, pauseBtn;
function createUI() {
if (uiCreated) return;
uiCreated = true;
panel = document.createElement('div');
panel.style = "position:fixed;top:20px;right:20px;z-index:2147483647;width:320px;background:#fff;padding:15px;border-radius:10px;box-shadow:0 10px 30px rgba(0,0,0,0.4);font-family:sans-serif;border:2px solid #8e44ad;";
panel.innerHTML = `
🎯 答题助手
已就绪
`;
document.body.appendChild(panel);
progressBar = document.getElementById('auto-progress-bar');
progressText = document.getElementById('auto-progress-text');
statusLabel = document.getElementById('auto-status-label');
startBtn = document.getElementById('auto-start-btn');
pauseBtn = document.getElementById('auto-pause-btn');
startBtn.onclick = () => {
if (!isRunning) {
currentIdx = 0;
isRunning = true;
isPaused = false;
startBtn.style.display = 'none';
pauseBtn.style.display = 'inline-block';
pauseBtn.innerText = '暂停';
pauseBtn.style.background = '#e74c3c';
startSolve();
}
};
pauseBtn.onclick = () => {
isPaused = !isPaused;
pauseBtn.innerText = isPaused ? '恢复' : '暂停';
pauseBtn.style.background = isPaused ? '#f1c40f' : '#e74c3c';
statusLabel.innerText = isPaused ? '已暂停' : '运行中';
};
}
async function getAIResponse(question, options, type) {
// 【核心恢复】:恢复 V5 原汁原味的高效 Prompt
let sys = "你是一个专业的大学考试答题专家。请先在心里一步步分析题目,然后**必须**将最终答案放在英文方括号内,格式如:[A] 或 [ABC] 或 [正确]。除了方括号内的答案,不要输出多余的解释。";
// 只有遇到填空题时,才追加填空题的格式要求
if (type.includes("填空")) {
sys += "注意:遇到填空题,请将所有空的答案放进同一个方括号内,并用###分隔,例如:[答案一###答案二]。";
}
return new Promise((resolve) => {
GM_xmlhttpRequest({
method: "POST",
url: "https://api.deepseek.com/chat/completions",
headers: { "Content-Type": "application/json", "Authorization": `Bearer ${API_KEY}` },
data: JSON.stringify({
model: "deepseek-chat",
messages:[{ role: "system", content: sys }, { role: "user", content: `题型:${type}\n题目:${question}\n${options ? '选项:\n' + options : ''}` }],
temperature: 0.1
}),
onload: (res) => {
try {
let content = JSON.parse(res.responseText).choices[0].message.content.trim();
let match = content.match(/\[(.*?)\]/);
if (match) {
resolve(match[1]);
} else {
resolve(content);
}
} catch { resolve(null); }
},
onerror: () => resolve(null)
});
});
}
async function startSolve() {
let sheetItems = document.querySelectorAll('.questionLi, .TiMu');
const total = sheetItems.length;
if (total === 0) {
alert("未找到题目!");
isRunning = false;
startBtn.style.display = 'inline-block';
pauseBtn.style.display = 'none';
return;
}
for (; currentIdx < total; currentIdx++) {
while (isPaused) { await sleep(300); }
const percent = Math.floor(((currentIdx + 1) / total) * 100);
progressBar.style.width = `${percent}%`;
progressText.innerText = `${currentIdx + 1} / ${total} (${percent}%)`;
const q = sheetItems[currentIdx];
q.scrollIntoView({ behavior: 'smooth', block: 'center' });
await sleep(300);
const titleEl = q.querySelector('h3.mark_name, div.mark_name, .Zy_TItle .clearfix');
let typeText = titleEl ? titleEl.innerText : "";
let type = typeText.includes('多选') ? "多选题" : typeText.includes('单选') ? "单选题" : typeText.includes('判断') ? "判断题" : typeText.includes('填空') ? "填空题" : "未知";
const questionText = typeText.replace(/【.*?】/, '').replace(/\s+/g, ' ').trim();
statusLabel.innerText = `答题中: 第 ${currentIdx + 1} 题...`;
if (type.includes("填空") || type.includes("简答")) {
const response = await getAIResponse(questionText, null, type);
if (response) {
const answers = type.includes("填空") ? response.split('###') : [response];
let fillIndex = 0;
// 【核心保留】:保留 V6 的强力富文本注入代码
if (window.unsafeWindow && window.unsafeWindow.UE && window.unsafeWindow.UE.instants) {
for (let key in window.unsafeWindow.UE.instants) {
let ue = window.unsafeWindow.UE.instants[key];
if (q.contains(ue.container) && fillIndex < answers.length) {
let ansText = answers[fillIndex] ? answers[fillIndex].trim() : "";
try {
ue.ready(() => { ue.setContent(ansText); });
} catch(e) {}
fillIndex++;
}
}
}
if (fillIndex === 0) {
const textareas = q.querySelectorAll('textarea');
for(let i=0; i opt.innerText.trim()).join('\n');
const result = await getAIResponse(questionText, opts, type);
if (result) {
const resUpper = result.toUpperCase();
optionElements.forEach(opt => {
const letterEl = opt.querySelector('[class*="num_option"], i.fl');
const letter = letterEl ? letterEl.innerText.trim().toUpperCase() : opt.innerText.trim().charAt(0).toUpperCase();
let shouldClick = false;
if (letter && resUpper.includes(letter)) shouldClick = true;
else if ((resUpper.includes("正确") || resUpper === "A" || resUpper === "√" || resUpper === "对") && (opt.innerText.includes("正确") || opt.innerText.includes("√") || opt.innerText.includes("对"))) shouldClick = true;
else if ((resUpper.includes("错误") || resUpper === "B" || resUpper === "×" || resUpper === "错") && (opt.innerText.includes("错误") || opt.innerText.includes("×") || opt.innerText.includes("错"))) shouldClick = true;
if (shouldClick) {
const isChecked = opt.getAttribute('aria-checked') === 'true' || opt.querySelector('input:checked');
if (!isChecked) {
const clickTarget = opt.querySelector('label, input') || opt;
clickTarget.click();
}
}
});
}
}
statusLabel.innerText = `第 ${currentIdx + 1} 题完成...`;
await sleep(DELAY + Math.random() * 300);
}
isRunning = false;
statusLabel.innerText = "全部作答完成";
pauseBtn.style.display = 'none';
startBtn.style.display = 'inline-block';
startBtn.innerText = '重新开始';
alert("作答完毕!");
}
setInterval(() => {
if (!uiCreated && document.querySelectorAll('.questionLi, .TiMu').length > 0) {
createUI();
}
}, 1000);
})();