// ==UserScript==
// @name 中泰学堂
// @namespace http://tampermonkey.net/
// @version 2.4.0
// @description 中泰学堂
// @author You
// @match *://*.radnova.cn/*
// @match *://*.yunxuetang.cn/*
// @match *://*.yxt.com/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_xmlhttpRequest
// @grant GM_getResourceText
// @run-at document-idle
// @connect open.bigmodel.cn
// @connect dashscope.aliyuncs.com
// @connect api.deepseek.com
// @connect *
// ==/UserScript==
(function() {
'use strict';
// 🔧 立即定义全局函数,确保面板按钮可用
window.ZTXT_startAnswering = null; // 先占位,后面会重新定义
window.ZTXT_stopAnswering = null;
// 全局配置 - 轻量化
const GLOBAL = {
index: 0,
stop: false,
delay: 1500, // 减少延迟时间
fillAnswerDelay: 500, // 减少填充延迟
isMatch: false,
searchDelay: 200, // 大幅减少搜索延迟
autoSubmit: false,
isMinimized: false, // 记录最小化状态
autoStudy: false, // 挂机检测
autoNext: false, // 自动下一个
videoProgress: false, // 视频进度检测
autoSpeed: false, // 自动最高倍速
currentTab: 'video' // 当前标签页
};
// 题目类型
const TYPE = {
"单选题": 0,
"单项选择题": 0,
"单选": 0,
"多选题": 1,
"多项选择题": 1,
"多选": 1,
"填空题": 2,
"填空": 2,
"判断题": 3,
"判断": 3,
"对错题": 3,
"问答题": 4,
"简答题": 4,
"主观题": 4
};
// 工具函数
function formatString(str) {
if (!str) return '';
return String(str)
.replace(/[\uff01-\uff5e]/g, function(char) {
return String.fromCharCode(char.charCodeAt(0) - 65248);
})
.replace(/\s+/g, ' ')
.replace(/[""]/g, '"')
.replace(/['']/g, "'")
.replace(/。/g, '.')
.replace(/[,.?:!;]$/, '')
.trim();
}
function sleep(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
// 挂机检测监控器
let autoStudyInterval = null;
let autoNextInterval = null;
let videoProgressInterval = null;
let autoSpeedInterval = null;
// 启动挂机检测监控
function startAutoStudyMonitor() {
if (autoStudyInterval) {
clearInterval(autoStudyInterval);
}
console.log('[中泰学堂] 📺 启动挂机检测监控');
autoStudyInterval = setInterval(() => {
// 查找"继续学习"按钮
const continueButtons = document.querySelectorAll('button, .btn, [role="button"]');
for (const btn of continueButtons) {
const btnText = btn.textContent.trim();
// 匹配"继续学习"相关文本
if (btnText.includes('继续学习') || btnText.includes('继续') ||
btnText.includes('continue') || btnText.includes('Continue')) {
console.log('[中泰学堂] 📺 发现"继续学习"按钮,自动点击');
btn.click();
// 记录到日志
const logEl = document.querySelector('#answer-log');
if (logEl) {
const time = new Date().toLocaleTimeString();
logEl.innerHTML += `
[${time}] 🎬 ${triggerReason}${actualBackwardTime.toFixed(1)}秒 (视频剩${videoRemaining.toFixed(1)}s→倒计时${countdownRemaining}s)
`;
logEl.scrollTop = logEl.scrollHeight;
}
// 暂停一段时间避免重复触发
setTimeout(() => {
console.log('[中泰学堂] 🎬 回退操作完成,继续监控');
}, 5000); // 增加到5秒避免重复
break;
}
}
// 场景2:更早期的预测(视频剩余15-30秒时)
else if (videoRemaining > 10 && videoRemaining <= 30 && countdownRemaining > videoRemaining + 10) {
const timeDifference = countdownRemaining - videoRemaining;
// 如果时间差超过15秒,提前进行小幅回退
if (timeDifference > 15) {
const earlyBackwardTime = Math.min(timeDifference * 0.3, 20); // 回退时间差的30%,最多20秒
console.log(`[中泰学堂] 🎬 早期预测: 视频剩余${videoRemaining.toFixed(1)}秒,倒计时${countdownRemaining}秒,提前回退${earlyBackwardTime.toFixed(1)}秒`);
video.currentTime = Math.max(0, video.currentTime - earlyBackwardTime);
// 记录到日志
const logEl = document.querySelector('#answer-log');
if (logEl) {
const time = new Date().toLocaleTimeString();
logEl.innerHTML += `
状态:
视频助手就绪
自动处理学习过程中的各种提示
视频完成但倒计时未结束时自动回退
开启后优先使用AI智能答题,提升准确率
🎯 中泰学堂助手
v2.3.0 | 答题 + 挂机检测 + 自动学习
`;
document.body.appendChild(panel);
// 创建悬浮小宠物
createFloatingPet();
// 检查用户之前的最小化状态
const wasMinimized = GM_getValue('panel_minimized', false);
GLOBAL.isMinimized = wasMinimized;
if (panel) {
console.log('[中泰学堂] 拟态化控制面板创建成功');
if (wasMinimized) {
// 如果之前是最小化状态,直接显示悬浮窗
panel.style.display = 'none';
const pet = document.querySelector('#floating-pet');
if (pet) {
pet.style.display = 'flex';
}
console.log('[中泰学堂] 📱 恢复最小化状态');
} else {
// 正常显示面板
panel.style.display = 'block';
panel.style.visibility = 'visible';
panel.style.opacity = '1';
panel.style.zIndex = '2147483647';
}
} else {
console.error('[中泰学堂] 控制面板创建失败');
}
return panel;
}
// 创建简单备用面板
function createSimplePanel() {
const panel = document.createElement('div');
panel.id = 'zt-auto-panel';
panel.style.cssText = `
position: fixed !important;
top: 50px !important;
right: 50px !important;
width: 300px !important;
background: white !important;
border: 2px solid #1890ff !important;
border-radius: 8px !important;
box-shadow: 0 4px 20px rgba(0,0,0,0.2) !important;
z-index: 2147483647 !important;
font-family: Arial, sans-serif !important;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
`;
panel.innerHTML = `
🎯 中泰学堂答题助手
`;
document.body.appendChild(panel);
console.log('[中泰学堂] 备用面板创建完成');
// 添加简单的开始按钮功能
const startBtn = panel.querySelector('#simple-start');
startBtn.addEventListener('click', () => {
startAnswering();
});
return panel;
}
// 创建悬浮小宠物
function createFloatingPet() {
const pet = document.createElement('div');
pet.id = 'floating-pet';
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 = `
/* 强制显示滚动条样式 */
#answer-log {
scrollbar-width: thin !important;
scrollbar-color: #a0aec0 #f0f2f5 !important;
overflow-y: scroll !important;
overflow-x: hidden !important;
}
#answer-log::-webkit-scrollbar {
width: 12px !important;
height: 12px !important;
display: block !important;
}
#answer-log::-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;
}
#answer-log::-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;
}
#answer-log::-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;
}
@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);
}
}
#floating-pet: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;
}
#floating-pet: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 makeDraggable(panel) {
const header = panel.querySelector('#panel-header');
const pet = document.querySelector('#floating-pet');
let isDragging = false;
let dragOffset = { x: 0, y: 0 };
// 面板拖拽
if (header) {
header.onmousedown = (e) => {
// 如果点击的是按钮,不触发拖拽
if (e.target.id === 'minimize-btn' || e.target.id === 'close-btn') {
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);
}
};
}
// 优化的鼠标移动事件
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;
}
};
// 恢复保存的位置
const savedPos = GM_getValue('panel_position', '30,20');
const [x, y] = savedPos.split(',').map(Number);
panel.style.left = x + 'px';
panel.style.top = y + 'px';
panel.style.right = 'auto';
}
// 最小化面板
function minimizePanel() {
const panel = document.querySelector('#zt-auto-panel');
const pet = document.querySelector('#floating-pet');
if (panel && pet) {
panel.style.display = 'none';
pet.style.display = 'flex';
// 保存最小化状态
GLOBAL.isMinimized = true;
GM_setValue('panel_minimized', true);
console.log('[中泰学堂] 📱 已最小化为悬浮小宠物');
}
}
// 恢复面板
function restorePanel() {
const panel = document.querySelector('#zt-auto-panel');
const pet = document.querySelector('#floating-pet');
if (panel && pet) {
panel.style.display = 'block';
pet.style.display = 'none';
// 保存恢复状态
GLOBAL.isMinimized = false;
GM_setValue('panel_minimized', false);
console.log('[中泰学堂] 📱 已恢复面板显示');
}
}
// 简化面板控制
function setupPanelControls(panel) {
console.log('[中泰学堂] 设置面板控制...');
// 获取设置元素
const delayInput = panel.querySelector('#delay-input');
const autoSubmitCheckbox = panel.querySelector('#auto-submit');
const enableAICheckbox = panel.querySelector('#enable-ai');
// 视频标签页的复选框(只在视频标签页中)
const autoStudyCheckbox = panel.querySelector('#auto-study');
const autoNextCheckbox = panel.querySelector('#auto-next');
const videoProgressCheckbox = panel.querySelector('#video-progress');
const autoSpeedCheckbox = panel.querySelector('#auto-speed');
// 获取复选框显示元素
const autoSubmitDisplay = panel.querySelector('#autosubmit-checkbox');
const aiDisplay = panel.querySelector('#ai-checkbox');
const autoStudyDisplay = panel.querySelector('#autostudy-checkbox');
const autoNextDisplay = panel.querySelector('#autonext-checkbox');
const videoProgressDisplay = panel.querySelector('#videoprogress-checkbox');
const autoSpeedDisplay = panel.querySelector('#autospeed-checkbox');
// 获取标签页元素
const videoTab = panel.querySelector('#video-tab');
const examTab = panel.querySelector('#exam-tab');
const videoContent = panel.querySelector('#video-content');
const examContent = panel.querySelector('#exam-content');
// 恢复保存的设置
if (delayInput) delayInput.value = GM_getValue('answer_delay', 2);
if (autoSubmitCheckbox) autoSubmitCheckbox.checked = GM_getValue('auto_submit', false);
if (enableAICheckbox) enableAICheckbox.checked = GM_getValue('enable_ai', false);
// 视频功能设置(只在视频标签页中)
if (autoStudyCheckbox) autoStudyCheckbox.checked = GM_getValue('auto_study', false);
if (autoNextCheckbox) autoNextCheckbox.checked = GM_getValue('auto_next', false);
if (videoProgressCheckbox) videoProgressCheckbox.checked = GM_getValue('video_progress', false);
if (autoSpeedCheckbox) autoSpeedCheckbox.checked = GM_getValue('auto_speed', false);
// 恢复标签页状态
GLOBAL.currentTab = GM_getValue('current_tab', 'video');
// 复选框交互函数
const updateCheckbox = (checkbox, display) => {
if (!checkbox || !display) return;
const isChecked = checkbox.checked;
const indicator = display.querySelector('div');
if (indicator) {
indicator.style.transform = isChecked ? 'scale(1)' : 'scale(0)';
}
display.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)';
};
// 标签页切换函数
const switchTab = (tabName) => {
GLOBAL.currentTab = tabName;
GM_setValue('current_tab', tabName);
if (tabName === 'video') {
if (videoTab) {
videoTab.style.background = '#f0f2f5';
videoTab.style.color = '#38a169';
videoTab.style.boxShadow = '4px 4px 8px rgba(0,0,0,0.1), -4px -4px 8px rgba(255,255,255,0.8)';
}
if (examTab) {
examTab.style.background = 'transparent';
examTab.style.color = '#718096';
examTab.style.boxShadow = 'none';
}
if (videoContent) videoContent.style.display = 'block';
if (examContent) examContent.style.display = 'none';
} else {
if (examTab) {
examTab.style.background = '#f0f2f5';
examTab.style.color = '#38a169';
examTab.style.boxShadow = '4px 4px 8px rgba(0,0,0,0.1), -4px -4px 8px rgba(255,255,255,0.8)';
}
if (videoTab) {
videoTab.style.background = 'transparent';
videoTab.style.color = '#718096';
videoTab.style.boxShadow = 'none';
}
if (videoContent) videoContent.style.display = 'none';
if (examContent) examContent.style.display = 'block';
}
console.log('[中泰学堂] 切换到标签页:', tabName);
};
// 绑定标签页点击事件
if (videoTab) {
videoTab.addEventListener('click', () => switchTab('video'));
}
if (examTab) {
examTab.addEventListener('click', () => switchTab('exam'));
}
// 初始化标签页状态
switchTab(GLOBAL.currentTab);
// 初始化复选框状态
updateCheckbox(autoSubmitCheckbox, autoSubmitDisplay);
updateCheckbox(enableAICheckbox, aiDisplay);
// 视频功能复选框(只在视频标签页中)
updateCheckbox(autoStudyCheckbox, autoStudyDisplay);
updateCheckbox(autoNextCheckbox, autoNextDisplay);
updateCheckbox(videoProgressCheckbox, videoProgressDisplay);
updateCheckbox(autoSpeedCheckbox, autoSpeedDisplay);
// 设置变更监听
if (delayInput) {
delayInput.addEventListener('change', () => {
GLOBAL.delay = parseInt(delayInput.value) * 1000;
GM_setValue('answer_delay', parseInt(delayInput.value));
console.log('[中泰学堂] 答题延迟更新为:', delayInput.value + '秒');
});
}
if (autoSubmitCheckbox && autoSubmitDisplay) {
autoSubmitCheckbox.addEventListener('change', () => {
GM_setValue('auto_submit', autoSubmitCheckbox.checked);
updateCheckbox(autoSubmitCheckbox, autoSubmitDisplay);
console.log('[中泰学堂] 自动提交设置:', autoSubmitCheckbox.checked);
});
// 点击显示区域也能切换
autoSubmitDisplay.addEventListener('click', () => {
autoSubmitCheckbox.checked = !autoSubmitCheckbox.checked;
GM_setValue('auto_submit', autoSubmitCheckbox.checked);
updateCheckbox(autoSubmitCheckbox, autoSubmitDisplay);
console.log('[中泰学堂] 自动提交设置:', autoSubmitCheckbox.checked);
});
}
if (enableAICheckbox && aiDisplay) {
enableAICheckbox.addEventListener('change', () => {
GM_setValue('enable_ai', enableAICheckbox.checked);
updateCheckbox(enableAICheckbox, aiDisplay);
console.log('[中泰学堂] 🤖 AI答题设置:', enableAICheckbox.checked ? '已启用' : '已关闭');
});
// 点击显示区域也能切换
aiDisplay.addEventListener('click', () => {
enableAICheckbox.checked = !enableAICheckbox.checked;
GM_setValue('enable_ai', enableAICheckbox.checked);
updateCheckbox(enableAICheckbox, aiDisplay);
console.log('[中泰学堂] 🤖 AI答题设置:', enableAICheckbox.checked ? '已启用' : '已关闭');
});
}
if (autoStudyCheckbox && autoStudyDisplay) {
autoStudyCheckbox.addEventListener('change', () => {
GLOBAL.autoStudy = autoStudyCheckbox.checked;
GM_setValue('auto_study', autoStudyCheckbox.checked);
updateCheckbox(autoStudyCheckbox, autoStudyDisplay);
console.log('[中泰学堂] 📺 挂机检测设置:', autoStudyCheckbox.checked ? '已启用' : '已关闭');
if (autoStudyCheckbox.checked) {
startAutoStudyMonitor();
} else {
stopAutoStudyMonitor();
}
});
// 点击显示区域也能切换
autoStudyDisplay.addEventListener('click', () => {
autoStudyCheckbox.checked = !autoStudyCheckbox.checked;
GLOBAL.autoStudy = autoStudyCheckbox.checked;
GM_setValue('auto_study', autoStudyCheckbox.checked);
updateCheckbox(autoStudyCheckbox, autoStudyDisplay);
console.log('[中泰学堂] 📺 挂机检测设置:', autoStudyCheckbox.checked ? '已启用' : '已关闭');
if (autoStudyCheckbox.checked) {
startAutoStudyMonitor();
} else {
stopAutoStudyMonitor();
}
});
}
if (autoNextCheckbox && autoNextDisplay) {
autoNextCheckbox.addEventListener('change', () => {
GLOBAL.autoNext = autoNextCheckbox.checked;
GM_setValue('auto_next', autoNextCheckbox.checked);
updateCheckbox(autoNextCheckbox, autoNextDisplay);
console.log('[中泰学堂] ⏭️ 自动下一个设置:', autoNextCheckbox.checked ? '已启用' : '已关闭');
if (autoNextCheckbox.checked) {
startAutoNextMonitor();
} else {
stopAutoNextMonitor();
}
});
// 点击显示区域也能切换
autoNextDisplay.addEventListener('click', () => {
autoNextCheckbox.checked = !autoNextCheckbox.checked;
GLOBAL.autoNext = autoNextCheckbox.checked;
GM_setValue('auto_next', autoNextCheckbox.checked);
updateCheckbox(autoNextCheckbox, autoNextDisplay);
console.log('[中泰学堂] ⏭️ 自动下一个设置:', autoNextCheckbox.checked ? '已启用' : '已关闭');
if (autoNextCheckbox.checked) {
startAutoNextMonitor();
} else {
stopAutoNextMonitor();
}
});
}
if (videoProgressCheckbox && videoProgressDisplay) {
videoProgressCheckbox.addEventListener('change', () => {
GLOBAL.videoProgress = videoProgressCheckbox.checked;
GM_setValue('video_progress', videoProgressCheckbox.checked);
updateCheckbox(videoProgressCheckbox, videoProgressDisplay);
console.log('[中泰学堂] 🎬 视频进度检测设置:', videoProgressCheckbox.checked ? '已启用' : '已关闭');
if (videoProgressCheckbox.checked) {
startVideoProgressMonitor();
} else {
stopVideoProgressMonitor();
}
});
// 点击显示区域也能切换
videoProgressDisplay.addEventListener('click', () => {
videoProgressCheckbox.checked = !videoProgressCheckbox.checked;
GLOBAL.videoProgress = videoProgressCheckbox.checked;
GM_setValue('video_progress', videoProgressCheckbox.checked);
updateCheckbox(videoProgressCheckbox, videoProgressDisplay);
console.log('[中泰学堂] 🎬 视频进度检测设置:', videoProgressCheckbox.checked ? '已启用' : '已关闭');
if (videoProgressCheckbox.checked) {
startVideoProgressMonitor();
} else {
stopVideoProgressMonitor();
}
});
}
if (autoSpeedCheckbox && autoSpeedDisplay) {
autoSpeedCheckbox.addEventListener('change', () => {
GLOBAL.autoSpeed = autoSpeedCheckbox.checked;
GM_setValue('auto_speed', autoSpeedCheckbox.checked);
updateCheckbox(autoSpeedCheckbox, autoSpeedDisplay);
console.log('[中泰学堂] ⚡ 自动最高倍速设置:', autoSpeedCheckbox.checked ? '已启用' : '已关闭');
if (autoSpeedCheckbox.checked) {
startAutoSpeedMonitor();
} else {
stopAutoSpeedMonitor();
}
});
// 点击显示区域也能切换
autoSpeedDisplay.addEventListener('click', () => {
autoSpeedCheckbox.checked = !autoSpeedCheckbox.checked;
GLOBAL.autoSpeed = autoSpeedCheckbox.checked;
GM_setValue('auto_speed', autoSpeedCheckbox.checked);
updateCheckbox(autoSpeedCheckbox, autoSpeedDisplay);
console.log('[中泰学堂] ⚡ 自动最高倍速设置:', autoSpeedCheckbox.checked ? '已启用' : '已关闭');
if (autoSpeedCheckbox.checked) {
startAutoSpeedMonitor();
} else {
stopAutoSpeedMonitor();
}
});
}
// 🔧 绑定按钮事件
const startBtn = panel.querySelector('#start-btn');
const stopBtn = panel.querySelector('#stop-btn');
const minimizeBtn = panel.querySelector('#minimize-btn');
const closeBtn = panel.querySelector('#close-btn');
const clearLogBtn = panel.querySelector('#clear-log');
const donateBtn = panel.querySelector('#donate-btn');
console.log('[中泰学堂] 🔍 查找按钮:');
console.log(' - 开始按钮:', !!startBtn);
console.log(' - 停止按钮:', !!stopBtn);
console.log(' - 最小化按钮:', !!minimizeBtn);
console.log(' - 关闭按钮:', !!closeBtn);
console.log(' - 打赏按钮:', !!donateBtn);
// 开始按钮
if (startBtn) {
startBtn.addEventListener('click', async function() {
console.log('[中泰学堂] 🚀 开始按钮被点击');
const questions = getAllQuestions();
if (questions.length === 0) {
console.log('[中泰学堂] 未找到题目');
alert('未找到题目,请确认在考试页面');
return;
}
console.log('[中泰学堂] 🚀 AI答题开始!');
// 更新按钮状态
startBtn.disabled = true;
startBtn.style.opacity = '0.6';
stopBtn.disabled = false;
stopBtn.style.opacity = '1';
await startAnswering();
});
console.log('[中泰学堂] ✅ 开始按钮事件监听器已绑定');
}
// 停止按钮
if (stopBtn) {
const forceStop = function() {
console.log('[中泰学堂] 🛑 强制停止答题!');
GLOBAL.stop = true;
// 更新面板状态
const statusEl = document.querySelector('#status-indicator');
const statusTextEl = document.querySelector('#status-text');
if (statusEl) {
statusEl.textContent = '已停止';
statusEl.style.background = '#f0f2f5';
statusEl.style.color = '#ed8936';
}
if (statusTextEl) {
statusTextEl.textContent = '用户主动停止了答题';
}
// 更新按钮状态
stopBtn.disabled = true;
stopBtn.style.opacity = '0.6';
startBtn.disabled = false;
startBtn.style.opacity = '1';
console.log('[中泰学堂] ✅ 强制停止完成');
return true;
};
stopBtn.addEventListener('click', function(e) {
console.log('[中泰学堂] 🛑 停止按钮点击事件触发');
e.preventDefault();
e.stopPropagation();
forceStop();
});
console.log('[中泰学堂] ✅ 停止按钮事件监听器已绑定');
}
// 最小化按钮
if (minimizeBtn) {
minimizeBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
minimizePanel();
});
console.log('[中泰学堂] ✅ 最小化按钮事件监听器已绑定');
}
// 关闭按钮
if (closeBtn) {
closeBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
if (confirm('确定要关闭中泰学堂助手吗?')) {
const panel = document.querySelector('#zt-auto-panel');
const pet = document.querySelector('#floating-pet');
if (panel) panel.remove();
if (pet) pet.remove();
GLOBAL.stop = true;
console.log('[中泰学堂] ❌ 答题助手已关闭');
}
});
console.log('[中泰学堂] ✅ 关闭按钮事件监听器已绑定');
}
// 清空日志按钮
if (clearLogBtn) {
clearLogBtn.addEventListener('click', function(e) {
e.preventDefault();
const logEl = document.querySelector('#answer-log');
if (logEl) {
logEl.innerHTML = '
暂无答题记录
';
}
console.log('[中泰学堂] 📝 答题记录已清空');
});
console.log('[中泰学堂] ✅ 清空日志按钮事件监听器已绑定');
}
// 打赏按钮
if (donateBtn) {
donateBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
showDonateModal();
});
console.log('[中泰学堂] ✅ 打赏按钮事件监听器已绑定');
}
console.log('[中泰学堂] 面板控制设置完成');
// 启动已勾选的监控功能
if (autoStudyCheckbox && autoStudyCheckbox.checked) {
startAutoStudyMonitor();
}
if (autoNextCheckbox && autoNextCheckbox.checked) {
startAutoNextMonitor();
}
if (videoProgressCheckbox && videoProgressCheckbox.checked) {
startVideoProgressMonitor();
}
if (autoSpeedCheckbox && autoSpeedCheckbox.checked) {
startAutoSpeedMonitor();
}
// 立即启动自动禁音功能和视频信息监控
startAutoMuteMonitor();
startVideoInfoMonitor();
// 🔧 立即定义全局函数,确保面板按钮可用
defineGlobalFunctions();
}
// 实时更新面板状态显示
function updatePanelStatus(questions, stats) {
try {
console.log('[中泰学堂] 🔄 更新面板状态显示...');
// 获取各种可能的面板元素选择器
const statusSelectors = ['#zt-status', '#status-indicator', '[id*="status"]'];
const statusTextSelectors = ['#zt-status-text', '#status-text', '[id*="status-text"]'];
const progressSelectors = ['#zt-progress', '#progress-text', '[id*="progress"]'];
const progressBarSelectors = ['#zt-progress-bar', '#progress-bar', '[id*="progress-bar"]'];
// 题型统计选择器
const singleCountSelectors = ['#single-count', '[id*="single"]'];
const multiCountSelectors = ['#multi-count', '[id*="multi"]'];
const judgeCountSelectors = ['#judge-count', '[id*="judge"]'];
// 更新主状态
const statusEl = findElement(statusSelectors);
if (statusEl) {
if (questions.length > 0) {
statusEl.textContent = '已检测到题目';
statusEl.style.background = '#52c41a';
statusEl.style.color = 'white';
} else {
statusEl.textContent = '未找到题目';
statusEl.style.background = '#faad14';
statusEl.style.color = 'white';
}
console.log('[中泰学堂] ✅ 更新状态指示器');
}
// 更新状态文本
const statusTextEl = findElement(statusTextSelectors);
if (statusTextEl) {
if (questions.length > 0) {
statusTextEl.textContent = `检测到${questions.length}道题目,点击开始答题`;
} else {
statusTextEl.textContent = '未检测到题目,请确认在考试页面';
}
console.log('[中泰学堂] ✅ 更新状态文本');
}
// 更新进度显示
const progressEl = findElement(progressSelectors);
if (progressEl) {
progressEl.textContent = `0/${questions.length}`;
console.log('[中泰学堂] ✅ 更新进度文本');
}
// 重置进度条
const progressBarEl = findElement(progressBarSelectors);
if (progressBarEl) {
progressBarEl.style.width = '0%';
console.log('[中泰学堂] ✅ 重置进度条');
}
// 更新题型统计
if (stats) {
const singleCountEl = findElement(singleCountSelectors);
const multiCountEl = findElement(multiCountSelectors);
const judgeCountEl = findElement(judgeCountSelectors);
if (singleCountEl) {
singleCountEl.textContent = stats.单选;
console.log('[中泰学堂] ✅ 更新单选题统计');
}
if (multiCountEl) {
multiCountEl.textContent = stats.多选;
console.log('[中泰学堂] ✅ 更新多选题统计');
}
if (judgeCountEl) {
judgeCountEl.textContent = stats.判断;
console.log('[中泰学堂] ✅ 更新判断题统计');
}
}
console.log('[中泰学堂] ✅ 面板状态更新完成');
} catch (e) {
console.error('[中泰学堂] 面板状态更新出错:', e);
}
}
// 辅助函数:通过多个选择器查找元素
function findElement(selectors) {
for (const selector of selectors) {
const element = document.querySelector(selector);
if (element) {
return element;
}
}
return null;
}
// 🔧 定义全局函数
function defineGlobalFunctions() {
console.log('[中泰学堂] 🔧 定义全局函数...');
// 主要答题函数
window.ZTXT_startAnswering = async function() {
console.log('[中泰学堂] 🚀 全局函数被调用!');
const questions = getAllQuestions();
if (questions.length === 0) {
console.log('[中泰学堂] 未找到题目');
alert('未找到题目,请确认在考试页面');
return;
}
console.log(`[中泰学堂] 开始处理${questions.length}题`);
await startAnswering();
};
// 停止答题函数
window.ZTXT_stopAnswering = function() {
console.log('[中泰学堂] 🛑 停止答题被调用');
console.log('[中泰学堂] 🛑 当前GLOBAL.stop状态:', GLOBAL.stop);
GLOBAL.stop = true;
// 立即反馈用户
console.log('[中泰学堂] 🛑 显示停止确认...');
try {
// 更新面板状态
const statusEl = document.querySelector('#zt-status, #status-indicator, [id*="status"]');
const statusTextEl = document.querySelector('#status-text, [id*="status-text"]');
const startBtn = document.querySelector('#start-btn, #zt-start-btn, [id*="start"]');
const stopBtn = document.querySelector('#stop-btn, #zt-stop-btn, [id*="stop"]');
console.log('[中泰学堂] 🔍 查找面板元素:');
console.log(' statusEl:', !!statusEl);
console.log(' statusTextEl:', !!statusTextEl);
console.log(' startBtn:', !!startBtn);
console.log(' stopBtn:', !!stopBtn);
if (statusEl) {
statusEl.textContent = '已停止';
statusEl.style.background = '#faad14';
statusEl.style.color = '#fff';
console.log('[中泰学堂] ✅ 更新状态指示器');
}
if (statusTextEl) {
statusTextEl.textContent = '用户主动停止了答题';
console.log('[中泰学堂] ✅ 更新状态文本');
}
if (startBtn) {
startBtn.disabled = false;
startBtn.textContent = '🚀 开始答题';
startBtn.style.background = '#1890ff';
console.log('[中泰学堂] ✅ 启用开始按钮');
}
if (stopBtn) {
stopBtn.disabled = true;
stopBtn.textContent = '已停止';
stopBtn.style.background = '#ccc';
stopBtn.style.cursor = 'not-allowed';
console.log('[中泰学堂] ✅ 禁用停止按钮');
}
// 弹窗确认
setTimeout(() => {
alert('✅ 答题已停止!面板状态已更新。');
}, 100);
} catch (e) {
console.error('[中泰学堂] ❌ 停止按钮更新失败:', e);
alert('⚠️ 答题已停止,但面板更新失败。请刷新页面。');
}
console.log('[中泰学堂] ✅ 停止答题完成,GLOBAL.stop =', GLOBAL.stop);
};
// 🔧 测试函数:检查面板状态
window.ZTXT_testPanel = function() {
console.log('=== 🔧 面板状态测试 ===');
console.log('1. 全局函数状态:');
console.log(' - ZTXT_startAnswering:', typeof window.ZTXT_startAnswering);
console.log(' - ZTXT_stopAnswering:', typeof window.ZTXT_stopAnswering);
console.log('2. 面板元素检查:');
const panel = document.querySelector('#zt-auto-panel');
const startBtn = document.querySelector('#start-btn');
const stopBtn = document.querySelector('#stop-btn');
const statusEl = document.querySelector('#zt-status');
console.log(' - 面板存在:', !!panel);
console.log(' - 开始按钮:', !!startBtn);
console.log(' - 停止按钮:', !!stopBtn);
console.log(' - 状态显示:', !!statusEl);
if (stopBtn) {
console.log('3. 停止按钮详情:');
console.log(' - onclick:', stopBtn.onclick);
console.log(' - getAttribute("onclick"):', stopBtn.getAttribute('onclick'));
console.log(' - disabled:', stopBtn.disabled);
console.log(' - style.display:', stopBtn.style.display);
}
console.log('4. GLOBAL状态:');
console.log(' - GLOBAL.stop:', GLOBAL.stop);
return {
panel: !!panel,
startBtn: !!startBtn,
stopBtn: !!stopBtn,
statusEl: !!statusEl,
functions: {
start: typeof window.ZTXT_startAnswering,
stop: typeof window.ZTXT_stopAnswering
}
};
};
console.log('[中泰学堂] ✅ 全局函数定义完成');
console.log('[中泰学堂] 函数检查:', typeof window.ZTXT_startAnswering);
console.log('[中泰学堂] 🔧 测试命令: window.ZTXT_testPanel()');
}
// 简化页面检测
function isExamPage() {
return location.hostname.includes('radnova.cn');
}
// 🚀 终极通用题目检测算法 - 支持任意数量题目
function getAllQuestions() {
try {
const questions = [];
console.log('[中泰学堂] 🔍 启动终极通用检测算法...');
// 🎯 策略1: 基于真实页面结构的精确检测
console.log('[中泰学堂] 📋 策略1: 精确页面结构检测...');
// 查找所有mv24容器(这是题目的标准容器)
const mv24Containers = document.querySelectorAll('div.mv24');
console.log(`[中泰学堂] 发现 ${mv24Containers.length} 个mv24容器`);
const questionContainers = [];
// 验证每个容器是否确实包含单个题目(避免大容器)
Array.from(mv24Containers).forEach((container, index) => {
const containerText = container.textContent || '';
// 检查是否包含题目编号和富文本
const hasQuestionNumber = containerText.match(/^\s*\d+\./);
const hasRichText = container.querySelector('[data-rich-text]');
const hasInputs = container.querySelectorAll('input[type="radio"], input[type="checkbox"]').length > 0;
// 严格检查条件,避免误识别
const isReasonableSize = containerText.length > 10 && containerText.length < 800; // 合理的题目长度
const questionNumbers = containerText.match(/\d+\./g);
const hasSingleQuestion = questionNumbers && questionNumbers.length === 1; // 必须恰好有1个题目编号
// 检查是否包含选项标识(A. B. C. D. 或 正确/错误)
const hasOptionsMarkers = (containerText.includes('A.') && containerText.includes('B.')) ||
(containerText.includes('正确') && containerText.includes('错误'));
// 放宽题目标识检查(不强制要求问号,因为很多题目是陈述句)
const hasQuestionMarkers = containerText.includes('?') || containerText.includes('?') ||
containerText.includes(':') || containerText.includes(':') ||
containerText.includes('()') || // 填空题标识
containerText.includes('下列') || containerText.includes('以下') ||
containerText.match(/\d+\.\s*\S+/); // 有编号的都算题目
// 或者检查相邻元素是否有input(有些页面结构input在下一个容器)
let hasNearbyInputs = false;
if (!hasInputs && container.nextElementSibling) {
hasNearbyInputs = container.nextElementSibling.querySelectorAll('input[type="radio"], input[type="checkbox"]').length > 0;
}
// 更灵活的验证条件(确保不漏题)
const isValidQuestion = (hasQuestionNumber || hasRichText) &&
(hasInputs || hasNearbyInputs) &&
isReasonableSize &&
hasSingleQuestion &&
(hasOptionsMarkers || hasQuestionMarkers); // 选项标识或题目标识有一个即可
if (isValidQuestion) {
questionContainers.push(container);
console.log(`[中泰学堂] ✅ 确认题目容器${index + 1}: ${containerText.substring(0, 80).replace(/\s+/g, ' ')}...`);
} else {
console.log(`[中泰学堂] ❌ 跳过容器${index + 1}(长度:${containerText.length}, 题号:${questionNumbers?.length || 0}, 选项:${hasOptionsMarkers?'有':'无'}, 问号:${hasQuestionMarkers?'有':'无'}): ${containerText.substring(0, 60).replace(/\s+/g, ' ')}...`);
}
});
// 🎯 策略2: 强制启用输入元素分组检测(确保找到所有题目)
console.log(`[中泰学堂] 当前找到${questionContainers.length}题,目标30题,强制启用策略2补充检测...`);
// 总是启用策略2,确保不漏题
console.log('[中泰学堂] 📋 策略2: 输入元素分组检测...');
const allInputs = document.querySelectorAll('input[type="radio"], input[type="checkbox"]');
console.log(`[中泰学堂] 总计发现 ${allInputs.length} 个输入元素`);
// 智能input分组:按name属性和位置分组
const inputGroups = new Map();
const usedInputs = new Set(); // 记录已经被现有容器使用的input
// 先标记已经被现有容器使用的input
questionContainers.forEach(container => {
const containerInputs = container.querySelectorAll('input[type="radio"], input[type="checkbox"]');
Array.from(containerInputs).forEach(input => usedInputs.add(input));
});
// 只处理未被使用的input
Array.from(allInputs).forEach(input => {
if (!usedInputs.has(input)) {
const name = input.name || `orphan_${Math.floor(Math.random() * 1000)}`;
if (!inputGroups.has(name)) {
inputGroups.set(name, []);
}
inputGroups.get(name).push(input);
}
});
console.log(`[中泰学堂] 已使用input: ${usedInputs.size}, 未使用input分组: ${inputGroups.size}`);
// 为每个未使用的input组查找对应的题目容器
let groupIndex = 0;
inputGroups.forEach((inputs, name) => {
if (inputs.length === 0) return;
groupIndex++;
console.log(`[中泰学堂] 🔍 处理未使用input组${groupIndex}: ${name} (${inputs.length}个input)`);
// 查找这组input的最合适父级容器
const firstInput = inputs[0];
let bestContainer = null;
let container = firstInput;
let level = 0;
while (container && level < 10) {
container = container.parentElement;
if (!container) break;
level++;
const containerText = container.textContent || '';
// 检查是否是合适的题目容器
const hasReasonableLength = containerText.length > 15 && containerText.length < 1000;
const hasQuestionNumber = containerText.match(/\d+\./);
const hasRichText = container.querySelector('[data-rich-text]');
const notAlreadyAdded = !questionContainers.includes(container);
// 更宽松的条件:只要有编号或富文本,且长度合理,且未添加过
if ((hasQuestionNumber || hasRichText) && hasReasonableLength && notAlreadyAdded) {
bestContainer = container;
break;
}
}
if (bestContainer) {
questionContainers.push(bestContainer);
const previewText = bestContainer.textContent.substring(0, 80).replace(/\s+/g, ' ');
console.log(`[中泰学堂] ✅ 策略2补充检测到题目容器${questionContainers.length}: ${previewText}...`);
} else {
console.log(`[中泰学堂] ❌ input组${groupIndex}未找到合适的题目容器`);
}
});
// 🎯 策略3: 兜底算法 - 深度扫描所有可能的题目元素
if (questionContainers.length < 5) { // 只在真正缺少题目时启用
console.log('[中泰学堂] 📋 策略3: 深度兜底扫描...');
// 查找所有可能包含题目的div元素
const allDivs = document.querySelectorAll('div');
const potentialContainers = [];
Array.from(allDivs).forEach(div => {
const text = div.textContent || '';
// 更宽松的题目判断条件
const hasReasonableLength = text.length > 15 && text.length < 1500;
const hasQuestionCharacteristics = text.includes('?') || text.includes('?') ||
text.includes('下列') || text.includes('以下') ||
text.includes('哪些') || text.includes('属于') ||
text.match(/^.{0,50}[是不对错]?[::]?/);
const hasRelatedInputs = div.querySelectorAll('input[type="radio"], input[type="checkbox"]').length > 0;
const hasNearbyInputs = div.parentElement &&
div.parentElement.querySelectorAll('input[type="radio"], input[type="checkbox"]').length > 0;
if (hasReasonableLength && hasQuestionCharacteristics && (hasRelatedInputs || hasNearbyInputs)) {
potentialContainers.push(div);
}
});
// 去重并按位置排序
const uniqueContainers = [];
potentialContainers.forEach(container => {
if (!questionContainers.includes(container) && !uniqueContainers.includes(container)) {
uniqueContainers.push(container);
console.log(`[中泰学堂] 🔍 深度扫描发现: ${container.textContent.substring(0, 60).replace(/\s+/g, ' ')}...`);
}
});
questionContainers.push(...uniqueContainers);
}
console.log(`[中泰学堂] 🎯 检测算法完成,共找到 ${questionContainers.length} 个题目容器`);
// 🎯 智能去重:移除重复和无效的容器
console.log(`[中泰学堂] 🔍 开始去重,目标30题...`);
const uniqueContainers = [];
const seenQuestions = new Set();
questionContainers.forEach((container, index) => {
const containerText = container.textContent || '';
// 跳过纯选项容器(如 "A. 完成各自的职责")
if (containerText.match(/^[A-D]\.\s*[^1-9]*$/)) {
console.log(`[中泰学堂] ❌ 跳过纯选项容器: ${containerText.substring(0, 30)}...`);
return;
}
// 更宽松的大型容器过滤(避免误过滤多选题)
const questionNumbers = containerText.match(/\d+\./g);
if (questionNumbers && questionNumbers.length > 8) { // 从5改为8,更宽松
console.log(`[中泰学堂] ❌ 跳过大型容器(${questionNumbers.length}个题号): ${containerText.substring(0, 50)}...`);
return;
}
// 提取题目关键特征用于去重
const richTextEl = container.querySelector('[data-rich-text]');
const questionKey = richTextEl ?
richTextEl.textContent.trim().substring(0, 50) :
containerText.match(/\d+\.\s*(.{10,50})/)?.[1] ||
containerText.substring(0, 50);
if (!seenQuestions.has(questionKey) && uniqueContainers.length < 30) {
seenQuestions.add(questionKey);
uniqueContainers.push(container);
console.log(`[中泰学堂] ✅ 保留容器${uniqueContainers.length}: ${questionKey}...`);
} else {
console.log(`[中泰学堂] ❌ 跳过重复/超额容器: ${questionKey}...`);
}
});
console.log(`[中泰学堂] 🎯 去重完成: ${uniqueContainers.length} 个有效容器`);
// 按垂直位置排序,确保题目顺序正确
uniqueContainers.sort((a, b) => {
const rectA = a.getBoundingClientRect();
const rectB = b.getBoundingClientRect();
return rectA.top - rectB.top;
});
// 🎯 开始处理去重后的题目容器
console.log(`[中泰学堂] 🎯 开始处理 ${uniqueContainers.length} 个题目容器`);
// 处理每个去重后的题目容器
uniqueContainers.forEach((container, index) => {
try {
console.log(`[中泰学堂] === 📝 处理题目容器 ${index + 1}/${uniqueContainers.length} ===`);
const containerPreview = container.textContent.substring(0, 100).replace(/\s+/g, ' ');
console.log(`[中泰学堂] 容器内容预览: ${containerPreview}...`);
// 🎯 智能题目文本提取(基于实际HTML结构)
let questionText = '';
// 方法1: 查找data-rich-text属性的元素(主要方法)
let questionEl = container.querySelector('[data-rich-text]');
if (questionEl) {
questionText = questionEl.textContent.trim();
console.log(`[中泰学堂] 容器${index + 1}: 通过rich-text找到题目: ${questionText.substring(0, 50)}...`);
}
// 方法2: 查找题目编号后的文本
if (!questionText) {
const containerText = container.textContent || '';
const match = containerText.match(/^\s*\d+\.\s*(.+?)(?:\s*(|$)/);
if (match && match[1]) {
questionText = match[1].trim();
console.log(`[中泰学堂] 容器${index + 1}: 通过编号匹配找到题目: ${questionText.substring(0, 50)}...`);
}
}
// 方法3: 查找包含问号的最长文本段
if (!questionText) {
const textElements = container.querySelectorAll('div, span, p');
let bestCandidate = '';
Array.from(textElements).forEach(el => {
const text = el.textContent.trim();
if (text.length > bestCandidate.length &&
(text.includes('?') || text.includes('?')) &&
text.length < 500 && // 避免选择过长的文本
!text.includes('分)')) { // 排除分数信息
bestCandidate = text;
}
});
if (bestCandidate) {
questionText = bestCandidate;
console.log(`[中泰学堂] 容器${index + 1}: 通过问号匹配找到题目: ${questionText.substring(0, 50)}...`);
}
}
// 方法4: 兜底 - 使用容器第一行有意义的文本
if (!questionText) {
const containerText = container.textContent.trim();
const lines = containerText.split('\n').filter(line => line.trim().length > 10);
if (lines.length > 0) {
questionText = lines[0].replace(/^\d+\.\s*/, '').trim();
console.log(`[中泰学堂] 容器${index + 1}: 兜底方法找到题目: ${questionText.substring(0, 50)}...`);
}
}
// 清理题目文本
if (questionText) {
// 移除题目编号、分数等干扰信息
questionText = questionText
.replace(/^\d+\.\s*/, '') // 移除题目编号
.replace(/(\s*\d+\s*分\s*)/g, '') // 移除分数信息
.replace(/\s*(\s*[2分]\s*)\s*/g, '') // 移除分数信息
.trim();
}
if (!questionText || questionText.length < 3) {
console.log(`[中泰学堂] 容器${index + 1}: 无法提取有效题目文本,跳过`);
return;
}
console.log(`[中泰学堂] 容器${index + 1}: 最终题目文本 = ${questionText}`);
// 增强选项组查找
const groupSelectors = [
'.yxtf-radio-group', '.yxtf-checkbox-group', // 原有选择器
'[role="radiogroup"]', '[role="group"]', // 语义选择器
'[class*="radio-group"]', '[class*="checkbox-group"]', // 模糊匹配
'[class*="option"]', '[class*="choice"]' // 选项相关
];
let radioGroup = null;
for (const selector of groupSelectors) {
radioGroup = container.querySelector(selector);
if (radioGroup) {
console.log(`[中泰学堂] 容器${index + 1}: 通过 ${selector} 找到选项组`);
break;
}
}
// 如果还是没找到,在父级容器中查找
if (!radioGroup && container.parentElement) {
for (const selector of groupSelectors) {
radioGroup = container.parentElement.querySelector(selector);
if (radioGroup) {
console.log(`[中泰学堂] 容器${index + 1}: 在父级通过 ${selector} 找到选项组`);
break;
}
}
}
if (!radioGroup) {
console.log(`[中泰学堂] 容器${index + 1}: 未找到选项组,跳过`);
return;
}
console.log(`[中泰学堂] 容器${index + 1}: 找到选项组`, radioGroup.className || radioGroup.tagName);
// 🔍 终极智能input查找算法
let inputs = [];
let inputSource = '';
// 优先级1: 在选项组内查找
if (radioGroup) {
inputs = radioGroup.querySelectorAll('input[type="radio"], input[type="checkbox"]');
if (inputs.length > 0) {
inputSource = '选项组内';
console.log(`[中泰学堂] 容器${index + 1}: 在${inputSource}找到${inputs.length}个input`);
}
}
// 优先级2: 在当前容器内查找
if (inputs.length === 0) {
inputs = container.querySelectorAll('input[type="radio"], input[type="checkbox"]');
if (inputs.length > 0) {
inputSource = '当前容器内';
console.log(`[中泰学堂] 容器${index + 1}: 在${inputSource}找到${inputs.length}个input`);
}
}
// 优先级3: 查找下一个兄弟元素(中泰学堂常见结构)
if (inputs.length === 0 && container.nextElementSibling) {
inputs = container.nextElementSibling.querySelectorAll('input[type="radio"], input[type="checkbox"]');
if (inputs.length > 0) {
inputSource = '下一个兄弟元素';
console.log(`[中泰学堂] 容器${index + 1}: 在${inputSource}找到${inputs.length}个input`);
}
}
// 优先级4: 在父级容器中查找
if (inputs.length === 0 && container.parentElement) {
const parentInputs = container.parentElement.querySelectorAll('input[type="radio"], input[type="checkbox"]');
if (parentInputs.length > 0 && parentInputs.length <= 10) { // 避免选择到太多input
inputs = parentInputs;
inputSource = '父级容器内';
console.log(`[中泰学堂] 容器${index + 1}: 在${inputSource}找到${inputs.length}个input`);
}
}
// 优先级5: 基于题目序号的精确匹配(考虑中泰学堂的实际结构)
if (inputs.length === 0) {
console.log(`[中泰学堂] 容器${index + 1}: 尝试基于题目序号的精确匹配...`);
// 从题目文本或容器中提取题目编号
let questionNumber = index + 1; // 默认使用容器索引
const numberMatch = container.textContent.match(/^\s*(\d+)\./);
if (numberMatch) {
questionNumber = parseInt(numberMatch[1]);
console.log(`[中泰学堂] 容器${index + 1}: 检测到题目编号${questionNumber}`);
}
// 查找所有页面input并按name分组
const allPageInputs = document.querySelectorAll('input[type="radio"], input[type="checkbox"]');
const inputGroups = {};
Array.from(allPageInputs).forEach(input => {
const name = input.name || 'unknown';
if (!inputGroups[name]) {
inputGroups[name] = [];
}
inputGroups[name].push(input);
});
// 尝试根据题目编号匹配input组
const groupNames = Object.keys(inputGroups);
if (groupNames.length > 0) {
// 方法1: 直接通过name匹配(如果name包含题目编号)
let targetGroup = null;
for (const name of groupNames) {
if (name.includes(questionNumber.toString())) {
targetGroup = inputGroups[name];
inputSource = `name匹配(${name})`;
break;
}
}
// 方法2: 按索引匹配
if (!targetGroup && questionNumber <= groupNames.length) {
const targetName = groupNames[questionNumber - 1];
targetGroup = inputGroups[targetName];
inputSource = `索引匹配(${targetName})`;
}
// 方法3: 按位置匹配(如果questionNumber合理)
if (!targetGroup && questionNumber > 0 && questionNumber <= questionContainers.length) {
const groupIndex = Math.floor((questionNumber - 1) * groupNames.length / questionContainers.length);
if (groupIndex < groupNames.length) {
const targetName = groupNames[groupIndex];
targetGroup = inputGroups[targetName];
inputSource = `位置匹配(${targetName})`;
}
}
if (targetGroup && targetGroup.length > 0) {
inputs = targetGroup;
console.log(`[中泰学堂] 容器${index + 1}: 通过${inputSource}找到${inputs.length}个input`);
}
}
}
if (inputs.length === 0) {
console.log(`[中泰学堂] 容器${index + 1}: 未找到任何input元素,跳过`);
return;
}
console.log(`[中泰学堂] 容器${index + 1}: 最终确定${inputs.length}个input`);
inputs = Array.from(inputs); // 转换为数组
// 判断题型
const isMultiChoice = inputs[0].type === 'checkbox';
const inputType = isMultiChoice ? 'checkbox' : 'radio';
console.log(`[中泰学堂] 容器${index + 1}: 题型 = ${isMultiChoice ? '多选' : '单选'} (${inputType})`);
// 增强选项文本获取
const options = [];
inputs.forEach((input, inputIndex) => {
let optionText = '';
// 方法1: 通过label获取
let label = input.closest('label');
if (!label) {
// 方法2: 通过for属性查找label
label = document.querySelector(`label[for="${input.id}"]`);
}
if (label) {
optionText = label.textContent.trim();
} else {
// 方法3: 查找input附近的文本
const parent = input.parentElement;
if (parent) {
optionText = parent.textContent.trim();
}
}
if (!optionText) {
// 方法4: 查找input后的兄弟元素文本
let sibling = input.nextSibling;
while (sibling && !optionText) {
if (sibling.nodeType === Node.TEXT_NODE) {
optionText = sibling.textContent.trim();
} else if (sibling.nodeType === Node.ELEMENT_NODE) {
optionText = sibling.textContent.trim();
}
sibling = sibling.nextSibling;
}
}
// 清理选项文本
if (optionText) {
// 移除常见的前缀(A. B. C. D. 或 A、B、C、D、等)
optionText = optionText.replace(/^[A-Z][.、::]\s*/, '').trim();
// 移除多余空白
optionText = optionText.replace(/\s+/g, ' ').trim();
if (optionText.length > 0) {
options.push(optionText);
console.log(`[中泰学堂] 容器${index + 1}: 选项${inputIndex + 1} = ${optionText}`);
} else {
// 如果还是没有文本,使用默认选项标识
const defaultText = `选项${String.fromCharCode(65 + inputIndex)}`;
options.push(defaultText);
console.log(`[中泰学堂] 容器${index + 1}: 选项${inputIndex + 1} = ${defaultText} (默认)`);
}
} else {
// 完全找不到文本时的兜底处理
const fallbackText = `选项${inputIndex + 1}`;
options.push(fallbackText);
console.log(`[中泰学堂] 容器${index + 1}: 选项${inputIndex + 1} = ${fallbackText} (兜底)`);
}
});
if (options.length === 0) {
console.log(`[中泰学堂] 容器${index + 1}: 未获取到选项文本`);
return;
}
// 最终题型判断
let type = 0; // 默认单选
if (isMultiChoice) {
type = 1; // 多选
} else if (options.length === 2 &&
(options.includes('正确') && options.includes('错误'))) {
type = 3; // 判断题:必须同时包含"正确"和"错误"
}
// 获取题目编号
const numberEl = container.querySelector('.w32');
const questionNumber = numberEl ? parseInt(numberEl.textContent.replace('.', '')) : questions.length + 1;
const questionData = {
index: questionNumber,
question: questionText,
options: options,
type: type,
element: container,
radioGroup: radioGroup,
inputs: Array.from(inputs),
isMultiChoice: isMultiChoice
};
questions.push(questionData);
console.log(`[中泰学堂] ✅ 题目${questionNumber}解析完成:`, {
题型: type === 0 ? '单选' : type === 1 ? '多选' : '判断',
选项数: options.length,
input数: inputs.length
});
} catch (e) {
console.error(`[中泰学堂] 处理容器${index + 1}出错:`, e);
}
});
console.log(`[中泰学堂] 🎯 题目扫描完成! 总计: ${questions.length}题`);
const stats = {
单选: questions.filter(q => q.type === 0).length,
多选: questions.filter(q => q.type === 1).length,
判断: questions.filter(q => q.type === 3).length
};
console.log('[中泰学堂] 题型统计:', stats);
// 立即更新面板状态显示
updatePanelStatus(questions, stats);
return questions;
} catch (e) {
console.error('[中泰学堂] 获取题目出错:', e);
return [];
}
}
// 简化选择答案函数 - 解决卡住问题
async function selectAnswer(questionData, answerIndexes) {
try {
console.log('[中泰学堂] === 开始选择答案 ===');
if (!Array.isArray(answerIndexes)) answerIndexes = [answerIndexes];
const inputs = questionData.inputs;
if (!inputs || inputs.length === 0) {
console.error('[中泰学堂] 没有可用的input元素');
return false;
}
console.log(`[中泰学堂] 题型: ${questionData.isMultiChoice ? '多选' : '单选'}`);
console.log(`[中泰学堂] 要选择: [${answerIndexes.join(',')}]`);
console.log(`[中泰学堂] 可用inputs: ${inputs.length}`);
// 直接简单的点击逻辑
for (const index of answerIndexes) {
if (index >= 0 && index < inputs.length) {
const input = inputs[index];
console.log(`[中泰学堂] 点击input[${index}], 当前checked: ${input.checked}`);
// 如果是多选题且已经选中,跳过
if (questionData.isMultiChoice && input.checked) {
console.log(`[中泰学堂] 多选项${index}已选中,跳过`);
continue;
}
// 直接点击
input.click();
console.log(`[中泰学堂] 已点击input[${index}], 新状态: ${input.checked}`);
// 短暂延迟
await sleep(500);
}
}
// 检查最终结果
const finalChecked = inputs.filter(input => input.checked);
console.log(`[中泰学堂] 最终选中${finalChecked.length}个选项`);
return finalChecked.length > 0;
} catch (e) {
console.error('[中泰学堂] 选择答案严重错误:', e);
return false;
}
}
// 高准确率智能答案策略
function getSmartAnswer(question, options, type) {
console.log(`[中泰学堂] 🎯 智能策略 - 题型:${type}, 选项数:${options.length}`);
// 精确答案库 - 根据实际题目
const exactAnswers = {
"下列关于中山装的特点叙述错误的一项是:": "五个对襟扣子", // 中山装是四个对襟扣子
"男士正装标配不包括哪一种?": "浅色毛衣", // 正装不包括毛衣
"正式社交场合不包括下列哪一种?": "家庭聚会", // 家庭聚会不是正式社交场合
"商务正装的特点有哪些?": ["保守", "简洁", "干练"], // 多选:商务正装的特点
"论形象的功能有哪些?": ["表达态度", "控制心理"] // 多选:形象功能
};
// 首先尝试精确匹配
const exactAnswer = exactAnswers[question.trim()];
if (exactAnswer) {
if (Array.isArray(exactAnswer)) {
// 多选题精确答案
const selected = [];
exactAnswer.forEach(answer => {
const index = options.findIndex(opt => opt.includes(answer));
if (index >= 0) selected.push(index);
});
if (selected.length > 0) {
console.log(`[中泰学堂] ✅ 精确匹配多选: [${selected.map(i => options[i]).join(', ')}]`);
return selected;
}
} else {
// 单选题精确答案
const index = options.findIndex(opt => opt.includes(exactAnswer));
if (index >= 0) {
console.log(`[中泰学堂] ✅ 精确匹配单选: ${options[index]}`);
return [index];
}
}
}
if (type === 3) {
// 判断题:关键词判断
const questionLower = question.toLowerCase();
if (questionLower.includes('不') || questionLower.includes('错') ||
questionLower.includes('无法') || questionLower.includes('不正确') ||
questionLower.includes('错误') || questionLower.includes('不太可能')) {
console.log('[中泰学堂] 判断题选择: 错误');
return [1]; // 错误
} else {
console.log('[中泰学堂] 判断题选择: 正确');
return [0]; // 正确
}
} else if (type === 1) {
// 多选题:基于关键词的智能选择
const selected = [];
const questionLower = question.toLowerCase();
// 商务/正装相关题目
if (questionLower.includes('商务') || questionLower.includes('正装')) {
options.forEach((option, index) => {
const optionLower = option.toLowerCase();
if (optionLower.includes('保守') || optionLower.includes('简洁') ||
optionLower.includes('干练') || optionLower.includes('规范') ||
optionLower.includes('专业') || optionLower.includes('庄重')) {
selected.push(index);
}
});
}
// 形象功能相关
if (questionLower.includes('形象') && questionLower.includes('功能')) {
options.forEach((option, index) => {
const optionLower = option.toLowerCase();
if (optionLower.includes('表达') || optionLower.includes('控制') ||
optionLower.includes('沟通') || optionLower.includes('影响')) {
selected.push(index);
}
});
}
// 如果没有匹配到,使用通用策略
if (selected.length === 0) {
// 排除明显错误的选项
options.forEach((option, index) => {
const optionLower = option.toLowerCase();
if (!optionLower.includes('个性') && !optionLower.includes('随意') &&
!optionLower.includes('夸张') && !optionLower.includes('花哨')) {
selected.push(index);
}
});
// 如果还是没有,选择前几个
if (selected.length === 0) {
selected.push(0, 1);
if (options.length > 2) selected.push(2);
}
}
// 确保至少选择2个选项
if (selected.length === 1 && options.length > 1) {
const nextIndex = selected[0] === 0 ? 1 : 0;
selected.push(nextIndex);
}
console.log(`[中泰学堂] 多选题选择: [${selected.join(',')}] = [${selected.map(i => options[i]).join(', ')}]`);
return selected;
} else {
// 单选题:基于题目内容的精确判断
const questionLower = question.toLowerCase();
let selectedIndex = 0;
// 中山装相关 - 错误的是"五个对襟扣子"(应该是四个)
if (questionLower.includes('中山装')) {
options.forEach((option, index) => {
if (option.includes('五个对襟扣子')) {
selectedIndex = index;
}
});
}
// 正装标配 - 不包括"浅色毛衣"
else if (questionLower.includes('正装标配') && questionLower.includes('不包括')) {
options.forEach((option, index) => {
if (option.includes('浅色毛衣') || option.includes('毛衣')) {
selectedIndex = index;
}
});
}
// 正式社交场合 - 不包括"家庭聚会"
else if (questionLower.includes('正式社交场合') && questionLower.includes('不包括')) {
options.forEach((option, index) => {
if (option.includes('家庭聚会') || option.includes('聚会')) {
selectedIndex = index;
}
});
}
// 通用错误选项判断
else if (questionLower.includes('错误') || questionLower.includes('不包括') || questionLower.includes('不')) {
options.forEach((option, index) => {
const optionLower = option.toLowerCase();
if (optionLower.includes('毛衣') || optionLower.includes('个性') ||
optionLower.includes('聚会') || optionLower.includes('家庭') ||
optionLower.includes('随意') || optionLower.includes('五个') ||
optionLower.includes('六个') || optionLower.includes('七个')) {
selectedIndex = index;
}
});
}
console.log(`[中泰学堂] 单选题选择: 选项${selectedIndex + 1} = ${options[selectedIndex]}`);
return [selectedIndex];
}
}
// 轻量答题流程
async function startAnswering() {
const questions = getAllQuestions();
console.log('[中泰学堂] 轻量答题开始,题目数:', questions.length);
if (questions.length === 0) {
console.log('[中泰学堂] 未找到题目');
return;
}
for (let i = 0; i < questions.length && !GLOBAL.stop; i++) {
const question = questions[i];
console.log(`[中泰学堂] === 开始处理第${i+1}题 ===`);
console.log(`题目: ${question.question}`);
console.log(`题型: ${question.type === 0 ? '单选' : question.type === 1 ? '多选' : '判断'}`);
console.log(`选项: [${question.options.join(', ')}]`);
// 首先尝试API搜索,然后使用智能策略
try {
let answerIndexes = [];
let selectedAnswer = '';
let answerSource = '智能策略';
// 尝试API搜索
const searchResult = await searchAnswer({
question: question.question,
options: question.options,
type: question.type
});
if (searchResult.success && searchResult.answers && searchResult.answers.length > 0) {
// API搜索成功,使用API答案
answerSource = searchResult.source || 'API';
console.log(`[中泰学堂] ✅ ${answerSource}返回答案:`, searchResult.answers);
// 将API答案转换为选项索引
const apiAnswers = Array.isArray(searchResult.answers) ? searchResult.answers : [searchResult.answers];
answerIndexes = [];
for (const apiAnswer of apiAnswers) {
// 精确匹配
let index = question.options.findIndex(opt => opt.trim() === apiAnswer.trim());
// 包含匹配
if (index === -1) {
index = question.options.findIndex(opt =>
opt.includes(apiAnswer) || apiAnswer.includes(opt)
);
}
// 字母匹配 (A、B、C、D)
if (index === -1 && apiAnswer.length === 1 && /[A-D]/i.test(apiAnswer)) {
index = apiAnswer.toUpperCase().charCodeAt(0) - 65;
}
if (index >= 0 && index < question.options.length) {
answerIndexes.push(index);
}
}
if (answerIndexes.length > 0) {
selectedAnswer = answerIndexes.map(idx => question.options[idx]).join(', ');
}
}
// 如果API搜索失败或没有找到答案,使用智能策略
if (answerIndexes.length === 0) {
console.log(`[中泰学堂] API未找到答案,使用智能策略`);
answerIndexes = getSmartAnswer(question.question, question.options, question.type);
selectedAnswer = answerIndexes.map(idx => question.options[idx] || `选项${idx + 1}`).join(', ');
answerSource = '智能策略';
}
console.log(`[中泰学堂] 第${i+1}题最终选择 (${answerSource}):`, selectedAnswer);
// 执行选择 - 添加超时保护
console.log(`[中泰学堂] 开始选择答案...`);
const selectPromise = selectAnswer(question, answerIndexes);
const timeoutPromise = new Promise((resolve) => {
setTimeout(() => {
console.log(`[中泰学堂] 选择答案超时,强制继续`);
resolve(false);
}, 10000); // 10秒超时
});
const success = await Promise.race([selectPromise, timeoutPromise]);
console.log(`[中泰学堂] 选择答案完成,结果:`, success);
} catch (selectError) {
console.error(`[中泰学堂] 第${i+1}题选择过程出错:`, selectError);
var success = false;
}
// 更新进度(如果面板存在)
const progressEl = document.querySelector('#zt-progress');
const progressBarEl = document.querySelector('#zt-progress-bar');
const logEl = document.querySelector('#zt-log');
if (progressEl) progressEl.textContent = `${i + 1}/${questions.length}`;
if (progressBarEl) progressBarEl.style.width = `${((i + 1) / questions.length) * 100}%`;
if (logEl) {
const typeIcon = question.type === 0 ? '🔘' : question.type === 1 ? '☑️' : '⚖️';
const statusIcon = success ? '✅' : '❌';
const sourceIcon = answerSource === 'AI' ? '🤖' : answerSource === '题库' ? '📚' : '🧠';
logEl.innerHTML += `
${statusIcon} ${typeIcon} ${sourceIcon} 第${i+1}题: ${selectedAnswer}
`;
logEl.scrollTop = logEl.scrollHeight;
}
console.log(`[中泰学堂] 第${i+1}题处理完成,成功: ${success}`);
// 🛑 在延迟前检查停止状态
if (GLOBAL.stop) {
console.log(`[中泰学堂] 🛑 检测到停止信号,跳过延迟`);
break;
}
console.log(`[中泰学堂] 等待${GLOBAL.delay}ms后处理下一题...`);
await sleep(GLOBAL.delay);
// 🛑 在延迟后再次检查停止状态
if (GLOBAL.stop) {
console.log(`[中泰学堂] 🛑 延迟后检测到停止信号`);
break;
}
console.log(`[中泰学堂] 延迟完成,准备处理下一题`);
}
console.log('[中泰学堂] 轻量答题完成');
// 更新状态
const statusEl = document.querySelector('#zt-status');
if (statusEl) statusEl.textContent = GLOBAL.stop ? '已停止' : '完成';
// 🎯 检查自动提交
const autoSubmitCheckbox = document.querySelector('#auto-submit');
const isAutoSubmit = autoSubmitCheckbox ? autoSubmitCheckbox.checked : false;
console.log('[中泰学堂] 检查自动提交:', isAutoSubmit);
if (isAutoSubmit && !GLOBAL.stop && questions.length > 0) {
console.log('[中泰学堂] 🚀 开始自动提交...');
if (statusEl) statusEl.textContent = '准备提交';
setTimeout(() => {
// 查找提交按钮
const allButtons = document.querySelectorAll('button');
let submitBtn = null;
for (const btn of allButtons) {
if (btn.textContent.includes('提交考试') || btn.textContent.includes('提交')) {
submitBtn = btn;
console.log('[中泰学堂] 找到提交按钮:', btn.textContent);
break;
}
}
if (submitBtn) {
console.log('[中泰学堂] 执行自动提交...');
if (statusEl) statusEl.textContent = '正在提交';
submitBtn.click();
// 处理确认弹窗
setTimeout(() => {
const confirmBtns = document.querySelectorAll('button');
for (const btn of confirmBtns) {
if (btn.textContent.includes('确定') || btn.textContent.includes('确认')) {
console.log('[中泰学堂] 点击确认按钮');
btn.click();
break;
}
}
}, 1000);
} else {
console.log('[中泰学堂] 未找到提交按钮,请手动提交');
if (statusEl) statusEl.textContent = '请手动提交';
}
}, 2000);
} else {
console.log('[中泰学堂] 不执行自动提交 - 自动提交:', isAutoSubmit, '停止状态:', GLOBAL.stop);
}
}
// 移除复杂的页面监听和快捷键,减少性能影响
// 轻量初始化
function init() {
if (GLOBAL.isMatch) return;
GLOBAL.isMatch = true;
console.log('[中泰学堂] 轻量初始化...');
// 简单检查:只要在正确域名就创建面板
if (location.hostname.includes('radnova.cn')) {
// 检查是否已存在面板或悬浮窗,避免重复创建
const existingPanel = document.querySelector('#zt-auto-panel');
const existingPet = document.querySelector('#floating-pet');
if (existingPanel || existingPet) {
console.log('[中泰学堂] 面板已存在,跳过初始化');
return;
}
requestAnimationFrame(() => {
const panel = createVuePanel();
if (panel) {
makeDraggable(panel);
setupPanelControls(panel);
// 面板创建完成后,立即检测题目并更新状态
setTimeout(() => {
console.log('[中泰学堂] 面板初始化完成,开始检测题目...');
try {
const questions = getAllQuestions();
console.log(`[中泰学堂] 初始化检测到${questions.length}道题目`);
} catch (e) {
console.error('[中泰学堂] 初始化题目检测失败:', e);
}
}, 1000); // 1秒后检测,确保页面完全加载
}
});
}
}
// 轻量级面板创建
function createLightPanel() {
console.log('[中泰学堂] 创建轻量级面板...');
// 移除旧面板
const oldPanel = document.querySelector('#zt-auto-panel');
if (oldPanel) oldPanel.remove();
const panel = document.createElement('div');
panel.id = 'zt-auto-panel';
panel.style.cssText = `
position: fixed !important;
top: 80px !important;
right: 80px !important;
width: 280px !important;
background: white !important;
border: 2px solid #1890ff !important;
border-radius: 8px !important;
box-shadow: 0 4px 16px rgba(0,0,0,0.2) !important;
z-index: 2147483647 !important;
font-family: Arial, sans-serif !important;
font-size: 13px !important;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
`;
panel.innerHTML = `
`;
document.body.appendChild(panel);
// 简单拖拽
const header = panel.querySelector('#zt-header');
let isDragging = false;
header.addEventListener('mousedown', (e) => {
isDragging = true;
const rect = panel.getBoundingClientRect();
const offsetX = e.clientX - rect.left;
const offsetY = e.clientY - rect.top;
function onMouseMove(e) {
if (isDragging) {
panel.style.left = (e.clientX - offsetX) + 'px';
panel.style.top = (e.clientY - offsetY) + 'px';
panel.style.right = 'auto';
}
}
function onMouseUp() {
isDragging = false;
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
}
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
});
console.log('[中泰学堂] 轻量级面板创建完成');
// 面板创建完成后立即检测题目
setTimeout(() => {
console.log('[中泰学堂] 轻量级面板初始化完成,开始检测题目...');
try {
const questions = getAllQuestions();
console.log(`[中泰学堂] 轻量级面板检测到${questions.length}道题目`);
} catch (e) {
console.error('[中泰学堂] 轻量级面板题目检测失败:', e);
}
}, 500);
return panel;
}
// 轻量化的页面加载检测
function lightInit() {
// 使用requestIdleCallback避免阻塞主线程
if (window.requestIdleCallback) {
requestIdleCallback(() => {
init();
}, { timeout: 3000 });
} else {
setTimeout(init, 2000);
}
}
// 页面加载检测
if (document.readyState === 'complete') {
lightInit();
} else {
window.addEventListener('load', lightInit);
}
// 备用轻量面板创建
setTimeout(() => {
if (!document.querySelector('#zt-auto-panel')) {
console.log('[中泰学堂] 创建备用轻量面板...');
requestAnimationFrame(() => {
const panel = createLightPanel();
if (panel) {
// 备用面板创建完成后也立即检测题目
setTimeout(() => {
console.log('[中泰学堂] 备用面板创建完成,开始检测题目...');
try {
const questions = getAllQuestions();
console.log(`[中泰学堂] 备用面板检测到${questions.length}道题目`);
} catch (e) {
console.error('[中泰学堂] 备用面板题目检测失败:', e);
}
}, 500);
}
});
}
}, 3000);
// 轻量化SPA页面变化监听
let lastUrl = location.href;
let observerTimer = null;
const lightObserver = new MutationObserver(() => {
// 使用防抖,避免频繁触发
if (observerTimer) clearTimeout(observerTimer);
observerTimer = setTimeout(() => {
const url = location.href;
if (url !== lastUrl) {
lastUrl = url;
console.log('[中泰学堂] 页面URL变化,检查是否需要重新初始化');
// 检查是否已存在面板或悬浮窗
const existingPanel = document.querySelector('#zt-auto-panel');
const existingPet = document.querySelector('#floating-pet');
if (!existingPanel && !existingPet) {
console.log('[中泰学堂] 未发现现有面板,准备重新初始化');
GLOBAL.isMatch = false;
requestIdleCallback ?
requestIdleCallback(() => init(), { timeout: 2000 }) :
setTimeout(init, 1000);
} else {
console.log('[中泰学堂] 面板已存在,跳过重新初始化');
}
}
}, 500);
});
// 只监听关键变化,减少性能影响
lightObserver.observe(document.body, {
childList: true,
subtree: false // 不监听深层子树
});
// 修复的全局控制函数
window.ZTXT_startAnswering = async function() {
console.log('[中泰学堂] 🚀 开始答题按钮被点击!');
// 更新面板状态
const statusEl = document.querySelector('#zt-status, #status-indicator');
const statusTextEl = document.querySelector('#status-text');
const progressEl = document.querySelector('#zt-progress, #progress-text');
const progressBarEl = document.querySelector('#zt-progress-bar, #progress-bar');
const logEl = document.querySelector('#zt-log, #answer-log');
const startBtn = document.querySelector('#zt-start-btn, #start-btn');
const stopBtn = document.querySelector('#zt-stop-btn, #stop-btn');
console.log('[中泰学堂] 面板元素检查:');
console.log(' 状态元素:', !!statusEl);
console.log(' 进度元素:', !!progressEl);
console.log(' 日志元素:', !!logEl);
console.log(' 开始按钮:', !!startBtn);
console.log(' 停止按钮:', !!stopBtn);
if (statusEl) {
statusEl.textContent = '运行中';
statusEl.style.background = '#1890ff';
}
if (statusTextEl) statusTextEl.textContent = '正在搜索题目...';
if (startBtn) startBtn.disabled = true;
if (stopBtn) stopBtn.disabled = false;
GLOBAL.stop = false;
const questions = getAllQuestions();
console.log('[中泰学堂] 找到题目数量:', questions.length);
// 统计题型
const singleCount = questions.filter(q => q.type === 0).length;
const multiCount = questions.filter(q => q.type === 1).length;
const judgeCount = questions.filter(q => q.type === 3).length;
console.log('[中泰学堂] 题型统计:');
console.log(` 单选题: ${singleCount}题`);
console.log(` 多选题: ${multiCount}题`);
console.log(` 判断题: ${judgeCount}题`);
// 更新状态显示
if (statusTextEl) {
statusTextEl.textContent = `找到${questions.length}题 (单选${singleCount} 多选${multiCount} 判断${judgeCount})`;
}
// 更新题型统计显示
const singleCountEl = document.querySelector('#single-count');
const multiCountEl = document.querySelector('#multi-count');
const judgeCountEl = document.querySelector('#judge-count');
if (singleCountEl) singleCountEl.textContent = singleCount;
if (multiCountEl) multiCountEl.textContent = multiCount;
if (judgeCountEl) judgeCountEl.textContent = judgeCount;
if (questions.length === 0) {
if (statusEl) statusEl.textContent = '未找到题目';
if (statusEl) statusEl.style.background = '#ff4d4f';
if (logEl) logEl.innerHTML = '❌ 未找到题目,请确认在考试页面';
if (startBtn) startBtn.disabled = false;
if (stopBtn) stopBtn.disabled = true;
return;
}
if (progressEl) progressEl.textContent = `0/${questions.length}`;
if (logEl) logEl.innerHTML = '开始答题...
';
for (let i = 0; i < questions.length && !GLOBAL.stop; i++) {
const question = questions[i];
// 更新状态
if (statusEl) statusEl.textContent = `答第${i+1}题`;
if (statusTextEl) statusTextEl.textContent = `正在处理第${i+1}题: ${question.question.substring(0, 20)}...`;
const answerIndexes = getSmartAnswer(question.question, question.options, question.type);
const selectedAnswer = answerIndexes.map(idx => question.options[idx] || `选项${idx + 1}`).join(', ');
console.log(`[中泰学堂] 第${i+1}题选择:`, selectedAnswer);
// 执行选择
const success = await selectAnswer(question, answerIndexes);
console.log(`[中泰学堂] 第${i+1}题选择结果:`, success);
// 更新进度
if (progressEl) progressEl.textContent = `${i + 1}/${questions.length}`;
if (progressBarEl) progressBarEl.style.width = `${((i + 1) / questions.length) * 100}%`;
if (logEl) {
const typeIcon = question.type === 0 ? '🔘' : question.type === 1 ? '☑️' : '⚖️';
const status = success ? '✅' : '❌';
logEl.innerHTML += `
${status} ${typeIcon} 第${i+1}题: ${selectedAnswer}
`;
logEl.scrollTop = logEl.scrollHeight;
}
await sleep(1500); // 1.5秒延迟
}
// 完成状态
if (statusEl) {
statusEl.textContent = GLOBAL.stop ? '已停止' : '答题完成';
statusEl.style.background = GLOBAL.stop ? '#faad14' : '#52c41a';
}
if (statusTextEl) {
statusTextEl.textContent = GLOBAL.stop ? '用户停止了答题' : `已完成${questions.length}道题目`;
}
if (startBtn) startBtn.disabled = false;
if (stopBtn) stopBtn.disabled = true;
console.log('[中泰学堂] 答题流程结束');
// 检查自动提交
const autoSubmitCheckbox = document.querySelector('#auto-submit');
const isAutoSubmit = autoSubmitCheckbox ? autoSubmitCheckbox.checked : false;
console.log('[中泰学堂] 自动提交状态:', isAutoSubmit);
if (isAutoSubmit && !GLOBAL.stop && questions.length > 0) {
console.log('[中泰学堂] 准备自动提交...');
if (statusEl) statusEl.textContent = '准备提交';
if (statusTextEl) statusTextEl.textContent = '3秒后自动提交考试...';
setTimeout(() => {
console.log('[中泰学堂] 开始查找提交按钮...');
// 修正提交按钮查找逻辑
let submitBtn = null;
// 方法1: 直接查找所有按钮,检查文本内容
const allButtons = document.querySelectorAll('button');
console.log('[中泰学堂] 页面总按钮数:', allButtons.length);
for (const btn of allButtons) {
const btnText = btn.textContent.trim();
console.log('[中泰学堂] 检查按钮:', btnText);
if (btnText.includes('提交考试') || btnText.includes('提交') || btnText === '提交考试') {
submitBtn = btn;
console.log('[中泰学堂] 找到提交按钮:', btnText);
break;
}
}
// 方法2: 通过class查找
if (!submitBtn) {
const primaryButtons = document.querySelectorAll('.yxtf-button--primary, .yxtf-button--larger');
console.log('[中泰学堂] 主要按钮数:', primaryButtons.length);
for (const btn of primaryButtons) {
console.log('[中泰学堂] 主要按钮文本:', btn.textContent.trim());
if (btn.textContent.includes('提交')) {
submitBtn = btn;
break;
}
}
}
// 方法3: 根据页面右侧的橙色按钮
if (!submitBtn) {
const orangeButtons = document.querySelectorAll('button[style*="background"], button[class*="orange"]');
for (const btn of orangeButtons) {
if (btn.textContent.includes('提交')) {
submitBtn = btn;
break;
}
}
}
console.log('[中泰学堂] 找到提交按钮:', !!submitBtn);
if (submitBtn) {
console.log('[中泰学堂] 执行自动提交...');
if (statusEl) statusEl.textContent = '正在提交';
if (statusTextEl) statusTextEl.textContent = '正在提交考试,请稍候...';
// 点击提交按钮
submitBtn.click();
console.log('[中泰学堂] 提交按钮已点击');
// 处理可能的确认弹窗
setTimeout(() => {
const allButtons = document.querySelectorAll('.yxtf-button--primary, .yxt-button--primary, button');
let confirmBtn = null;
for (const btn of allButtons) {
if (btn.textContent.includes('确定') || btn.textContent.includes('确认')) {
confirmBtn = btn;
break;
}
}
if (confirmBtn) {
console.log('[中泰学堂] 点击确认按钮:', confirmBtn.textContent);
confirmBtn.click();
// 提交完成后重置状态
setTimeout(() => {
handleSubmitComplete();
}, 3000);
} else {
// 如果没有确认弹窗,直接处理提交完成
setTimeout(() => {
handleSubmitComplete();
}, 2000);
}
}, 1000);
} else {
console.log('[中泰学堂] ❌ 未找到提交按钮');
if (statusTextEl) statusTextEl.textContent = '未找到提交按钮,请手动提交';
}
}, 3000); // 3秒后提交
} else {
console.log('[中泰学堂] 不执行自动提交 - 自动提交:', isAutoSubmit, '停止状态:', GLOBAL.stop);
}
};
window.ZTXT_stopAnswering = function() {
console.log('[中泰学堂] 停止答题');
GLOBAL.stop = true;
const statusEl = document.querySelector('#zt-status');
const startBtn = document.querySelector('#zt-start-btn, #start-btn');
const stopBtn = document.querySelector('#zt-stop-btn, #stop-btn');
if (statusEl) {
statusEl.textContent = '已停止';
statusEl.style.background = '#faad14';
}
if (startBtn) startBtn.disabled = false;
if (stopBtn) stopBtn.disabled = true;
};
// 全局调试接口
window.ZTXT_DEBUG = {
isExamPage: isExamPage,
getAllQuestions: getAllQuestions,
createLightPanel: createLightPanel,
showPanel: () => {
// 强制显示面板的最简单方法
let panel = document.querySelector('#zt-auto-panel');
if (!panel) {
// 如果没有面板,创建轻量面板
panel = createLightPanel();
}
if (panel) {
panel.style.display = 'block !important';
panel.style.visibility = 'visible !important';
panel.style.opacity = '1 !important';
panel.style.zIndex = '2147483647 !important';
}
return panel;
},
reinit: () => {
GLOBAL.isMatch = false;
init();
},
GLOBAL: GLOBAL
};
// 确保全局函数正确定义
console.log('[中泰学堂] 🔧 确保全局函数定义...');
// 重新定义全局函数,确保可用
if (typeof window.ZTXT_startAnswering !== 'function') {
console.log('[中泰学堂] ⚠️ 重新定义ZTXT_startAnswering函数');
window.ZTXT_startAnswering = async function() {
console.log('[中泰学堂] 🚀 全局函数被调用!');
const questions = getAllQuestions();
if (questions.length === 0) {
console.log('[中泰学堂] 未找到题目');
alert('未找到题目,请确认在考试页面');
return;
}
console.log(`[中泰学堂] 开始处理${questions.length}题`);
for (let i = 0; i < questions.length; i++) {
const question = questions[i];
console.log(`[中泰学堂] 处理第${i+1}题:`, question.question);
const answerIndexes = getSmartAnswer(question.question, question.options, question.type);
await selectAnswer(question, answerIndexes);
await sleep(1500);
}
console.log('[中泰学堂] 答题完成!');
};
}
if (typeof window.ZTXT_stopAnswering !== 'function') {
window.ZTXT_stopAnswering = function() {
GLOBAL.stop = true;
console.log('[中泰学堂] 已停止');
};
}
// 控制台输出 - 中泰学堂助手
console.log('[中泰学堂] 🚀 中泰学堂助手已加载 - v2.3.0');
console.log('[中泰学堂] 🎨 新特性:答题 + 挂机检测 + 自动学习');
console.log('[中泰学堂] 🔧 主要功能:');
console.log(' 📝 智能答题 - 支持单选/多选/判断题');
console.log(' 📺 挂机检测 - 自动点击"继续学习"');
console.log(' ⏭️ 自动下一个 - 完成后自动进入下一课');
console.log(' 🎬 视频进度检测 - 视频完成但倒计时未结束时回退');
console.log(' ⚡ 自动最高倍速 - 自动识别并切换到最高播放倍速');
console.log(' 🔇 自动禁音 - 自动禁用所有视频和音频声音');
console.log(' 🎨 拟态化设计 - 现代化立体效果');
console.log(' 📱 可最小化 - 悬浮小宠物');
console.log(' 🏷️ 标签页设计 - 视频学习和考试答题分离');
console.log('[中泰学堂] 💡 使用方法:');
console.log(' 1. 脚本加载后自动禁音所有媒体');
console.log(' 2. 默认显示"视频学习"标签页');
console.log(' 3. 勾选需要的功能(挂机检测/自动下一个/视频进度检测/自动最高倍速)');
console.log(' 4. 点击"考试答题"标签页进行答题设置');
console.log(' 5. 在考试页面点击"开始答题"');
console.log(' 6. 点击右上角 − 按钮可最小化');
console.log('[中泰学堂] 🔧 调试命令:');
console.log(' 🎬 视频状态调试: window.ZTXT_debugVideoStatus()');
console.log(' 🔇 音量控制调试: window.ZTXT_debugVolumeControl()');
console.log(' ⏰ 倒计时格式调试: window.ZTXT_debugCountdownFormat()');
console.log(' 🧪 测试倒计时匹配: window.ZTXT_testCountdownMatch("1小时 3分钟 12秒")');
console.log(' 📋 查看题目: window.ZTXT_showQuestions()');
console.log(' 🧪 快速测试: window.ZTXT_quickTest()');
// 简化的快速测试
window.ZTXT_quickTest = async function() {
console.log('[中泰学堂] 🚀 快速测试开始');
const questions = getAllQuestions();
if (questions.length === 0) {
console.log('[中泰学堂] ❌ 未找到题目');
return;
}
console.log(`[中泰学堂] ✅ 找到${questions.length}题,开始快速答题`);
// 只测试第1题
if (questions.length > 0) {
const question = questions[0];
console.log(`[中泰学堂] 测试第1题:`, question.question);
if (question.inputs && question.inputs.length > 0) {
console.log(`[中泰学堂] 点击第一个选项`);
question.inputs[0].click();
await sleep(1000);
console.log(`[中泰学堂] 选择结果:`, question.inputs[0].checked);
}
}
console.log('[中泰学堂] 快速测试完成');
};
// 查看当前题目和选项(调试用)
window.ZTXT_showQuestions = function() {
const questions = getAllQuestions();
console.log('[中泰学堂] 📋 当前页面题目列表:');
questions.forEach((q, i) => {
console.log(`\n=== 第${i+1}题 ===`);
console.log(`题目: ${q.question}`);
console.log(`类型: ${q.type === 0 ? '单选' : q.type === 1 ? '多选' : '判断'}`);
console.log(`选项:`);
q.options.forEach((opt, j) => {
console.log(` ${String.fromCharCode(65 + j)}. ${opt}`);
});
});
return questions;
};
// 调试视频和倒计时状态
window.ZTXT_debugVideoStatus = function() {
console.log('\n🎬 ============ 视频状态调试 ============');
const videos = document.querySelectorAll('video');
console.log(`📺 发现 ${videos.length} 个视频元素:`);
videos.forEach((video, index) => {
console.log(`\n--- 视频${index + 1} ---`);
console.log(`时长: ${video.duration ? video.duration.toFixed(1) : '未知'}秒`);
console.log(`当前进度: ${video.currentTime.toFixed(1)}秒`);
console.log(`剩余时间: ${video.duration ? (video.duration - video.currentTime).toFixed(1) : '未知'}秒`);
console.log(`播放状态: ${video.paused ? '暂停' : '播放中'}`);
console.log(`是否结束: ${video.ended ? '是' : '否'}`);
console.log(`是否静音: ${video.muted ? '是' : '否'}`);
});
// 查找倒计时元素
const countdownElements = document.querySelectorAll('.yxt-color-warning, [class*="countdown"], [class*="timer"], span');
console.log(`\n⏰ 检查 ${countdownElements.length} 个可能的倒计时元素:`);
let foundCountdown = false;
countdownElements.forEach((element, index) => {
const text = element.textContent || '';
// 检查是否包含时间格式
if (text.match(/\d+\s*分/) || text.match(/\d+\s*秒/) || text.match(/\d+:\d+/)) {
console.log(`\n--- 倒计时元素${index + 1} ---`);
console.log(`文本: "${text}"`);
console.log(`类名: ${element.className}`);
// 尝试解析时间
let timeMatch = text.match(/(\d+)分钟?\s*(\d+)?秒?/) ||
text.match(/(\d+):\s*(\d+)/) ||
text.match(/还有\s*(\d+)\s*分\s*(\d+)?\s*秒?/) ||
text.match(/剩余\s*(\d+)\s*分\s*(\d+)?\s*秒?/) ||
text.match(/(\d+)\s*分钟?\s*(\d+)\s*秒/) ||
text.match(/(\d+)\s*分\s*(\d+)\s*秒/) ||
text.match(/(\d+)分(\d+)秒/) ||
text.match(/还需\s*(\d+)\s*分\s*(\d+)?\s*秒?/);
if (timeMatch) {
const minutes = parseInt(timeMatch[1]) || 0;
const seconds = parseInt(timeMatch[2]) || 0;
const totalSeconds = minutes * 60 + seconds;
console.log(`解析结果: ${minutes}分${seconds}秒 = ${totalSeconds}秒`);
foundCountdown = true;
}
}
});
if (!foundCountdown) {
console.log('❌ 未找到有效的倒计时元素');
}
console.log('============ 调试完成 ============\n');
return {
videoCount: videos.length,
countdownElements: countdownElements.length,
foundCountdown: foundCountdown
};
};
// 调试音量控制元素
window.ZTXT_debugVolumeControl = function() {
console.log('\n🔇 ============ 音量控制调试 ============');
// 检查音量按钮
const volumeButtons = document.querySelectorAll('.ml-volume_button, [class*="volume"], [class*="mute"]');
console.log(`🔘 发现 ${volumeButtons.length} 个音量按钮:`);
volumeButtons.forEach((button, index) => {
console.log(`\n--- 音量按钮${index + 1} ---`);
console.log(`类名: ${button.className}`);
console.log(`文本: "${button.textContent}"`);
console.log(`标题: "${button.title}"`);
console.log(`是否静音: ${button.classList.contains('muted') ? '是' : '否'}`);
});
// 检查音量百分比元素
const volumePercents = document.querySelectorAll('.ml-volume_percent');
console.log(`\n📊 发现 ${volumePercents.length} 个音量百分比元素:`);
volumePercents.forEach((element, index) => {
console.log(`\n--- 音量百分比${index + 1} ---`);
console.log(`类名: ${element.className}`);
console.log(`文本: "${element.textContent}"`);
const percentMatch = element.textContent.match(/(\d+)%/);
if (percentMatch) {
console.log(`当前音量: ${percentMatch[1]}%`);
}
});
// 检查音量滑块
const volumeSliders = document.querySelectorAll('input[type="range"], .ml-volume_scroll-wrapper input');
console.log(`\n🎚️ 发现 ${volumeSliders.length} 个音量滑块:`);
volumeSliders.forEach((slider, index) => {
console.log(`\n--- 音量滑块${index + 1} ---`);
console.log(`类名: ${slider.className}`);
console.log(`当前值: ${slider.value}`);
console.log(`最小值: ${slider.min}`);
console.log(`最大值: ${slider.max}`);
});
// 检查视频元素的音量状态
const videos = document.querySelectorAll('video');
console.log(`\n📹 发现 ${videos.length} 个视频元素:`);
videos.forEach((video, index) => {
console.log(`\n--- 视频${index + 1} ---`);
console.log(`是否静音: ${video.muted ? '是' : '否'}`);
console.log(`音量: ${(video.volume * 100).toFixed(0)}%`);
console.log(`播放状态: ${video.paused ? '暂停' : '播放中'}`);
});
console.log('============ 调试完成 ============\n');
return {
volumeButtons: volumeButtons.length,
volumePercents: volumePercents.length,
volumeSliders: volumeSliders.length,
videos: videos.length
};
};
// 调试倒计时格式解析(增强版)
window.ZTXT_debugCountdownFormat = function() {
console.log('\n⏰ ============ 倒计时格式调试 ============');
const countdownElements = document.querySelectorAll('.yxt-color-warning, [class*="countdown"], [class*="timer"], span');
console.log(`🔍 发现 ${countdownElements.length} 个可能的倒计时元素:`);
let foundValidCountdown = false;
countdownElements.forEach((element, index) => {
const text = element.textContent || '';
// 检查是否包含时间格式
if (text.match(/\d+/) && (text.includes('分') || text.includes('秒') || text.includes(':') || text.includes('小时'))) {
console.log(`\n--- 倒计时元素${index + 1} ---`);
console.log(`原始文本: "${text}"`);
console.log(`类名: ${element.className}`);
// 测试所有时间格式匹配(按优先级排序)
const formats = [
{ name: 'X分钟 Y秒(您的格式)', regex: /(\d+)分钟\s+(\d+)秒/ },
{ name: 'X小时Y分钟Z秒', regex: /(\d+)小时\s*(\d+)分钟?\s*(\d+)?秒?/ },
{ name: 'HH:MM:SS', regex: /(\d+):\s*(\d+):\s*(\d+)/ },
{ name: 'X分钟Y秒', regex: /(\d+)分钟?\s*(\d+)?秒?/ },
{ name: 'MM:SS', regex: /(\d+):\s*(\d+)/ },
{ name: '还有X分Y秒', regex: /还有\s*(\d+)\s*分\s*(\d+)?\s*秒?/ },
{ name: 'X分 Y秒', regex: /(\d+)\s*分\s*(\d+)\s*秒/ },
{ name: 'X分Y秒', regex: /(\d+)分(\d+)秒/ }
];
let matched = false;
for (const format of formats) {
const match = text.match(format.regex);
if (match) {
console.log(`✅ 匹配格式: ${format.name}`);
console.log(`匹配结果: [${match.slice(1).join(', ')}]`);
// 计算总秒数
let totalSeconds = 0;
if (format.name.includes('小时') || format.name === 'HH:MM:SS') {
const hours = parseInt(match[1]) || 0;
const minutes = parseInt(match[2]) || 0;
const seconds = parseInt(match[3]) || 0;
// 验证数据合理性
if (hours <= 24 && minutes <= 59 && seconds <= 59) {
totalSeconds = hours * 3600 + minutes * 60 + seconds;
console.log(`解析为: ${hours}时${minutes}分${seconds}秒 = ${totalSeconds}秒`);
} else {
console.log(`❌ 数据异常: ${hours}时${minutes}分${seconds}秒`);
continue;
}
} else {
const minutes = parseInt(match[1]) || 0;
const seconds = parseInt(match[2]) || 0;
// 验证数据合理性
if (minutes <= 999 && seconds <= 59) {
totalSeconds = minutes * 60 + seconds;
console.log(`解析为: ${minutes}分${seconds}秒 = ${totalSeconds}秒`);
} else {
console.log(`❌ 数据异常: ${minutes}分${seconds}秒`);
continue;
}
}
// 格式化显示
const hours = Math.floor(totalSeconds / 3600);
const mins = Math.floor((totalSeconds % 3600) / 60);
const secs = totalSeconds % 60;
if (hours > 0) {
console.log(`格式化显示: ${hours.toString().padStart(2, '0')}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`);
} else {
console.log(`格式化显示: ${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`);
}
matched = true;
foundValidCountdown = true;
break;
}
}
if (!matched) {
console.log(`❌ 未匹配任何格式`);
}
}
});
if (!foundValidCountdown) {
console.log('❌ 未找到有效的倒计时元素');
}
console.log('============ 倒计时格式调试完成 ============\n');
return {
totalElements: countdownElements.length,
foundValidCountdown: foundValidCountdown
};
};
// 实时倒计时匹配测试
window.ZTXT_testCountdownMatch = function(testText) {
console.log(`\n🧪 测试倒计时文本: "${testText || '1小时 3分钟 12秒'}"`);
const text = testText || '1小时 3分钟 12秒';
// 按优先级测试所有格式
const formats = [
{ name: 'X小时 Y分钟 Z秒(您的最新格式)', regex: /(\d+)小时\s+(\d+)分钟\s+(\d+)秒/ },
{ name: 'X分钟 Y秒', regex: /(\d+)分钟\s+(\d+)秒/ },
{ name: 'X小时Y分钟Z秒', regex: /(\d+)小时\s*(\d+)分钟?\s*(\d+)?秒?/ },
{ name: 'HH:MM:SS', regex: /(\d+):\s*(\d+):\s*(\d+)/ },
{ name: 'X分钟Y秒', regex: /(\d+)分钟?\s*(\d+)?秒?/ },
{ name: 'MM:SS', regex: /(\d+):\s*(\d+)/ }
];
for (const format of formats) {
const match = text.match(format.regex);
if (match) {
console.log(`✅ 匹配格式: ${format.name}`);
console.log(`匹配结果: [${match.slice(1).join(', ')}]`);
// 计算总秒数
let totalSeconds = 0;
if (format.name.includes('小时') || format.name === 'HH:MM:SS') {
const hours = parseInt(match[1]) || 0;
const minutes = parseInt(match[2]) || 0;
const seconds = parseInt(match[3]) || 0;
totalSeconds = hours * 3600 + minutes * 60 + seconds;
console.log(`解析为: ${hours}时${minutes}分${seconds}秒 = ${totalSeconds}秒`);
} else {
const minutes = parseInt(match[1]) || 0;
const seconds = parseInt(match[2]) || 0;
totalSeconds = minutes * 60 + seconds;
console.log(`解析为: ${minutes}分${seconds}秒 = ${totalSeconds}秒`);
}
// 格式化显示
const hours = Math.floor(totalSeconds / 3600);
const mins = Math.floor((totalSeconds % 3600) / 60);
const secs = totalSeconds % 60;
if (hours > 0) {
console.log(`面板显示: ${hours.toString().padStart(2, '0')}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`);
} else {
console.log(`面板显示: ${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`);
}
return totalSeconds;
}
}
console.log('❌ 未匹配任何格式');
return 0;
};
// 🔧 立即定义全局函数(确保面板按钮可用)
defineGlobalFunctions();
// 立即尝试初始化(无论什么条件)
setTimeout(() => {
console.log('[中泰学堂] 1秒后强制初始化...');
if (!document.querySelector('#zt-auto-panel')) {
GLOBAL.isMatch = false;
init();
}
}, 1000);
// 5秒后再次尝试(确保页面完全加载)
setTimeout(() => {
if (!document.querySelector('#zt-auto-panel')) {
console.log('[中泰学堂] 5秒后再次初始化...');
GLOBAL.isMatch = false;
init();
}
}, 5000);
// 强制绑定按钮事件(兜底方案)
setTimeout(() => {
const startBtn = document.querySelector('#start-btn');
if (startBtn) {
console.log('[中泰学堂] 强制绑定开始按钮事件');
startBtn.addEventListener('click', function(e) {
e.preventDefault();
console.log('[中泰学堂] 事件监听器触发');
window.ZTXT_startAnswering();
});
// 测试按钮是否可点击
startBtn.style.pointerEvents = 'auto';
startBtn.style.cursor = 'pointer';
}
const stopBtn = document.querySelector('#stop-btn');
if (stopBtn) {
stopBtn.addEventListener('click', function(e) {
e.preventDefault();
window.ZTXT_stopAnswering();
});
}
console.log('[中泰学堂] 按钮事件绑定完成');
}, 4000);
// 添加键盘快捷键作为备用
document.addEventListener('keydown', function(e) {
if (e.ctrlKey && e.altKey && e.key === 's') {
e.preventDefault();
console.log('[中泰学堂] 快捷键触发答题');
window.ZTXT_startAnswering();
}
});
// 强制定义全局函数(确保可用)
window.ZTXT_startAnswering = async function() {
console.log('[中泰学堂] 🚀 AI答题开始!');
const questions = getAllQuestions();
if (questions.length === 0) {
alert('未找到题目!');
return;
}
console.log(`[中泰学堂] 找到${questions.length}题,开始AI答题...`);
// 更新面板显示
const statusEl = document.querySelector('#zt-status');
const progressEl = document.querySelector('#zt-progress');
const progressBarEl = document.querySelector('#zt-progress-bar');
const logEl = document.querySelector('#zt-log');
if (statusEl) {
statusEl.textContent = '运行中';
statusEl.style.background = '#1890ff';
}
if (progressEl) progressEl.textContent = `0/${questions.length}`;
if (logEl) logEl.innerHTML = '🤖 AI答题开始...
';
for (let i = 0; i < questions.length && !GLOBAL.stop; i++) {
// 🛑 在每题开始前检查停止状态
if (GLOBAL.stop) {
console.log(`[中泰学堂] 🛑 检测到停止信号,在第${i+1}题前停止`);
break;
}
const question = questions[i];
console.log(`[中泰学堂] 处理第${i+1}题: ${question.question}`);
// 优先使用AI(如果启用)
const enableAI = document.querySelector('#enable-ai')?.checked;
let answerIndexes = [];
let answerSource = '智能';
if (enableAI) {
try {
const searchResult = await searchAnswer({
question: question.question,
options: question.options,
type: question.type
});
if (searchResult.success && searchResult.answers) {
console.log('[中泰学堂] AI返回原始答案:', searchResult.answers);
// 转换AI答案为选项索引
for (const ans of searchResult.answers) {
let idx = -1;
// 方法1: 字母匹配 (A, B, C, D)
if (ans.length === 1 && /[A-D]/i.test(ans)) {
idx = ans.toUpperCase().charCodeAt(0) - 65;
console.log(`[中泰学堂] 字母${ans}转换为索引${idx}`);
}
// 方法2: 精确文本匹配
else {
idx = question.options.findIndex(opt =>
opt.trim() === ans.trim() ||
opt.includes(ans) ||
ans.includes(opt)
);
console.log(`[中泰学堂] 文本"${ans}"匹配到索引${idx}`);
}
if (idx >= 0 && idx < question.options.length && !answerIndexes.includes(idx)) {
answerIndexes.push(idx);
console.log(`[中泰学堂] ✅ 添加选项${idx}: ${question.options[idx]}`);
}
}
if (answerIndexes.length > 0) {
answerSource = 'AI';
console.log(`[中泰学堂] ✅ AI答案转换成功: [${answerIndexes.join(',')}]`);
} else {
console.log('[中泰学堂] ⚠️ AI答案转换失败,使用智能策略');
}
}
} catch (e) {
console.log('[中泰学堂] AI调用失败,使用智能策略:', e);
}
}
// 如果AI没找到答案,使用智能策略
if (answerIndexes.length === 0) {
answerIndexes = getSmartAnswer(question.question, question.options, question.type);
answerSource = '智能';
}
const selectedAnswer = answerIndexes.map(idx => question.options[idx]).join(', ');
console.log(`[中泰学堂] 第${i+1}题选择(${answerSource}): 索引[${answerIndexes.join(',')}] = ${selectedAnswer}`);
// 执行选择
await selectAnswer(question, answerIndexes);
// 更新进度
if (progressEl) progressEl.textContent = `${i+1}/${questions.length}`;
if (progressBarEl) progressBarEl.style.width = `${((i+1)/questions.length)*100}%`;
if (logEl) {
const icon = answerSource === 'AI' ? '🤖' : '🧠';
const typeIcon = question.type === 0 ? '🔘' : question.type === 1 ? '☑️' : '⚖️';
logEl.innerHTML += `
✅ ${typeIcon} ${icon} 第${i+1}题: ${selectedAnswer}
`;
logEl.scrollTop = logEl.scrollHeight;
}
await sleep(1500);
}
console.log('[中泰学堂] AI答题完成!');
if (statusEl) {
statusEl.textContent = '答题完成';
statusEl.style.background = '#52c41a';
}
// 检查自动提交
const autoSubmitCheckbox = document.querySelector('#auto-submit');
const isAutoSubmit = autoSubmitCheckbox ? autoSubmitCheckbox.checked : false;
console.log('[中泰学堂] 检查自动提交:', isAutoSubmit);
if (isAutoSubmit && !GLOBAL.stop) {
console.log('[中泰学堂] 🚀 开始自动提交...');
if (statusEl) statusEl.textContent = '准备提交';
setTimeout(() => {
// 查找提交按钮
const allButtons = document.querySelectorAll('button');
let submitBtn = null;
for (const btn of allButtons) {
if (btn.textContent.includes('提交考试') || btn.textContent.includes('提交')) {
submitBtn = btn;
console.log('[中泰学堂] 找到提交按钮:', btn.textContent);
break;
}
}
if (submitBtn) {
console.log('[中泰学堂] 执行自动提交...');
if (statusEl) statusEl.textContent = '正在提交';
submitBtn.click();
// 处理确认弹窗
setTimeout(() => {
const confirmBtns = document.querySelectorAll('button');
for (const btn of confirmBtns) {
if (btn.textContent.includes('确定') || btn.textContent.includes('确认')) {
console.log('[中泰学堂] 点击确认按钮');
btn.click();
// 提交完成后重置状态
setTimeout(() => {
handleSubmitComplete();
}, 3000);
break;
}
}
// 如果没有确认弹窗,直接处理提交完成
setTimeout(() => {
handleSubmitComplete();
}, 2000);
}, 1000);
} else {
console.log('[中泰学堂] 未找到提交按钮,请手动提交');
if (statusEl) statusEl.textContent = '请手动提交';
}
}, 2000);
}
};
// 处理提交完成后的状态重置
function handleSubmitComplete() {
console.log('[中泰学堂] 🎉 提交完成,开始重置状态...');
try {
// 重置全局状态
GLOBAL.stop = false;
GLOBAL.currentQuestionIndex = 0;
// 获取UI元素
const statusEl = document.querySelector('#zt-status, #status-indicator');
const statusTextEl = document.querySelector('#status-text, #zt-status-text');
const progressEl = document.querySelector('#zt-progress, #progress-text');
const progressBarEl = document.querySelector('#zt-progress-bar');
const logEl = document.querySelector('#zt-log, #answer-log');
const startBtn = document.querySelector('#zt-start-btn, #start-btn');
const stopBtn = document.querySelector('#zt-stop-btn, #stop-btn');
// 获取统计元素
const singleCountEl = document.querySelector('#single-count');
const multiCountEl = document.querySelector('#multi-count');
const judgeCountEl = document.querySelector('#judge-count');
// 重置状态显示
if (statusEl) {
statusEl.textContent = '准备就绪';
statusEl.style.background = '#52c41a';
}
if (statusTextEl) {
statusTextEl.textContent = '等待开始答题...';
}
// 重置进度显示
if (progressEl) progressEl.textContent = '0/0';
if (progressBarEl) progressBarEl.style.width = '0%';
// 清空答题记录
if (logEl) {
logEl.innerHTML = '
暂无答题记录
';
}
// 重置按钮状态
if (startBtn) startBtn.disabled = false;
if (stopBtn) stopBtn.disabled = true;
// 重置题型统计
if (singleCountEl) singleCountEl.textContent = '0';
if (multiCountEl) multiCountEl.textContent = '0';
if (judgeCountEl) judgeCountEl.textContent = '0';
console.log('[中泰学堂] ✅ 状态重置完成,可以开始新的答题');
} catch (error) {
console.error('[中泰学堂] 状态重置出错:', error);
}
}
window.ZTXT_stopAnswering = function() {
GLOBAL.stop = true;
console.log('[中泰学堂] 答题已停止');
};
console.log('[中泰学堂] ✅ 全局函数强制定义完成');
})();