// ==UserScript==
// @name 特种考试自动答题脚本-中安云教育
// @namespace http://tampermonkey.net/
// @version 5.2.0
// @description 特种考试自动答题脚本-中安云教育 | ⚠️ 此脚本仅供学习交流使用,请勿用于违规用途
// @author You
// @match https://txsyaqpx.zhongancloud.com/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_xmlhttpRequest
// @grant GM_info
// @grant GM_notification
// @grant unsafeWindow
// @require https://lib.baomitu.com/jquery/3.6.0/jquery.min.js
// @run-at document-start
// ==/UserScript==
// ========== 验证码验证模块 ==========
(function() {
'use strict';
const VERIFY_API = 'https://qsy.iano.cn/index.php?s=/api/code/verify';
const STORAGE_KEY = 'zhongan_exam_valid_until';
const VERIFY_DATE_KEY = 'zhongan_exam_verify_date';
const SESSION_KEY = 'zhongan_exam_session';
const QRCODE_IMG = 'https://qsy.iano.cn/yzm.png';
// 域名验证
if (!window.location.hostname.includes('zhongancloud.com')) {
console.error('❌ 脚本仅在中安云教育平台使用');
return;
}
// 获取今天的日期字符串 YYYY-MM-DD
function getTodayStr() {
const d = new Date();
return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0');
}
// 检查是否已验证
function isVerified() {
// 检查是否是同一会话(浏览器未关闭)
if (sessionStorage.getItem(SESSION_KEY)) {
// 同一会话内,检查24小时有效期
const validUntil = GM_getValue(STORAGE_KEY, 0);
if (validUntil > Date.now() / 1000) {
return true;
}
}
// 新会话(浏览器已关闭重新打开):检查是否跨天
const verifyDate = GM_getValue(VERIFY_DATE_KEY, '');
const today = getTodayStr();
if (verifyDate === today) {
// 同一天,标记会话并允许使用
sessionStorage.setItem(SESSION_KEY, '1');
return true;
}
// 跨天了,需要重新验证
return false;
}
// 显示验证弹窗
function showVerifyDialog() {
const overlay = document.createElement('div');
overlay.id = '_verify_overlay';
overlay.innerHTML = `
🔐 验证码验证
扫码观看广告获取验证码
验证后免费使用24小时
`;
(document.body || document.documentElement).appendChild(overlay);
const input = document.getElementById('_verify_code');
const btn = document.getElementById('_verify_submit');
const errorEl = document.getElementById('_verify_error');
btn.onclick = function() {
const code = input.value.trim();
if (!/^\d{4}$/.test(code)) {
errorEl.textContent = '请输入4位验证码';
errorEl.style.display = 'block';
errorEl.classList.remove('shake');
void errorEl.offsetWidth;
errorEl.classList.add('shake');
return;
}
btn.disabled = true;
btn.textContent = '验证中...';
errorEl.style.display = 'none';
GM_xmlhttpRequest({
method: 'POST',
url: VERIFY_API,
timeout: 10000,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: 'code=' + encodeURIComponent(code),
onload: function(res) {
try {
const data = JSON.parse(res.responseText);
if (data.code === 1 && data.data.valid) {
GM_setValue(STORAGE_KEY, data.data.valid_until);
GM_setValue(VERIFY_DATE_KEY, getTodayStr());
sessionStorage.setItem(SESSION_KEY, '1');
overlay.remove();
GM_notification({ text: '验证成功!24小时内免费使用', title: '自动答题助手', timeout: 3000 });
location.reload();
} else {
errorEl.textContent = data.msg || '验证码无效或已过期';
errorEl.style.display = 'block';
errorEl.classList.remove('shake');
void errorEl.offsetWidth;
errorEl.classList.add('shake');
btn.disabled = false;
btn.textContent = '立即验证';
}
} catch(e) {
errorEl.textContent = '验证失败,请重试';
errorEl.style.display = 'block';
errorEl.classList.remove('shake');
void errorEl.offsetWidth;
errorEl.classList.add('shake');
btn.disabled = false;
btn.textContent = '立即验证';
}
},
onerror: function() {
errorEl.textContent = '网络错误,请重试';
errorEl.style.display = 'block';
errorEl.classList.remove('shake');
void errorEl.offsetWidth;
errorEl.classList.add('shake');
btn.disabled = false;
btn.textContent = '立即验证';
}
});
};
input.onkeypress = function(e) { if (e.key === 'Enter') btn.click(); };
setTimeout(() => input.focus(), 300);
}
// 主逻辑:检查验证状态
if (!isVerified()) {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', showVerifyDialog);
} else {
showVerifyDialog();
}
return; // 未验证则阻止脚本继续执行
}
})();
// ========== 验证码验证模块结束 ==========
(function() {
'use strict';
// 全局配置
const CONFIG = {
delay: 1500, // 优化:默认延时从2000ms减少到1500ms
stop: true,
minDelay: 800, // 优化:最小延时从1000ms减少到800ms
autoSubmit: false, // 自动提交试卷
// 设备类型检测
isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),
isTablet: /iPad|Android.*(?=.*\b\d+X\d+\b)/i.test(navigator.userAgent) ||
(navigator.userAgent.includes('Android') && !navigator.userAgent.includes('Mobile')),
// 智谱AI配置(密钥已加密)
ZHIPU_CONFIG: {
// 加密的API密钥(Base64编码)
_key: 'ZjkwNTNkZTc1NmUwNDFmNWEzNjEzZjMzY2YyMmY4NzguaEhXMjRNUkRITGdQTHE3SQ==',
application_id: '1975919497449705472', // 智能体ID
knowledge_base_id: '1975919768523378688', // 知识库ID
base_url: 'https://open.bigmodel.cn/api/llm-application/open',
// 解密函数
get api_key() {
// 域名验证
if (!window.location.hostname.includes('zhongancloud.com')) {
console.error('❌ 域名验证失败');
return '';
}
// Base64解码
try {
return atob(this._key);
} catch(e) {
console.error('❌ 密钥解密失败');
return '';
}
}
}
};
let logContainer;
let stats = {
total: 0,
processed: 0,
success: 0,
failed: 0,
knowledgeHits: 0,
aiBackup: 0
};
// 答题进度管理
let progressManager = {
storageKey: 'exam_progress_' + window.location.pathname,
// 保存进度
saveProgress: function(currentIndex, totalQuestions) {
const progress = {
currentIndex: currentIndex,
totalQuestions: totalQuestions,
timestamp: Date.now(),
url: window.location.href,
stats: {...stats}
};
GM_setValue(this.storageKey, JSON.stringify(progress));
log(`💾 已保存答题进度: ${currentIndex + 1}/${totalQuestions}`);
},
// 获取保存的进度
getProgress: function() {
try {
const saved = GM_getValue(this.storageKey, null);
if (saved) {
const progress = JSON.parse(saved);
// 检查进度是否过期(24小时)
if (Date.now() - progress.timestamp < 24 * 60 * 60 * 1000) {
return progress;
}
}
} catch (e) {
log(`⚠️ 读取进度失败: ${e.message}`);
}
return null;
},
// 清除进度
clearProgress: function() {
GM_setValue(this.storageKey, null);
log(`🗑️ 已清除答题进度`);
},
// 检查是否有可恢复的进度
hasProgress: function() {
const progress = this.getProgress();
return progress && progress.currentIndex > 0;
}
};
// 后台运行相关变量
let isRunning = false;
let keepAliveInterval = null;
let visibilityChangeCount = 0;
let lastActiveTime = Date.now();
let focusChangeTimeout = null;
// 防止后台暂停机制(平板优化版)
function setupBackgroundKeepAlive() {
const debounceTime = CONFIG.isTablet ? 3000 : 1000; // 平板设备使用更长的防抖时间
// 页面可见性变化监听
document.addEventListener('visibilitychange', function() {
visibilityChangeCount++;
log(`📱 页面可见性变化: ${document.hidden ? '隐藏' : '显示'} (第${visibilityChangeCount}次)`);
if (document.hidden) {
if (isRunning) {
log('🛡️ 页面进入后台,启动保活机制');
startKeepAlive();
}
} else {
if (keepAliveInterval) {
log('🛡️ 页面回到前台,停止保活机制');
clearInterval(keepAliveInterval);
keepAliveInterval = null;
}
lastActiveTime = Date.now();
}
});
// 窗口焦点变化监听(平板优化防抖)
window.addEventListener('blur', function() {
if (focusChangeTimeout) {
clearTimeout(focusChangeTimeout);
}
focusChangeTimeout = setTimeout(() => {
if (isRunning && !keepAliveInterval) {
log('🛡️ 窗口失去焦点,启动保活机制');
startKeepAlive();
}
}, debounceTime); // 平板使用更长的防抖时间
});
window.addEventListener('focus', function() {
if (focusChangeTimeout) {
clearTimeout(focusChangeTimeout);
focusChangeTimeout = null;
}
if (keepAliveInterval) {
log('🛡️ 窗口获得焦点,停止保活机制');
clearInterval(keepAliveInterval);
keepAliveInterval = null;
}
lastActiveTime = Date.now();
});
// 移动设备特殊事件监听
if (CONFIG.isMobile || CONFIG.isTablet) {
// 监听触摸事件
['touchstart', 'touchmove', 'touchend'].forEach(event => {
document.addEventListener(event, function() {
lastActiveTime = Date.now();
}, { passive: true });
});
// 监听方向变化
window.addEventListener('orientationchange', function() {
log('📱 屏幕方向发生变化,重置活跃时间');
lastActiveTime = Date.now();
// 延迟重启保活机制,给设备时间适应
setTimeout(() => {
if (isRunning && document.hidden) {
startKeepAlive();
}
}, 2000);
});
}
}
// 启动保活机制(平板优化版)
function startKeepAlive() {
if (keepAliveInterval) {
return;
}
const keepAliveDelay = CONFIG.isTablet ? 2000 : 3000; // 平板使用更频繁的保活
keepAliveInterval = setInterval(() => {
// 执行轻量级操作保持页面活跃
lastActiveTime = Date.now();
// 模拟用户活动
try {
// 移动设备优先使用触摸事件
if (CONFIG.isMobile || CONFIG.isTablet) {
const touchEvent = new TouchEvent('touchstart', {
bubbles: true,
cancelable: true,
touches: []
});
document.dispatchEvent(touchEvent);
} else {
const event = new Event('mousemove', { bubbles: true });
document.dispatchEvent(event);
}
// 触发一个轻量级的DOM操作
const dummy = document.createElement('div');
dummy.style.display = 'none';
document.body.appendChild(dummy);
document.body.removeChild(dummy);
// 平板设备额外的保活操作
if (CONFIG.isTablet) {
// 轻微滚动页面
const currentScroll = window.pageYOffset;
window.scrollTo(0, currentScroll + 1);
window.scrollTo(0, currentScroll);
}
} catch (e) {
// 忽略错误,但记录日志
log(`⚠️ 保活操作出错: ${e.message}`);
}
// 更新页面标题显示运行状态
if (isRunning) {
const now = new Date();
const timeStr = `${now.getHours()}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;
const deviceType = CONFIG.isTablet ? '📱' : '🤖';
document.title = `${deviceType} 后台答题中... ${timeStr}`;
}
if (Date.now() - lastActiveTime > 30000) {
lastActiveTime = Date.now();
}
}, keepAliveDelay);
log(`🛡️ 保活机制已启动 (间隔: ${keepAliveDelay}ms, 设备: ${CONFIG.isTablet ? '平板' : '桌面'})`);
}
// 停止保活机制
function stopKeepAlive() {
if (keepAliveInterval) {
clearInterval(keepAliveInterval);
keepAliveInterval = null;
}
// 恢复原始标题
document.title = document.title.replace(/🤖 后台答题中.*/, '').trim() || '中安云教育';
}
// 后台稳定延时函数(平板优化版)
function backgroundSafeDelay(ms) {
return new Promise(resolve => {
const startTime = Date.now();
const minCheckInterval = CONFIG.isTablet ? 200 : 100; // 平板使用更稳定的检查间隔
log(`⏱️ 开始延时 ${ms}ms (设备: ${CONFIG.isTablet ? '平板' : '桌面'})`);
const checkDelay = () => {
const elapsed = Date.now() - startTime;
if (elapsed >= ms) {
log(`✅ 延时完成,实际用时: ${elapsed}ms`);
resolve();
} else {
const remaining = ms - elapsed;
const nextCheck = Math.min(minCheckInterval, remaining);
// 平板设备在后台时使用更可靠的延时策略
if (document.hidden || CONFIG.isTablet) {
// 后台或平板设备优先使用setTimeout
setTimeout(checkDelay, nextCheck);
} else {
// 前台桌面设备使用requestAnimationFrame
if (remaining > 16) { // 超过一帧的时间才使用RAF
requestAnimationFrame(checkDelay);
} else {
setTimeout(checkDelay, nextCheck);
}
}
}
};
// 移动设备立即启动,避免RAF的延迟
if (CONFIG.isMobile || CONFIG.isTablet) {
setTimeout(checkDelay, 0);
} else {
checkDelay();
}
});
}
// 日志函数
function log(message) {
const time = new Date().toLocaleTimeString();
const logMessage = `[${time}] ${message}`;
console.log(logMessage);
if (logContainer) {
// 创建新的日志条目
const logEntry = document.createElement('div');
logEntry.style.cssText = 'margin-bottom: 5px; word-wrap: break-word; white-space: pre-wrap; line-height: 1.7; padding: 3px 0; font-size: 12px; min-height: 20px;';
logEntry.textContent = logMessage;
logContainer.appendChild(logEntry);
// 限制日志条目数量,避免过多影响性能
const maxLogs = 200;
while (logContainer.children.length > maxLogs) {
logContainer.removeChild(logContainer.firstChild);
}
// 强制滚动到底部,确保新内容可见
requestAnimationFrame(() => {
logContainer.scrollTop = logContainer.scrollHeight;
// 双重确保滚动到底部
setTimeout(() => {
logContainer.scrollTop = logContainer.scrollHeight;
}, 50);
});
}
}
// 网络状态检测
function isNetworkAvailable() {
return navigator.onLine;
}
// 网络重试机制(平板优化版)
async function retryApiCall(apiFunction, maxRetries = null) {
// 平板设备使用更多重试次数和更长超时
if (maxRetries === null) {
maxRetries = CONFIG.isTablet ? 4 : 2;
}
for (let i = 0; i <= maxRetries; i++) {
try {
if (!isNetworkAvailable()) {
log(`🌐 网络不可用,等待恢复... (第${i + 1}次重试)`);
await backgroundSafeDelay(3000);
continue;
}
log(`🔄 API调用 (第${i + 1}次尝试)`);
return await apiFunction();
} catch (error) {
log(`❌ API调用失败 (第${i + 1}次): ${error.message}`);
if (i === maxRetries) {
throw error;
}
const isTimeout = error.message.includes('timeout') || error.message.includes('超时');
const isNetworkError = error.message.includes('网络') || error.message.includes('network');
// 平板设备使用更长的重试延迟
let retryDelay;
if (isTimeout || isNetworkError) {
retryDelay = CONFIG.isTablet ? 3000 * (i + 1) : 2000 * (i + 1);
} else {
retryDelay = CONFIG.isTablet ? 2000 * (i + 1) : 1000 * (i + 1);
}
log(`⏳ ${retryDelay}ms后重试...`);
await backgroundSafeDelay(retryDelay);
}
}
}
// 调用智谱应用API(使用v3接口 + 新密钥)
async function callKnowledgeBaseAPI(question, options) {
const query = `请回答这道低压电工题目,严格按照格式返回:
题目:${question}
选项:
${options.map((opt, i) => `${String.fromCharCode(65 + i)}. ${opt}`).join('\n')}
要求:
1. 基于低压电工专业知识选择正确答案
2. 严格按照格式:选项字母,选项原文
3. 选项原文必须与上面选项完全一致
4. 不要添加解释或额外内容
格式示例:A,正确 或 B,错误 或 C,竖放
答案:`;
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: 'POST',
url: `${CONFIG.ZHIPU_CONFIG.base_url}/v3/application/invoke`,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${CONFIG.ZHIPU_CONFIG.api_key}`
},
data: JSON.stringify({
app_id: CONFIG.ZHIPU_CONFIG.application_id,
stream: false,
messages: [
{
role: "user",
content: [
{
type: "input",
value: query
}
]
}
]
}),
timeout: CONFIG.isTablet ? 20000 : 12000, // 优化:减少超时时间以加快失败重试
onload: function(response) {
try {
if (response.status !== 200) {
reject(new Error(`知识库API错误: ${response.status}`));
return;
}
const result = JSON.parse(response.responseText);
if (result.choices && result.choices[0] && result.choices[0].messages) {
const messages = result.choices[0].messages;
const content = messages.content;
if (content && content.type === "text" && content.msg) {
const answer = content.msg.trim();
stats.knowledgeHits++;
resolve(answer);
} else {
reject(new Error('智能体响应内容格式错误'));
}
} else {
reject(new Error(result.message || '智能体API调用失败'));
}
} catch (e) {
reject(new Error('知识库响应解析失败: ' + e.message));
}
},
onerror: function(error) {
reject(new Error('知识库网络请求失败'));
}
});
});
}
// 备用AI调用(使用v4标准API)
async function callBackupAI(question, options) {
const prompt = `请回答这道${options.length === 2 ? '判断' : '选择'}题,严格按照格式返回:
题目:${question}
选项:
${options.map((opt, i) => `${String.fromCharCode(65 + i)}. ${opt}`).join('\n')}
要求:
1. 选择正确答案
2. 格式:选项字母,选项原文
3. 选项原文必须与上面选项完全一致
4. 不要解释
答案:`;
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: 'POST',
url: 'https://open.bigmodel.cn/api/paas/v4/chat/completions',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${CONFIG.ZHIPU_CONFIG.api_key}`
},
data: JSON.stringify({
model: 'glm-4-flash',
messages: [
{
role: "system",
content: "你是专业的低压电工,只回答选项字母和内容,不要解释。"
},
{
role: "user",
content: prompt
}
],
temperature: 0.3,
max_tokens: 50
}),
timeout: CONFIG.isTablet ? 20000 : 12000,
onload: function(response) {
try {
const result = JSON.parse(response.responseText);
if (result.choices && result.choices[0] && result.choices[0].message) {
const answer = result.choices[0].message.content.trim();
stats.aiBackup++;
resolve(answer);
} else if (result.error) {
reject(new Error(result.error.message || '备用AI响应错误'));
} else {
reject(new Error('备用AI响应格式错误'));
}
} catch (e) {
reject(new Error('备用AI解析失败: ' + e.message));
}
},
onerror: () => reject(new Error('备用AI网络错误'))
});
});
}
// 智能获取答案
async function getSmartAnswer(question, options) {
try {
const knowledgeAnswer = await retryApiCall(() => callKnowledgeBaseAPI(question, options));
return knowledgeAnswer;
} catch (error) {
try {
const aiAnswer = await retryApiCall(() => callBackupAI(question, options));
return aiAnswer;
} catch (aiError) {
throw new Error('所有答案获取方式都失败');
}
}
}
// 更新时间预估
function updateTimeEstimate() {
const delayInput = document.getElementById('delayInput');
const timeEstimate = document.getElementById('timeEstimate');
if (delayInput && timeEstimate) {
const delaySeconds = parseInt(delayInput.value) || 3;
const containers = document.querySelectorAll('.ques-type-item');
let questionCount = containers.length;
// 如果还没检测到题目,使用默认值并标注
let isEstimated = false;
if (questionCount === 0) {
questionCount = 100;
isEstimated = true;
}
// 计算总时间(延时 + 处理时间)
const processingTimePerQuestion = 1.2; // 每题处理时间约1.2秒(优化后)
const totalTimePerQuestion = delaySeconds + processingTimePerQuestion;
const totalSeconds = questionCount * totalTimePerQuestion;
const minutes = Math.floor(totalSeconds / 60);
const seconds = totalSeconds % 60;
let timeText = '';
if (minutes > 0) {
timeText = `${minutes}分${seconds}秒`;
} else {
timeText = `${totalSeconds}秒`;
}
const estimateText = isEstimated ?
`预计完成时间: ${timeText} (预估${questionCount}题)` :
`预计完成时间: ${timeText} (${questionCount}题)`;
timeEstimate.textContent = estimateText;
timeEstimate.style.color = isEstimated ? '#a0aec0' : '#718096';
}
}
// 更新继续答题按钮状态
function updateResumeButton() {
const resumeBtn = document.getElementById('resumeBtn');
if (!resumeBtn) return;
const hasProgress = progressManager.hasProgress();
const containers = document.querySelectorAll('.ques-type-item');
const { answeredCount } = detectAnsweredQuestions(containers);
if (hasProgress || answeredCount > 0) {
resumeBtn.style.display = 'block';
if (hasProgress) {
const progress = progressManager.getProgress();
const savedTime = new Date(progress.timestamp).toLocaleTimeString();
resumeBtn.innerHTML = `🔄 继续答题 (第${progress.currentIndex + 1}题 ${savedTime})`;
resumeBtn.title = `恢复到第${progress.currentIndex + 1}题继续答题`;
} else if (answeredCount > 0) {
resumeBtn.innerHTML = `🔄 继续答题 (已答${answeredCount}题)`;
resumeBtn.title = `跳过已答的${answeredCount}题,继续答题`;
}
} else {
resumeBtn.style.display = 'none';
}
}
// 设置全局函数(在面板创建前)
function setupGlobalFunctions() {
window.updateTimeEstimate = updateTimeEstimate;
window.updateResumeButton = updateResumeButton;
}
// 自动提交试卷
async function autoSubmitExam() {
try {
const submitSelectors = [
'button[type="submit"]',
'.submit-btn',
'.btn-submit',
'input[type="submit"]',
'.exam-submit',
'#submitBtn',
'.btn-primary',
'.submit-button',
'button[style*="background-color: rgb(24, 144, 255)"]',
'button[style*="background: rgb(24, 144, 255)"]',
'.ant-btn-primary',
'[class*="submit"]',
'[class*="primary"]'
];
let submitBtn = null;
for (const selector of submitSelectors) {
try {
submitBtn = document.querySelector(selector);
if (submitBtn) {
break;
}
} catch (e) {
continue;
}
}
if (!submitBtn) {
const buttons = document.querySelectorAll('button, input[type="button"], a, .btn, [role="button"], div[role="button"]');
for (const btn of buttons) {
const text = (btn.textContent || btn.value || btn.innerText || '').trim();
if (text === '提交试卷' || text === '提交答案' || text === '提交考试') {
submitBtn = btn;
break;
}
if (text.includes('提交') || text.includes('完成') || text.includes('结束') ||
text.includes('交卷') || text.includes('确认') || text.includes('保存') ||
text.includes('submit') || text.includes('finish') || text.includes('complete')) {
submitBtn = btn;
break;
}
}
}
if (!submitBtn) {
const blueButtons = document.querySelectorAll('button, .btn, [style*="background"], [class*="primary"], [class*="blue"]');
for (const btn of blueButtons) {
const rect = btn.getBoundingClientRect();
const isRightSide = rect.right > window.innerWidth * 0.7;
const isBottomSide = rect.bottom > window.innerHeight * 0.7;
if (isRightSide && isBottomSide) {
const text = (btn.textContent || btn.value || '').trim();
if (text.length > 0) {
submitBtn = btn;
break;
}
}
}
}
if (submitBtn) {
await new Promise(resolve => setTimeout(resolve, 2000));
submitBtn.click();
log('🎉 试卷已自动提交');
return true;
} else {
return false;
}
} catch (error) {
return false;
}
}
// 解析答案(增强版)- 返回详细信息
function parseAnswer(answer, options = []) {
const cleanAnswer = answer.trim();
// 1. 解析"字母,内容"格式(最优先)
const commaMatch = cleanAnswer.match(/^([A-D])[,,]\s*(.+)$/i);
if (commaMatch) {
const letter = commaMatch[1].toUpperCase();
const content = commaMatch[2].trim();
// 通过内容匹配找到正确的选项索引
let bestMatch = null;
let bestScore = 0;
for (let i = 0; i < options.length; i++) {
const option = options[i].trim();
let score = 0;
// 完全匹配(最高优先级)
if (option === content) {
score = 1.0;
}
// 选项包含AI内容
else if (option.includes(content)) {
score = 0.9;
}
// AI内容包含选项
else if (content.includes(option)) {
score = 0.8;
}
// 相似度匹配
else {
score = parseAnswer.contentSimilarity(option, content);
}
if (score > bestScore && score > 0.6) {
bestScore = score;
bestMatch = {
letter: String.fromCharCode(65 + i),
index: i,
content: option,
source: 'format_content_match',
aiLetter: letter,
aiContent: content,
matchScore: score
};
}
}
if (bestMatch) {
return bestMatch;
}
// 如果内容匹配失败,尝试使用AI提供的字母(但要验证)
const aiIndex = letter.charCodeAt(0) - 65;
if (aiIndex >= 0 && aiIndex < options.length) {
const result = {
letter: letter,
index: aiIndex,
content: options[aiIndex],
source: 'format_letter_fallback',
aiContent: content
};
return result;
}
}
// 2. 直接匹配单个字母
const upperAnswer = cleanAnswer.toUpperCase();
if (/^[A-Z]$/.test(upperAnswer)) {
const index = upperAnswer.charCodeAt(0) - 65;
if (index >= 0 && index < options.length) {
const result = {
letter: upperAnswer,
index: index,
content: options[index],
source: 'direct_letter'
};
return result;
}
}
// 3. 提取第一个字母
const letterMatch = upperAnswer.match(/[A-Z]/);
if (letterMatch) {
const letter = letterMatch[0];
const index = letter.charCodeAt(0) - 65;
if (index >= 0 && index < options.length) {
const result = {
letter: letter,
index: index,
content: options[index],
source: 'extract_letter'
};
return result;
}
}
// 4. 判断题关键词匹配
if (upperAnswer.includes('正确') || upperAnswer.includes('对') || upperAnswer.includes('TRUE')) {
// 找到包含"正确"的选项
for (let i = 0; i < options.length; i++) {
if (options[i].includes('正确') || options[i].includes('对')) {
const result = {
letter: String.fromCharCode(65 + i),
index: i,
content: options[i],
source: 'keyword_correct'
};
return result;
}
}
} else if (upperAnswer.includes('错误') || upperAnswer.includes('错') || upperAnswer.includes('FALSE')) {
// 找到包含"错误"的选项
for (let i = 0; i < options.length; i++) {
if (options[i].includes('错误') || options[i].includes('错')) {
const result = {
letter: String.fromCharCode(65 + i),
index: i,
content: options[i],
source: 'keyword_wrong'
};
return result;
}
}
}
// 5. 选项内容关键词匹配
if (options.length > 0) {
for (let i = 0; i < options.length; i++) {
const option = options[i].trim();
const optionWords = option.split(/[\s,。、]/);
for (const word of optionWords) {
if (word.length >= 2 && upperAnswer.includes(word.toUpperCase())) {
const letter = String.fromCharCode(65 + i);
const result = {
letter: letter,
index: i,
content: option,
source: 'content_match'
};
return result;
}
}
}
}
return null;
}
// 内容相似度计算(简单版)
parseAnswer.contentSimilarity = function(str1, str2) {
const s1 = str1.toLowerCase().replace(/[^\w\u4e00-\u9fff]/g, '');
const s2 = str2.toLowerCase().replace(/[^\w\u4e00-\u9fff]/g, '');
if (s1 === s2) return 1;
if (s1.includes(s2) || s2.includes(s1)) return 0.8;
// 简单的字符重叠度计算
let overlap = 0;
const minLen = Math.min(s1.length, s2.length);
for (let i = 0; i < minLen; i++) {
if (s1[i] === s2[i]) overlap++;
}
return overlap / Math.max(s1.length, s2.length);
};
// 处理单个题目
async function processQuestion(container, index) {
try {
log(`📝 开始处理第${index + 1}题`);
const questionEl = container.querySelector('.question-name .content p');
if (!questionEl) {
log(`❌ 第${index + 1}题: 无法找到题目元素`);
return false;
}
const question = questionEl.textContent.trim();
const optionGroups = container.querySelectorAll('.option-group');
const options = [];
optionGroups.forEach(group => {
const content = group.querySelector('.option-content p');
if (content) {
const text = content.textContent.trim();
if (text && !options.includes(text)) {
options.push(text);
}
}
});
if (options.length === 0) {
log(`❌ 第${index + 1}题: 无法找到选项`);
return false;
}
log(`🤔 第${index + 1}题: ${question.substring(0, 30)}... (${options.length}个选项)`);
const answer = await getSmartAnswer(question, options);
log(`🤖 第${index + 1}题: AI回答 "${answer}"`);
const parseResult = parseAnswer(answer, options);
if (parseResult && parseResult.index >= 0 && parseResult.index < optionGroups.length) {
log(`✅ 第${index + 1}题: 选择${parseResult.letter}选项 "${parseResult.content}" (匹配方式: ${parseResult.source})`);
const targetGroup = optionGroups[parseResult.index];
const radioInput = targetGroup.querySelector('input[type="radio"]');
if (radioInput) {
radioInput.checked = true;
radioInput.dispatchEvent(new Event('change', { bubbles: true }));
targetGroup.click();
stats.success++;
log(`✅ 第${index + 1}题: 已成功选中答案`);
return true;
} else {
log(`❌ 第${index + 1}题: 找不到单选按钮`);
}
} else {
log(`❌ 第${index + 1}题: 无法解析答案 "${answer}"`);
}
stats.failed++;
return false;
} catch (error) {
log(`❌ 第${index + 1}题: 处理出错 - ${error.message}`);
stats.failed++;
return false;
} finally {
stats.processed++;
}
}
// 显示打赏弹窗
function showDonateModal() {
// 创建遮罩层
const overlay = document.createElement('div');
overlay.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 20000;
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(5px);
`;
// 创建弹窗
const modal = document.createElement('div');
modal.style.cssText = `
background: #f0f2f5;
border-radius: 20px;
padding: 30px;
max-width: 400px;
text-align: center;
box-shadow:
20px 20px 40px rgba(0,0,0,0.2),
-20px -20px 40px rgba(255,255,255,0.9);
position: relative;
`;
modal.innerHTML = `
❤️
感谢支持
如果脚本对您有帮助,请考虑打赏支持作者
`;
overlay.className = 'donate-overlay';
overlay.appendChild(modal);
document.body.appendChild(overlay);
// 绑定按钮事件
setTimeout(() => {
const closeBtn = document.getElementById('closeModalBtn');
const contactBtn = document.getElementById('contactBtn');
if (closeBtn) {
closeBtn.onclick = () => overlay.remove();
}
if (contactBtn) {
contactBtn.onclick = () => copyWechatId(contactBtn);
}
}, 100);
// 点击遮罩关闭
overlay.onclick = (e) => {
if (e.target === overlay) {
overlay.remove();
}
};
}
// 全局函数已在setupGlobalFunctions中设置
// 检测已答题目
function detectAnsweredQuestions(containers) {
let answeredCount = 0;
const answeredQuestions = [];
containers.forEach((container, index) => {
const radioInputs = container.querySelectorAll('input[type="radio"]');
let isAnswered = false;
radioInputs.forEach(radio => {
if (radio.checked) {
isAnswered = true;
}
});
if (isAnswered) {
answeredCount++;
answeredQuestions.push(index);
}
});
return { answeredCount, answeredQuestions };
}
// 开始答题
function startAnswering(resumeFromIndex = 0) {
if (!CONFIG.stop) return;
CONFIG.stop = false;
isRunning = true; // 设置运行状态
// 如果是继续答题,保留之前的统计数据
if (resumeFromIndex === 0) {
stats = { total: 0, processed: 0, success: 0, failed: 0, knowledgeHits: 0, aiBackup: 0 };
}
// 获取延时和自动提交设置
const delaySeconds = parseInt(document.getElementById('delayInput')?.value || 3);
const delay = delaySeconds * 1000; // 转换为毫秒
CONFIG.autoSubmit = document.getElementById('autoSubmitCheck')?.checked || false;
const containers = document.querySelectorAll('.ques-type-item');
stats.total = containers.length;
// 检测已答题目
const { answeredCount, answeredQuestions } = detectAnsweredQuestions(containers);
if (resumeFromIndex === 0) {
log('🚀 开始AI智能答题');
} else {
log(`🔄 继续答题 (从第${resumeFromIndex + 1}题开始)`);
}
log(`⚠️ 此脚本仅供学习交流使用`);
log(`📱 设备类型: ${CONFIG.isTablet ? '平板设备' : CONFIG.isMobile ? '手机设备' : '桌面设备'}`);
log(`📚 使用知识库: ${CONFIG.ZHIPU_CONFIG.knowledge_base_id}`);
log(`🤖 使用模型: ${CONFIG.ZHIPU_CONFIG.model}`);
log(`⏱️ 答题延时: ${delaySeconds}秒/题`);
log(`📋 自动提交: ${CONFIG.autoSubmit ? '已启用' : '已禁用'}`);
log(`📝 题目状态: 总计${containers.length}题, 已答${answeredCount}题, 剩余${containers.length - answeredCount}题`);
log('🛡️ 后台运行保护已激活 (平板优化)');
// 更新状态显示
const statusElement = document.getElementById('backgroundStatus');
if (statusElement) {
statusElement.textContent = document.hidden ? '🌙 后台运行中...' : '🚀 前台运行中...';
statusElement.style.color = '#38a169';
}
// 计算预计完成时间(包含处理时间)
const remainingQuestions = containers.length - Math.max(resumeFromIndex, answeredCount);
const processingTimePerQuestion = 1.2; // 每题处理时间约1.2秒(优化后)
const totalTimePerQuestion = delaySeconds + processingTimePerQuestion;
const totalSeconds = remainingQuestions * totalTimePerQuestion;
const minutes = Math.floor(totalSeconds / 60);
const remainingSeconds = Math.round(totalSeconds % 60);
const timeText = minutes > 0 ? `${minutes}分${remainingSeconds}秒` : `${totalSeconds}秒`;
log(`⏰ 预计剩余时间: ${timeText} (${remainingQuestions}题)`);
(async () => {
const startTime = Date.now();
let actualStartIndex = resumeFromIndex;
// 如果有已答题目,从最后一个已答题目的下一题开始
if (answeredCount > 0 && resumeFromIndex === 0) {
actualStartIndex = Math.max(...answeredQuestions) + 1;
log(`🔍 检测到已答题目,从第${actualStartIndex + 1}题开始`);
}
for (let i = actualStartIndex; i < containers.length && !CONFIG.stop; i++) {
// 检查当前题目是否已经答过
const radioInputs = containers[i].querySelectorAll('input[type="radio"]');
let isAlreadyAnswered = false;
radioInputs.forEach(radio => {
if (radio.checked) {
isAlreadyAnswered = true;
}
});
if (isAlreadyAnswered) {
log(`⏭️ 第${i + 1}题已答,跳过`);
stats.processed++;
stats.success++;
continue;
}
await processQuestion(containers[i], i);
// 每5题保存一次进度
if ((i + 1) % 5 === 0) {
progressManager.saveProgress(i, containers.length);
}
const progress = Math.round((i + 1) / containers.length * 100);
const accuracy = stats.processed > 0 ? Math.round(stats.success / stats.processed * 100) : 0;
const knowledgeRate = stats.processed > 0 ? Math.round(stats.knowledgeHits / stats.processed * 100) : 0;
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
// 平板设备每10题显示一次详细进度
if (CONFIG.isTablet && (i + 1) % 10 === 0) {
log(`📊 平板进度报告: ${i + 1}/${containers.length} (${progress}%) | 准确率: ${accuracy}% | 用时: ${elapsed}s`);
}
if (i < containers.length - 1) {
await backgroundSafeDelay(delay);
}
}
const finalScore = Math.round(stats.success / stats.total * 100);
const knowledgeUsage = Math.round(stats.knowledgeHits / stats.processed * 100);
const totalTime = ((Date.now() - startTime) / 1000).toFixed(1);
log(`✅ 答题完成: ${stats.success}/${stats.total} (预估${finalScore}分)`);
// 清除进度记录
progressManager.clearProgress();
// 自动提交试卷
if (CONFIG.autoSubmit) {
log(`\n🎯 准备自动提交试卷...`);
await autoSubmitExam();
}
CONFIG.stop = true;
isRunning = false; // 设置停止状态
stopKeepAlive(); // 停止后台保活
})();
}
// 继续答题
function resumeAnswering() {
const progress = progressManager.getProgress();
if (progress) {
// 恢复统计数据
stats = {...progress.stats};
log(`🔄 恢复答题进度: 第${progress.currentIndex + 1}题 (${new Date(progress.timestamp).toLocaleString()})`);
startAnswering(progress.currentIndex + 1);
} else {
log('❌ 没有找到可恢复的进度,将从头开始');
startAnswering(0);
}
}
// 停止答题
function stopAnswering() {
CONFIG.stop = true;
isRunning = false; // 设置停止状态
stopKeepAlive(); // 停止后台保活
// 更新状态显示
const statusElement = document.getElementById('backgroundStatus');
if (statusElement) {
statusElement.textContent = '🛡️ 后台运行保护已就绪';
statusElement.style.color = '#4a5568';
}
log('⏹️ 停止答题');
}
// 创建控制面板
function createPanel() {
const panel = document.createElement('div');
panel.id = 'knowledgePanel';
panel.style.cssText = `
position: fixed;
top: 30px;
right: 20px;
width: 360px;
height: auto;
min-width: 300px;
min-height: 450px;
max-width: 600px;
max-height: 95vh;
background: #f0f2f5;
border: none;
border-radius: 20px;
box-shadow:
20px 20px 40px rgba(0,0,0,0.1),
-20px -20px 40px rgba(255,255,255,0.8),
inset 0 0 0 1px rgba(255,255,255,0.3);
z-index: 10000;
font-family: 'Microsoft YaHei', Arial, sans-serif;
transition: none;
backdrop-filter: blur(10px);
overflow-y: auto;
overflow-x: hidden;
`;
panel.innerHTML = `
完成后自动提交
💬 定制脚本联系微信:C919irt
${CONFIG.isTablet ? '📱 平板设备 (已优化)' : CONFIG.isMobile ? '📱 手机设备' : '🖥️ 桌面设备'}
${CONFIG.isTablet ? '保活间隔2s | 超时25s | 重试4次' : '标准配置'}
答题助手已就绪...
⚠️ 此脚本仅供学习交流使用
📱 设备: ${CONFIG.isTablet ? '平板设备 (已启用优化)' : CONFIG.isMobile ? '手机设备' : '桌面设备'}
🛡️ 后台保护: ${CONFIG.isTablet ? '平板专用保活机制' : '标准机制'}
💾 进度保存: 每5题自动保存,支持断点续答
`;
document.body.appendChild(panel);
logContainer = document.getElementById('logArea');
// 创建最小化悬浮窗
createFloatingPet();
// 绑定事件
setTimeout(() => {
const startBtn = document.getElementById('startBtn');
const stopBtn = document.getElementById('stopBtn');
const resumeBtn = document.getElementById('resumeBtn');
const minimizeBtn = document.getElementById('minimizeBtn');
const closeBtn = document.getElementById('closeBtn');
const autoSubmitCheck = document.getElementById('autoSubmitCheck');
const checkboxDisplay = document.getElementById('checkboxDisplay');
if (startBtn) startBtn.onclick = () => startAnswering(0);
if (stopBtn) stopBtn.onclick = stopAnswering;
if (resumeBtn) resumeBtn.onclick = resumeAnswering;
if (minimizeBtn) minimizeBtn.onclick = minimizePanel;
if (closeBtn) closeBtn.onclick = closePanel;
// 检查是否有可恢复的进度
updateResumeButton();
// 复选框交互
if (autoSubmitCheck && checkboxDisplay) {
const updateCheckbox = () => {
const isChecked = autoSubmitCheck.checked;
const indicator = checkboxDisplay.querySelector('div');
if (indicator) {
indicator.style.transform = isChecked ? 'scale(1)' : 'scale(0)';
}
checkboxDisplay.style.boxShadow = isChecked ?
'inset 6px 6px 12px rgba(0,0,0,0.15), inset -6px -6px 12px rgba(255,255,255,0.9)' :
'inset 4px 4px 8px rgba(0,0,0,0.1), inset -4px -4px 8px rgba(255,255,255,0.8)';
};
autoSubmitCheck.onchange = updateCheckbox;
checkboxDisplay.onclick = () => {
autoSubmitCheck.checked = !autoSubmitCheck.checked;
updateCheckbox();
};
// 初始状态
updateCheckbox();
}
// 拖拽功能
setupDragFunctionality();
// 初始化时间预估和继续按钮状态
setTimeout(() => {
updateTimeEstimate();
updateResumeButton();
setInterval(() => {
updateTimeEstimate();
updateResumeButton();
}, 2000);
}, 500);
}, 100);
// 实时更新统计
setInterval(() => {
const statsArea = document.getElementById('statsArea');
const pet = document.getElementById('floatingPet');
if (statsArea && stats.total > 0) {
const progress = Math.round((stats.processed / stats.total) * 100);
const accuracy = stats.processed > 0 ? Math.round((stats.success / stats.processed) * 100) : 0;
const knowledgeRate = stats.processed > 0 ? Math.round((stats.knowledgeHits / stats.processed) * 100) : 0;
const aiRate = stats.processed > 0 ? Math.round((stats.aiBackup / stats.processed) * 100) : 0;
statsArea.innerHTML = `
进度
${stats.processed}/${stats.total}
`;
// 同时更新悬浮宠物状态
if (pet && pet.style.display === 'flex') {
pet.className = ''; // 清除之前的状态类
if (CONFIG.stop === false && stats.processed > 0) {
// 答题进行中
pet.className = 'pet-working';
pet.innerHTML = `
`;
pet.title = `🚀 答题进行中: ${stats.processed}/${stats.total} (准确率${accuracy}%) - 点击展开面板`;
} else if (stats.processed > 0) {
// 答题完成
if (accuracy >= 90) {
pet.className = 'pet-success';
pet.innerHTML = `
`;
} else {
pet.className = 'pet-warning';
pet.innerHTML = `
`;
}
pet.title = `✅ 答题完成: ${accuracy}分 (${stats.success}/${stats.total}) - 点击展开面板`;
} else {
// 待机状态
pet.innerHTML = `
`;
pet.title = '🤖 自动答题助手 - 点击展开面板';
}
}
}
}, 1000);
}
// 创建悬浮小宠物
function createFloatingPet() {
const pet = document.createElement('div');
pet.id = 'floatingPet';
pet.style.cssText = `
position: fixed;
top: 50px;
right: 20px;
width: 75px;
height: 75px;
background: #f0f2f5;
border-radius: 50%;
box-shadow:
12px 12px 24px rgba(0,0,0,0.15),
-12px -12px 24px rgba(255,255,255,0.9);
z-index: 10001;
cursor: pointer;
display: none;
align-items: center;
justify-content: center;
font-size: 28px;
color: #4a5568;
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
user-select: none;
animation: petFloat 4s ease-in-out infinite;
border: none;
`;
pet.innerHTML = `
`;
pet.title = '自动答题助手 - 点击展开';
pet.onclick = restorePanel;
// 添加悬浮动画和样式
const style = document.createElement('style');
style.textContent = `
/* 强制显示滚动条样式 */
#logArea {
scrollbar-width: thin !important;
scrollbar-color: #a0aec0 #f0f2f5 !important;
overflow-y: scroll !important;
overflow-x: hidden !important;
}
#logArea::-webkit-scrollbar {
width: 12px !important;
height: 12px !important;
display: block !important;
}
#logArea::-webkit-scrollbar-track {
background: #e2e8f0 !important;
border-radius: 6px !important;
box-shadow: inset 3px 3px 6px rgba(0,0,0,0.1), inset -3px -3px 6px rgba(255,255,255,0.8) !important;
border: 1px solid #cbd5e0 !important;
}
#logArea::-webkit-scrollbar-thumb {
background: linear-gradient(135deg, #a0aec0, #718096) !important;
border-radius: 6px !important;
box-shadow: 2px 2px 4px rgba(0,0,0,0.2), -2px -2px 4px rgba(255,255,255,0.9) !important;
border: 2px solid #f0f2f5 !important;
min-height: 30px !important;
}
#logArea::-webkit-scrollbar-thumb:hover {
background: linear-gradient(135deg, #718096, #4a5568) !important;
box-shadow: inset 2px 2px 4px rgba(0,0,0,0.15), inset -2px -2px 4px rgba(255,255,255,0.9) !important;
}
#logArea::-webkit-scrollbar-thumb:active {
background: linear-gradient(135deg, #4a5568, #2d3748) !important;
box-shadow: inset 3px 3px 6px rgba(0,0,0,0.2), inset -3px -3px 6px rgba(255,255,255,0.8) !important;
}
#logArea::-webkit-scrollbar-corner {
background: #f0f2f5 !important;
}
@keyframes petFloat {
0%, 100% {
transform: translateY(0px) rotate(0deg);
box-shadow:
12px 12px 24px rgba(0,0,0,0.15),
-12px -12px 24px rgba(255,255,255,0.9);
}
25% {
transform: translateY(-6px) rotate(1deg);
box-shadow:
15px 15px 30px rgba(0,0,0,0.2),
-15px -15px 30px rgba(255,255,255,0.95);
}
50% {
transform: translateY(-10px) rotate(0deg);
box-shadow:
18px 18px 36px rgba(0,0,0,0.25),
-18px -18px 36px rgba(255,255,255,1);
}
75% {
transform: translateY(-6px) rotate(-1deg);
box-shadow:
15px 15px 30px rgba(0,0,0,0.2),
-15px -15px 30px rgba(255,255,255,0.95);
}
}
@keyframes petPulse {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
}
#floatingPet:hover {
transform: scale(1.1) translateY(-3px) !important;
box-shadow:
inset 6px 6px 12px rgba(0,0,0,0.1),
inset -6px -6px 12px rgba(255,255,255,0.8) !important;
animation: petPulse 1s ease-in-out infinite !important;
}
#floatingPet:active {
transform: scale(0.95) !important;
transition: all 0.1s ease !important;
box-shadow:
inset 8px 8px 16px rgba(0,0,0,0.15),
inset -8px -8px 16px rgba(255,255,255,0.9) !important;
}
/* 状态指示器样式 */
.pet-working {
background: #e6fffa !important;
color: #38a169 !important;
animation: petFloat 2s ease-in-out infinite, petPulse 1.5s ease-in-out infinite !important;
box-shadow:
12px 12px 24px rgba(56, 161, 105, 0.2),
-12px -12px 24px rgba(255,255,255,0.9) !important;
}
.pet-success {
background: #ebf8ff !important;
color: #3182ce !important;
box-shadow:
12px 12px 24px rgba(49, 130, 206, 0.2),
-12px -12px 24px rgba(255,255,255,0.9) !important;
}
.pet-warning {
background: #fffaf0 !important;
color: #ed8936 !important;
box-shadow:
12px 12px 24px rgba(237, 137, 54, 0.2),
-12px -12px 24px rgba(255,255,255,0.9) !important;
}
`;
document.head.appendChild(style);
document.body.appendChild(pet);
}
// 设置拖拽和调整大小功能
function setupDragFunctionality() {
const panel = document.getElementById('knowledgePanel');
const header = document.getElementById('panelHeader');
const pet = document.getElementById('floatingPet');
let isDragging = false;
let dragOffset = { x: 0, y: 0 };
// 移除调整大小控制点(用户要求取消)
// addResizeHandles(panel);
// 面板拖拽
if (header) {
header.onmousedown = (e) => {
// 如果点击的是按钮,不触发拖拽
if (e.target.id === 'minimizeBtn' || e.target.id === 'closeBtn') {
return;
}
isDragging = true;
dragOffset.x = e.clientX - panel.offsetLeft;
dragOffset.y = e.clientY - panel.offsetTop;
header.style.cursor = 'grabbing';
document.body.style.userSelect = 'none'; // 防止选中文本
e.preventDefault();
};
}
// 悬浮宠物拖拽
if (pet) {
pet.onmousedown = (e) => {
if (e.detail === 1) { // 单击时不拖拽,双击时拖拽
setTimeout(() => {
if (e.detail === 1) return; // 如果是单击就返回
isDragging = true;
dragOffset.x = e.clientX - pet.offsetLeft;
dragOffset.y = e.clientY - pet.offsetTop;
pet.style.cursor = 'grabbing';
document.body.style.userSelect = 'none';
e.preventDefault();
e.stopPropagation();
}, 200);
}
};
}
// 优化的鼠标移动事件(使用requestAnimationFrame)
let animationId = null;
document.onmousemove = (e) => {
if (isDragging) {
if (animationId) {
cancelAnimationFrame(animationId);
}
animationId = requestAnimationFrame(() => {
if (isDragging) {
const activeElement = panel.style.display !== 'none' ? panel : pet;
if (activeElement) {
const newX = e.clientX - dragOffset.x;
const newY = e.clientY - dragOffset.y;
// 限制在屏幕范围内
const maxX = window.innerWidth - activeElement.offsetWidth;
const maxY = window.innerHeight - activeElement.offsetHeight;
activeElement.style.left = Math.max(0, Math.min(newX, maxX)) + 'px';
activeElement.style.top = Math.max(0, Math.min(newY, maxY)) + 'px';
activeElement.style.right = 'auto';
activeElement.style.bottom = 'auto';
}
}
});
}
};
// 全局鼠标释放事件
document.onmouseup = () => {
if (isDragging) {
isDragging = false;
if (header) header.style.cursor = 'move';
if (pet) pet.style.cursor = 'pointer';
document.body.style.userSelect = '';
}
if (animationId) {
cancelAnimationFrame(animationId);
animationId = null;
}
};
}
// 最小化面板
function minimizePanel() {
const panel = document.getElementById('knowledgePanel');
const pet = document.getElementById('floatingPet');
if (panel && pet) {
panel.style.display = 'none';
pet.style.display = 'flex';
// 悬浮宠物显示状态
if (stats.processed > 0) {
const accuracy = Math.round((stats.success / stats.processed) * 100);
pet.innerHTML = `${accuracy}%`;
pet.title = `答题进度: ${stats.processed}/${stats.total} (${accuracy}%) - 点击展开`;
} else {
pet.innerHTML = '📚';
pet.title = '自动答题助手 - 点击展开';
}
log('📱 已最小化为悬浮小宠物');
}
}
// 恢复面板
function restorePanel() {
const panel = document.getElementById('knowledgePanel');
const pet = document.getElementById('floatingPet');
if (panel && pet) {
panel.style.display = 'block';
pet.style.display = 'none';
log('📱 已恢复面板显示');
}
}
// 关闭面板
function closePanel() {
const panel = document.getElementById('knowledgePanel');
const pet = document.getElementById('floatingPet');
if (confirm('确定要关闭自动答题助手吗?')) {
if (panel) panel.remove();
if (pet) pet.remove();
// 停止答题
CONFIG.stop = true;
log('❌ 答题助手已关闭');
console.log('📚 自动答题助手已关闭');
}
}
// 初始化
function init() {
if (!location.href.includes('txsyaqpx.zhongancloud.com')) {
return;
}
const checkReady = () => {
if (document.querySelector('.ques-type-item')) {
setupGlobalFunctions();
setupBackgroundKeepAlive();
createPanel();
} else {
setTimeout(checkReady, 1000);
}
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', checkReady);
} else {
setTimeout(checkReady, 1000);
}
}
// 启动
init();
})();