// ==UserScript== // @name 中泰学堂 // @namespace http://tampermonkey.net/ // @version 2.1.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}] 📺 自动点击"继续学习"
`; logEl.scrollTop = logEl.scrollHeight; } break; } } }, 3000); // 每3秒检查一次 } // 停止挂机检测监控 function stopAutoStudyMonitor() { if (autoStudyInterval) { clearInterval(autoStudyInterval); autoStudyInterval = null; console.log('[中泰学堂] 📺 停止挂机检测监控'); } } // 启动自动下一个监控(优化版 - 只点击一次) let hasClickedNext = false; // 防止重复点击的标志 function startAutoNextMonitor() { if (autoNextInterval) { clearInterval(autoNextInterval); } console.log('[中泰学堂] ⏭️ 启动自动下一个监控(单次点击版)'); hasClickedNext = false; // 重置标志 autoNextInterval = setInterval(() => { // 如果已经点击过,跳过检测 if (hasClickedNext) { return; } // 查找完成学习相关的弹窗和按钮 const allElements = document.querySelectorAll('*'); let foundCompleteDialog = false; // 检查是否有"太棒了"、"已完成学习"等文本 for (const element of allElements) { const text = element.textContent || ''; if (text.includes('太棒了') || text.includes('已完成学习') || text.includes('学习完成') || text.includes('恭喜') || text.includes('完成了') || text.includes('学习结束') || text.includes('您已完成当前任务')) { foundCompleteDialog = true; console.log('[中泰学堂] ⏭️ 发现完成学习提示:', text.substring(0, 20)); break; } } if (foundCompleteDialog) { // 查找"下一个"按钮 const nextButtons = document.querySelectorAll('button, .btn, [role="button"], a'); for (const btn of nextButtons) { const btnText = btn.textContent.trim(); if (btnText.includes('下一个') || btnText.includes('下一课') || btnText.includes('继续') || btnText.includes('next') || btnText.includes('Next') || btnText.includes('下一')) { console.log('[中泰学堂] ⏭️ 发现"下一个"按钮,执行单次点击'); btn.click(); // 设置已点击标志,防止重复点击 hasClickedNext = true; // 记录到日志 const logEl = document.querySelector('#answer-log'); if (logEl) { const time = new Date().toLocaleTimeString(); logEl.innerHTML += `
[${time}] ⏭️ 自动点击"下一个"(单次)
`; logEl.scrollTop = logEl.scrollHeight; } // 3秒后重置标志,允许下次课程使用 setTimeout(() => { hasClickedNext = false; console.log('[中泰学堂] ⏭️ 重置点击标志,准备下次课程'); }, 3000); break; } } } }, 2000); // 每2秒检查一次 } // 停止自动下一个监控 function stopAutoNextMonitor() { if (autoNextInterval) { clearInterval(autoNextInterval); autoNextInterval = null; console.log('[中泰学堂] ⏭️ 停止自动下一个监控'); } } // 启动视频进度检测监控(智能预测版) function startVideoProgressMonitor() { if (videoProgressInterval) { clearInterval(videoProgressInterval); } console.log('[中泰学堂] 🎬 启动智能视频进度检测监控'); videoProgressInterval = setInterval(() => { // 查找视频元素和倒计时元素 const videos = document.querySelectorAll('video'); const countdownElements = document.querySelectorAll('.yxt-color-warning, [class*="countdown"], [class*="timer"], span'); if (videos.length > 0) { const video = videos[0]; // 确保视频有有效的时长 if (!video.duration || video.duration === 0) { return; } // 检查倒计时文本 for (const element of countdownElements) { const text = element.textContent || ''; // 匹配多种倒计时格式(包括您图片中的格式) 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*秒/) || // 匹配 "1分钟 50秒" 格式 text.match(/(\d+)\s*分\s*(\d+)\s*秒/) || // 匹配 "1分 50秒" 格式 text.match(/(\d+)分(\d+)秒/) || // 匹配 "1分50秒" 格式 text.match(/还需\s*(\d+)\s*分\s*(\d+)?\s*秒?/); // 匹配 "还需X分X秒" 格式 if (timeMatch) { const minutes = parseInt(timeMatch[1]) || 0; const seconds = parseInt(timeMatch[2]) || 0; const countdownRemaining = minutes * 60 + seconds; // 计算视频剩余时间 const videoRemaining = video.duration - video.currentTime; console.log(`[中泰学堂] 🎬 检测状态: 视频剩余${videoRemaining.toFixed(1)}秒, 倒计时剩余${countdownRemaining}秒`); // 智能预测算法:提前预判并回退 // 场景1:视频即将结束(剩余10秒内),预测倒计时不能同步结束 if (videoRemaining <= 10 && countdownRemaining > videoRemaining + 2) { // 计算需要回退的时间:倒计时剩余时间 - 视频剩余时间 + 缓冲时间 const timeDifference = countdownRemaining - videoRemaining; const bufferTime = 3; // 3秒缓冲 const needBackwardTime = timeDifference + bufferTime; // 实际回退时间:不能超过当前播放进度,也不能超过合理范围 const actualBackwardTime = Math.min(needBackwardTime, video.currentTime, 120); // 最多回退2分钟 console.log(`[中泰学堂] 🎬 智能预测分析:`); console.log(` - 视频还有 ${videoRemaining.toFixed(1)} 秒结束`); console.log(` - 倒计时还有 ${countdownRemaining} 秒`); console.log(` - 时间差 ${timeDifference} 秒`); console.log(` - 需要回退 ${needBackwardTime} 秒`); console.log(` - 实际回退 ${actualBackwardTime.toFixed(1)} 秒`); if (actualBackwardTime >= 5) { // 只有需要回退5秒以上才执行 video.currentTime = Math.max(0, video.currentTime - actualBackwardTime); // 记录到日志 const logEl = document.querySelector('#answer-log'); if (logEl) { const time = new Date().toLocaleTimeString(); logEl.innerHTML += `
[${time}] 🎬 智能预测回退${actualBackwardTime.toFixed(1)}秒 (视频剩余${videoRemaining.toFixed(1)}s,倒计时${countdownRemaining}s)
`; logEl.scrollTop = logEl.scrollHeight; } // 暂停一段时间避免重复触发 setTimeout(() => { console.log('[中泰学堂] 🎬 预测回退完成,继续监控'); }, 3000); 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 += `
[${time}] 🎬 早期预测回退${earlyBackwardTime.toFixed(1)}秒
`; logEl.scrollTop = logEl.scrollHeight; } break; } } // 兜底机制:视频已完成但倒计时还有时间 else if (video.ended || (video.currentTime >= video.duration - 0.5)) { if (countdownRemaining > 0 && countdownRemaining <= 30) { const backwardTime = Math.min(countdownRemaining + 3, 30); console.log(`[中泰学堂] 🎬 兜底机制: 视频已完成,倒计时还有${countdownRemaining}秒,回退${backwardTime}秒`); video.currentTime = Math.max(0, video.currentTime - backwardTime); // 记录到日志 const logEl = document.querySelector('#answer-log'); if (logEl) { const time = new Date().toLocaleTimeString(); logEl.innerHTML += `
[${time}] 🎬 兜底回退${backwardTime}秒 (倒计时剩余${countdownRemaining}秒)
`; logEl.scrollTop = logEl.scrollHeight; } break; } } } } } }, 1000); // 每1秒检查一次,更精确 } // 停止视频进度检测监控 function stopVideoProgressMonitor() { if (videoProgressInterval) { clearInterval(videoProgressInterval); videoProgressInterval = null; console.log('[中泰学堂] 🎬 停止视频进度检测监控'); } } // 自动禁音功能(增强版) function autoMuteVideos() { console.log('[中泰学堂] 🔇 启动智能自动禁音功能'); let mutedCount = 0; // 方法1: 直接设置视频和音频元素的muted属性 const videos = document.querySelectorAll('video'); videos.forEach((video, index) => { if (!video.muted) { video.muted = true; video.volume = 0; // 同时设置音量为0 mutedCount++; console.log(`[中泰学堂] 🔇 视频${index + 1}已禁音`); } }); const audios = document.querySelectorAll('audio'); audios.forEach((audio, index) => { if (!audio.muted) { audio.muted = true; audio.volume = 0; // 同时设置音量为0 mutedCount++; console.log(`[中泰学堂] 🔇 音频${index + 1}已禁音`); } }); // 方法2: 点击页面上的静音按钮(根据您提供的HTML结构) const muteButtons = document.querySelectorAll( '.ml-volume_button, ' + // 您代码中的音量按钮类名 '[class*="volume"], ' + // 包含volume的类名 '[class*="mute"], ' + // 包含mute的类名 '[class*="sound"], ' + // 包含sound的类名 '[title*="静音"], ' + // title包含静音的元素 '[title*="音量"], ' + // title包含音量的元素 '[aria-label*="mute"], ' + // aria-label包含mute的元素 '[aria-label*="volume"]' // aria-label包含volume的元素 ); muteButtons.forEach((button, index) => { // 检查按钮是否表示"开启声音"状态(需要点击来静音) const buttonText = button.textContent || ''; const buttonTitle = button.title || ''; const buttonClass = button.className || ''; // 如果按钮显示为"有声音"状态,点击它来静音 const hasSound = buttonClass.includes('volume') && !buttonClass.includes('muted') || buttonTitle.includes('音量') || buttonText.includes('音量') || !button.classList.contains('muted'); if (hasSound) { console.log(`[中泰学堂] 🔇 点击音量按钮${index + 1}进行静音`); button.click(); mutedCount++; } }); // 方法3: 精确控制音量百分比(根据您的HTML结构) const volumePercents = document.querySelectorAll('.ml-volume_percent'); volumePercents.forEach((element, index) => { const currentText = element.textContent || ''; const percentMatch = currentText.match(/(\d+)%/); if (percentMatch) { const currentPercent = parseInt(percentMatch[1]); if (currentPercent > 0) { // 直接修改文本内容为0% element.textContent = '0%'; console.log(`[中泰学堂] 🔇 音量百分比${index + 1}从${currentPercent}%设置为0%`); mutedCount++; } } }); // 方法4: 查找音量滑块并设置为0 const volumeSliders = document.querySelectorAll( 'input[type="range"][class*="volume"], ' + '[class*="volume-slider"], ' + '[class*="volume-control"], ' + '.ml-volume_scroll-wrapper input' // 根据您的HTML结构 ); volumeSliders.forEach((slider, index) => { if (slider.value && parseFloat(slider.value) > 0) { slider.value = 0; slider.dispatchEvent(new Event('input', { bubbles: true })); slider.dispatchEvent(new Event('change', { bubbles: true })); console.log(`[中泰学堂] 🔇 音量滑块${index + 1}设置为0`); mutedCount++; } }); if (mutedCount > 0) { // 记录到日志 const logEl = document.querySelector('#answer-log'); if (logEl) { const time = new Date().toLocaleTimeString(); logEl.innerHTML += `
[${time}] 🔇 智能禁音${mutedCount}个媒体元素
`; logEl.scrollTop = logEl.scrollHeight; } } return mutedCount; } // 持续监控新加载的视频并自动禁音 function startAutoMuteMonitor() { console.log('[中泰学堂] 🔇 启动自动禁音监控'); // 立即执行一次禁音 autoMuteVideos(); // 监听新视频元素的加载 const observer = new MutationObserver((mutations) => { let hasNewMedia = false; mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node.nodeType === Node.ELEMENT_NODE) { // 检查新加载的视频或音频元素 const videos = node.querySelectorAll ? node.querySelectorAll('video') : []; const audios = node.querySelectorAll ? node.querySelectorAll('audio') : []; if (videos.length > 0 || audios.length > 0 || node.tagName === 'VIDEO' || node.tagName === 'AUDIO') { hasNewMedia = true; } } }); }); if (hasNewMedia) { console.log('[中泰学堂] 🔇 检测到新媒体元素,执行禁音'); setTimeout(() => autoMuteVideos(), 500); // 延迟500ms确保元素完全加载 } }); observer.observe(document.body, { childList: true, subtree: true }); // 定期检查(兜底机制) setInterval(() => { autoMuteVideos(); }, 5000); // 每5秒检查一次 } // 实时更新视频信息显示 let videoInfoInterval = null; function startVideoInfoMonitor() { if (videoInfoInterval) { clearInterval(videoInfoInterval); } console.log('[中泰学堂] 📊 启动视频信息实时显示'); videoInfoInterval = setInterval(() => { const videos = document.querySelectorAll('video'); const videoProgressText = document.querySelector('#video-progress-text'); const countdownText = document.querySelector('#countdown-text'); const syncStatus = document.querySelector('#sync-status'); const videoProgressBar = document.querySelector('#video-progress-bar'); if (videos.length > 0 && videoProgressText) { const video = videos[0]; if (video.duration && video.duration > 0) { // 格式化时间显示 const formatTime = (seconds) => { const mins = Math.floor(seconds / 60); const secs = Math.floor(seconds % 60); return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; }; const currentTime = video.currentTime; const duration = video.duration; const remaining = duration - currentTime; const progress = (currentTime / duration) * 100; // 更新视频进度显示 videoProgressText.textContent = `${formatTime(currentTime)} / ${formatTime(duration)}`; // 更新进度条 if (videoProgressBar) { videoProgressBar.style.width = `${progress}%`; } // 查找并显示倒计时 const countdownElements = document.querySelectorAll('.yxt-color-warning, [class*="countdown"], [class*="timer"], span'); let foundCountdown = false; for (const element of countdownElements) { const text = element.textContent || ''; // 匹配多种倒计时格式 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+)秒/); if (timeMatch) { const minutes = parseInt(timeMatch[1]) || 0; const seconds = parseInt(timeMatch[2]) || 0; const countdownRemaining = minutes * 60 + seconds; // 更新倒计时显示 if (countdownText) { countdownText.textContent = formatTime(countdownRemaining); } // 更新同步状态 if (syncStatus) { const timeDiff = Math.abs(remaining - countdownRemaining); if (timeDiff <= 3) { syncStatus.textContent = '✅ 时间同步'; syncStatus.style.color = '#38a169'; } else if (timeDiff <= 10) { syncStatus.textContent = `⚠️ 相差${timeDiff.toFixed(0)}秒`; syncStatus.style.color = '#ed8936'; } else { syncStatus.textContent = `❌ 相差${timeDiff.toFixed(0)}秒`; syncStatus.style.color = '#e53e3e'; } } foundCountdown = true; break; } } if (!foundCountdown && countdownText) { countdownText.textContent = '未检测到'; if (syncStatus) { syncStatus.textContent = '⏰ 等待倒计时'; syncStatus.style.color = '#718096'; } } } else { // 视频未加载完成 videoProgressText.textContent = '加载中...'; if (videoProgressBar) { videoProgressBar.style.width = '0%'; } } } else { // 没有视频元素 if (videoProgressText) { videoProgressText.textContent = '未检测到视频'; } if (countdownText) { countdownText.textContent = '未检测到'; } if (syncStatus) { syncStatus.textContent = '等待视频加载'; syncStatus.style.color = '#718096'; } if (videoProgressBar) { videoProgressBar.style.width = '0%'; } } }, 1000); // 每1秒更新一次 } // 停止视频信息监控 function stopVideoInfoMonitor() { if (videoInfoInterval) { clearInterval(videoInfoInterval); videoInfoInterval = null; console.log('[中泰学堂] 📊 停止视频信息实时显示'); } } // 启动自动最高倍速监控 function startAutoSpeedMonitor() { if (autoSpeedInterval) { clearInterval(autoSpeedInterval); } console.log('[中泰学堂] ⚡ 启动自动最高倍速监控'); autoSpeedInterval = setInterval(() => { // 查找倍速选择器 const speedSelectors = document.querySelectorAll('.mplayer-playback-rate_item, [class*="playback-rate"], [class*="speed"], [data-value]'); if (speedSelectors.length > 0) { let maxSpeed = 0; let maxSpeedElement = null; // 找到最高倍速选项 speedSelectors.forEach(element => { const dataValue = element.getAttribute('data-value'); const textContent = element.textContent || ''; // 从data-value或文本中提取倍速值 let speedValue = 0; if (dataValue) { speedValue = parseFloat(dataValue); } else { // 从文本中提取倍速(如 "2x", "1.5x", "2.0") const speedMatch = textContent.match(/(\d+\.?\d*)x?/); if (speedMatch) { speedValue = parseFloat(speedMatch[1]); } } if (speedValue > maxSpeed) { maxSpeed = speedValue; maxSpeedElement = element; } }); // 如果找到最高倍速且不是当前选中的 if (maxSpeedElement && maxSpeed > 1) { const isActive = maxSpeedElement.classList.contains('is-active') || maxSpeedElement.classList.contains('active') || maxSpeedElement.classList.contains('selected'); if (!isActive) { console.log(`[中泰学堂] ⚡ 发现最高倍速${maxSpeed}x,自动切换`); maxSpeedElement.click(); // 记录到日志 const logEl = document.querySelector('#answer-log'); if (logEl) { const time = new Date().toLocaleTimeString(); logEl.innerHTML += `
[${time}] ⚡ 自动切换到${maxSpeed}x倍速
`; logEl.scrollTop = logEl.scrollHeight; } } } } // 也检查视频元素的playbackRate属性 const videos = document.querySelectorAll('video'); videos.forEach(video => { if (video.playbackRate < 2.0) { // 尝试设置最高倍速 try { video.playbackRate = 2.0; console.log(`[中泰学堂] ⚡ 直接设置视频倍速为2.0x`); const logEl = document.querySelector('#answer-log'); if (logEl) { const time = new Date().toLocaleTimeString(); logEl.innerHTML += `
[${time}] ⚡ 直接设置视频2.0x倍速
`; logEl.scrollTop = logEl.scrollHeight; } } catch (e) { console.log('[中泰学堂] ⚡ 无法直接设置视频倍速'); } } }); }, 3000); // 每3秒检查一次 } // 停止自动最高倍速监控 function stopAutoSpeedMonitor() { if (autoSpeedInterval) { clearInterval(autoSpeedInterval); autoSpeedInterval = null; console.log('[中泰学堂] ⚡ 停止自动最高倍速监控'); } } // 显示打赏弹窗 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(); } }; console.log('[中泰学堂] ❤️ 显示打赏弹窗'); } // 复制微信号 function copyWechatId(button) { const wechatId = 'C919irt'; try { // 尝试使用现代API if (navigator.clipboard && window.isSecureContext) { navigator.clipboard.writeText(wechatId).then(() => { showCopySuccess(button, wechatId); }).catch(() => { fallbackCopy(wechatId, button); }); } else { fallbackCopy(wechatId, button); } } catch (error) { fallbackCopy(wechatId, button); } } // 备用复制方法 function fallbackCopy(text, button) { const textArea = document.createElement('textarea'); textArea.value = text; textArea.style.position = 'fixed'; textArea.style.opacity = '0'; document.body.appendChild(textArea); textArea.select(); try { document.execCommand('copy'); showCopySuccess(button, text); } catch (err) { showCopyFailed(button, text); } document.body.removeChild(textArea); } // 显示复制成功 function showCopySuccess(button, wechatId) { const originalText = button.textContent; button.textContent = '✅ 已复制微信号'; button.style.color = '#38a169'; setTimeout(() => { button.textContent = originalText; button.style.color = '#38a169'; }, 2000); console.log(`[中泰学堂] ✅ 微信号已复制: ${wechatId}`); // 显示提示 const tip = document.createElement('div'); tip.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #38a169; color: white; padding: 12px 20px; border-radius: 8px; font-size: 14px; z-index: 25000; box-shadow: 0 4px 12px rgba(56, 161, 105, 0.3); `; tip.textContent = `微信号 ${wechatId} 已复制到剪贴板`; document.body.appendChild(tip); setTimeout(() => { tip.remove(); }, 3000); } // 显示复制失败 function showCopyFailed(button, wechatId) { const originalText = button.textContent; button.textContent = `微信号: ${wechatId}`; button.style.color = '#ed8936'; setTimeout(() => { button.textContent = originalText; button.style.color = '#38a169'; }, 3000); console.log(`[中泰学堂] ❌ 复制失败,微信号: ${wechatId}`); } function getQuestionType(str) { if (!str) return 0; str = str.trim().replace(/\s+/g, ''); for (let key in TYPE) { if (str.includes(key)) return TYPE[key]; } return 0; // 默认单选题 } // 简化的答案搜索 async function searchAnswer(data) { const enableAI = document.querySelector('#enable-ai')?.checked || false; if (enableAI) { try { console.log('[中泰学堂] 🤖 启用AI答题,调用智谱GLM-4-Flash...'); const aiResult = await callBuiltinAI(data); if (aiResult.success) { console.log('[中泰学堂] ✅ AI智能回答:', aiResult.answers); return aiResult; } } catch (e) { console.error('[中泰学堂] AI调用异常:', e); } } // 使用智能策略 return { success: false, msg: "使用智能策略" }; } // 移除内置题库,避免答案过时 // 最优中文AI组合 - 免费、快速、准确 async function callBuiltinAI(data) { console.log('[中泰学堂] 🚀 调用最优中文AI组合...'); // 中文AI服务配置 (按优先级排序) const chineseAIServices = [ { name: '智谱GLM-4-Flash', url: 'https://open.bigmodel.cn/api/paas/v4/chat/completions', model: 'glm-4-flash', key: '51ae1d1540dd4d2d9418c32d3cefd868.3nX8rj0r87zTFSdl', // 智谱AI API密钥 priority: 1 }, { name: '通义千问', url: 'https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation', model: 'qwen-turbo', key: '你的阿里云API密钥', // 需要到阿里云获取 priority: 2 }, { name: 'DeepSeek', url: 'https://api.deepseek.com/v1/chat/completions', model: 'deepseek-chat', key: '你的DeepSeek密钥', // 需要到 https://platform.deepseek.com/ 获取 priority: 3 } ]; // 构建专业中文prompt const typeMap = { 0: '单选题', 1: '多选题', 3: '判断题' }; const prompt = `作为专业答题助手,请回答这道${typeMap[data.type]}: 题目:${data.question} 选项: ${data.options.map((opt, i) => `${String.fromCharCode(65 + i)}. ${opt}`).join('\n')} ${data.type === 1 ? '这是多选题,请选择所有正确答案,用逗号分隔' : data.type === 3 ? '这是判断题,请回答"正确"或"错误"' : '这是单选题,请选择一个最佳答案'} 只返回答案内容,不要解释:`; // 按优先级尝试AI服务 for (const service of chineseAIServices) { try { console.log(`[中泰学堂] 🔄 尝试 ${service.name}...`); const result = await callAIService(service, prompt, data); if (result.success) { console.log(`[中泰学堂] ✅ ${service.name} 回答成功:`, result.answers); return { success: true, answers: result.answers, source: "AI", msg: `${service.name} 智能回答` }; } } catch (e) { console.log(`[中泰学堂] ${service.name} 调用失败:`, e.message); } } console.log('[中泰学堂] ⚠️ 所有AI服务暂不可用,使用智能策略'); return { success: false, msg: "AI服务暂不可用,请检查网络或API配置" }; } // 智谱AI真实调用 async function callAIService(service, prompt, data) { return new Promise((resolve) => { console.log(`[中泰学堂] 🚀 调用 ${service.name}...`); GM_xmlhttpRequest({ method: 'POST', url: service.url, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${service.key}` }, data: JSON.stringify({ model: service.model, messages: [ { role: "user", content: prompt } ], max_tokens: 200, temperature: 0.1, stream: false }), timeout: 15000, onload: function(response) { try { console.log(`[中泰学堂] ${service.name} 响应状态:`, response.status); if (response.status === 200) { const result = JSON.parse(response.responseText); console.log(`[中泰学堂] ${service.name} 原始响应:`, result); let aiAnswer = ''; // 智谱AI响应格式 if (service.name.includes('智谱')) { aiAnswer = result.choices?.[0]?.message?.content?.trim(); } // 通义千问响应格式 else if (service.name.includes('通义')) { aiAnswer = result.output?.text?.trim(); } // DeepSeek响应格式 else if (service.name.includes('DeepSeek')) { aiAnswer = result.choices?.[0]?.message?.content?.trim(); } if (aiAnswer) { console.log(`[中泰学堂] 🎯 ${service.name} AI回答:`, aiAnswer); // 智能解析AI回答 let answers = []; // 清理AI回答 let cleanAnswer = aiAnswer.replace(/答案[::]?/g, '').trim(); if (data.type === 1) { // 多选题:分割答案 answers = cleanAnswer.split(/[,,、]/) .map(s => s.trim()) .filter(s => s.length > 0); } else if (data.type === 3) { // 判断题:标准化答案 if (cleanAnswer.includes('正确') || cleanAnswer.includes('对') || cleanAnswer.includes('是')) { answers = ['正确']; } else if (cleanAnswer.includes('错误') || cleanAnswer.includes('错') || cleanAnswer.includes('否')) { answers = ['错误']; } else { answers = [cleanAnswer]; } } else { // 单选题 answers = [cleanAnswer]; } resolve({ success: true, answers: answers, source: "AI" }); } else { resolve({ success: false, msg: "AI回答为空" }); } } else { console.error(`[中泰学堂] ${service.name} API错误:`, response.status, response.responseText); resolve({ success: false, msg: `API错误: ${response.status}` }); } } catch (e) { console.error(`[中泰学堂] ${service.name} 解析失败:`, e); resolve({ success: false, msg: "响应解析失败" }); } }, onerror: function(error) { console.error(`[中泰学堂] ${service.name} 请求失败:`, error); resolve({ success: false, msg: "网络请求失败" }); } }); }); } // 创建拟态化控制面板 function createVuePanel() { // 检查是否已存在面板或悬浮窗 const existingPanel = document.querySelector('#zt-auto-panel'); const existingPet = document.querySelector('#floating-pet'); if (existingPanel || existingPet) { console.log('[中泰学堂] 面板或悬浮窗已存在,跳过创建'); return existingPanel || existingPet; } console.log('[中泰学堂] 开始创建拟态化控制面板...'); const panel = document.createElement('div'); panel.id = 'zt-auto-panel'; panel.style.cssText = ` position: fixed !important; top: 30px !important; right: 20px !important; width: 380px !important; height: auto; min-width: 320px; min-height: 500px; max-width: 600px; max-height: 95vh; background: #f0f2f5 !important; 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: 2147483647 !important; font-family: 'Microsoft YaHei', Arial, sans-serif !important; transition: none; backdrop-filter: blur(10px); overflow-y: auto; overflow-x: hidden; display: block !important; visibility: visible !important; opacity: 1 !important; `; panel.innerHTML = `
🎯
中泰学堂助手
AI-Powered Exam Assistant
状态: 视频助手就绪
自动处理学习过程中的各种提示
视频进度
--:-- / --:--
倒计时
--:--
检测中...
看课时自动点击"继续学习"按钮
完成学习后自动点击"下一个"
视频完成但倒计时未结束时自动回退
自动识别并切换到最高播放倍速
`; 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 = `
🎯
AI
`; 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 = `
🎯 中泰答题助手
状态: 就绪
进度: 0/0
等待开始答题...
`; 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.0.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_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 }; }; // 🔧 立即定义全局函数(确保面板按钮可用) 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('[中泰学堂] ✅ 全局函数强制定义完成'); })();