// ==UserScript== // @name 江西省会计继续教育-会计人员继续教育网络培训-东奥继教刷课助手(jiangxi.dongao.cn) // @version 1.0 // @description 东奥会计在线江西站刷课助手,支持视频刷课+自动答题,客服微信wkds995 // @author 晓晓 // @match *://jiangxi.dongao.cn/* // @grant GM_getValue // @grant GM_setValue // @run-at document-end // @license MIT // ==/UserScript== (function () { 'use strict'; // ===================== 弹窗模板(标准4条须知,打赏需点按钮)===================== (function(){ function _esc(s) { return s.replace(/[<>&'"]/g, function(c){ return {'<':'<','>':'>','&':'&',"'":''','"':'"'}[c]; }); } function _injectStyles() { if (document.getElementById('xx-popup-styles')) return; var s = document.createElement('style'); s.id = 'xx-popup-styles'; s.textContent = [ '.xx-mask{position:fixed;inset:0;background:rgba(0,0,0,0.75);z-index:99999998;display:flex;align-items:center;justify-content:center;}', '.xx-box{background:#181c2b;border-radius:16px;border:1px solid rgba(255,255,255,0.12);padding:28px;color:#fff;font-family:system-ui,-apple-system,sans-serif;}', '.xx-box h2{margin:0 0 18px;font-size:18px;text-align:center;border-bottom:1px solid rgba(255,255,255,0.1);padding-bottom:14px;color:#fff;}', '.xx-content{line-height:1.8;font-size:14px;color:#e2e8f0;}', '.xx-content p{margin:6px 0;}', '.xx-footer{margin-top:22px;text-align:center;}', '.xx-btn{padding:11px 36px;border:none;border-radius:10px;cursor:pointer;font-size:14px;font-weight:600;transition:opacity .2s;}', '.xx-btn:hover{opacity:0.88;}', '.xx-btn-primary{background:linear-gradient(135deg,#6a11cb,#2575fc);color:#fff;}', '.xx-btn-secondary{background:rgba(255,255,255,0.08);color:#aaa;border:1px solid rgba(255,255,255,0.15);}', '.xx-donate{width:360px;}', '.xx-donate h3{margin:0 0 14px;font-size:16px;text-align:center;letter-spacing:.5px;color:#fff;}', '.xx-wechat-label{text-align:center;font-size:13px;color:#c9d1d9;margin-bottom:10px;letter-spacing:1px;}', '.xx-qr-wrap{width:220px;height:220px;background:#fff;border-radius:12px;margin:0 auto 12px;display:flex;align-items:center;justify-content:center;overflow:hidden;}', '.xx-qr-wrap img{width:200px;height:200px;border-radius:8px;object-fit:cover;}', '.xx-donate-desc{font-size:12px;color:#c9d1d9;margin-bottom:16px;text-align:center;line-height:1.6;}' ].join(''); document.head.appendChild(s); } window.__popupGuide = function(items, btnText, onClose) { if (document.querySelector('.xx-guide-mask')) return; btnText = btnText || '我已知晓'; onClose = onClose || function(){}; _injectStyles(); var lines = items.map(function(item){ var icon = item.ok !== false ? '\u2705' : '\u26a0\ufe0f'; return '

' + icon + ' ' + _esc(item.text) + '

'; }).join(''); var mask = document.createElement('div'); mask.className = 'xx-mask xx-guide-mask'; mask.innerHTML = '

\ud83d\udcd6 \u811a\u672c\u4f7f\u7528\u9875\u77e5

' + lines + '
'; document.body.appendChild(mask); function close(){ mask.remove(); onClose(); } mask.querySelector('.guide-close-btn').onclick = close; mask.onclick = function(e){ if(e.target === mask) close(); }; }; window.__popupDonate = function(wxQrUrl, desc, onClose) { if (document.querySelector('.xx-donate-mask')) return; onClose = onClose || function(){}; _injectStyles(); var descHtml = desc ? '
' + _esc(desc) + '
' : '
\u81ea\u613f\u6253\u8d4d\uff0c\u60a8\u7684\u652f\u6301\u662f\u6301\u7eed\u66f4\u65b0\u7684\u52a8\u529b
'; var mask = document.createElement('div'); mask.className = 'xx-mask xx-donate-mask'; mask.innerHTML = '

\ud83d\udcb0 \u611f\u8c22\u652f\u6301\u811a\u672c\u6301\u7eed\u7ef4\u62a4\u66f4\u65b0

\u5fae\u4fe1\u652f\u4ed8
\u5fae\u4fe1\u6536\u6b3e\u7801
' + descHtml + '
'; document.body.appendChild(mask); function close(){ mask.remove(); onClose(); } mask.querySelector('.donate-close-btn').onclick = close; mask.onclick = function(e){ if(e.target === mask) close(); }; }; })(); // ===================== 平台配置(东奥会计在线江西站)===================== const PLATFORM_CONFIGS = { // ========== 东奥会计在线 专属精细配置 ========== dongao: { name: "东奥会计在线", match: /dongao\.com/, selectors: { // 课程列表页 courseItem: '.course-item, .kc-item', unfinishedCourse: '.course-item.status-unfinish, .kc-item.no-study', courseTitle: '.course-name, .kc-title', courseEnterBtn: '.study-btn, .enter-study, .btn-study', // 课程内章节列表 chapterItem: '.chapter-item, .section-item', unfinishedChapter: '.chapter-item.unfinish, .section-item.no-study', chapterTitle: '.chapter-name, .section-title', chapterPlayBtn: '.play-btn, .btn-play', nextChapterBtn: '.next-section-btn, .btn-next', // 视频播放器 videoPlayer: 'video', playerBox: '.player-box, .video-player', progressBar: '.progress-bar-inner', // 验证码(中途弹窗+考试前) captchaModal: '.verify-modal, .captcha-dialog', captchaImg: '#verifyImg, .captcha-img img', captchaInput: '#verifyCode, .captcha-input', captchaSubmit: '#btnSubmit, .captcha-confirm-btn', // 考试页面 questionItem: '.question-item, .exam-question', questionTitle: '.question-stem, .q-title', optionSingle: '.option-item input[type="radio"] + label, .option-single', optionMulti: '.option-item input[type="checkbox"] + label, .option-multi', judgeTrue: '.judge-option.true, .option-true', judgeFalse: '.judge-option.false, .option-false', fillInput: '.fill-blank input, .blank-input', submitPaperBtn: '#submitPaper, .btn-submit-paper', confirmSubmitBtn: '.dialog-confirm-btn, .el-button--primary', scoreText: '.score-number, .exam-score-value', retryBtn: '#reExam, .btn-retake-exam' }, special: { chapterMode: true, // 启用章节遍历模式 captchaInterval: 180, // 每180秒检查一次验证码弹窗 antiPause: true // 强制防视频暂停 } } }; // ===================== 全局配置 ===================== const GLOBAL_CONFIG = { passScore: 60, maxRetry: 4, videoMuted: true, answerDelaySingle: [5000, 7000], // 单选/判断 5-7秒 answerDelayFill: [10000, 12000], // 填空 10-12秒 activityInterval: 25000, // 活跃度模拟间隔 questionBank: [ { question: "会计的基本职能包括核算和监督。", type: "judge", answer: "正确" }, { question: "下列各项中,属于会计要素的有", type: "multi", answer: "资产,负债,所有者权益" }, { question: "企业会计核算的基础是", type: "single", answer: "权责发生制" }, { question: "会计恒等式:资产 = 负债 + ________", type: "fill", answer: "所有者权益" } ] } // ===================== 当前平台自动识别 ===================== var SELECTORS = PLATFORM_CONFIGS.dongao.selectors; var SPECIAL = PLATFORM_CONFIGS.dongao.special || {}; var PLATFORM_NAME = PLATFORM_CONFIGS.dongao.name; // ===================== GM存储兼容层 ===================== var GM = { get: function(k, def) { var v = GM_getValue("_da_" + k); return v !== undefined ? v : def; }, set: function(k, v) { GM_setValue("_da_" + k, v); }, del: function(k) { GM_setValue("_da_" + k, null); } }; // ===================== 工具函数 ===================== const Utils = { randomDelay(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }, similarity(str1, str2) { const s1 = str1.trim().replace(/[\s\W]/g, ''); const s2 = str2.trim().replace(/[\s\W]/g, ''); if (s1 === s2) return 1; const len = Math.max(s1.length, s2.length); if (len === 0) return 1; let match = 0; for (let i = 0; i < s1.length; i++) { if (s2.includes(s1[i])) match++; } return match / len; }, log(msg, type = 'info') { const time = new Date().toLocaleTimeString(); const text = `[${time}] [${type.toUpperCase()}] ${msg}`; console.log(text); UI.appendLog(text); }, waitFor(selector, timeout = 15000) { return new Promise((resolve, reject) => { const timer = setInterval(() => { const el = document.querySelector(selector); if (el && el.offsetParent !== null) { clearInterval(timer); resolve(el); } }, 500); setTimeout(() => { clearInterval(timer); reject(new Error(`元素超时未找到: ${selector}`)); }, timeout); }); }, async humanMoveTo(element) { if (!element) return; const rect = element.getBoundingClientRect(); const targetX = rect.left + rect.width / 2 + this.randomDelay(-12, 12); const targetY = rect.top + rect.height / 2 + this.randomDelay(-6, 6); const steps = this.randomDelay(10, 18); const startX = window.mouseX || window.innerWidth / 2; const startY = window.mouseY || window.innerHeight / 2; for (let i = 1; i <= steps; i++) { const x = startX + (targetX - startX) * (i / steps) + Math.sin(i / 2) * 3; const y = startY + (targetY - startY) * (i / steps) + Math.cos(i / 2) * 2; document.dispatchEvent(new MouseEvent('mousemove', { clientX: x, clientY: y, bubbles: true, cancelable: true })); window.mouseX = x; window.mouseY = y; await new Promise(r => setTimeout(r, 15)); } }, sleep(ms) { return new Promise(r => setTimeout(r, ms)); } } // ===================== 反作弊模块 ===================== const AntiCheat = { init() { this.hijackVisibilityDeep(); this.startActivitySimulation(); this.hookVideoAntiPause(); // 平台专属反作弊 if (currentPlatform?.name === '东奥会计在线') { this.dongaoSpecial(); } if (currentPlatform?.name === '正保会计网校') { this.chinaaccSpecial(); } Utils.log(`深度反作弊模块已加载,当前平台:${currentPlatform?.name || '通用模式'}`); }, // 深度劫持可见性与失焦检测 hijackVisibilityDeep() { // 重写核心属性 Object.defineProperty(document, 'hidden', { value: false, writable: false, configurable: false }); Object.defineProperty(document, 'visibilityState', { value: 'visible', writable: false, configurable: false }); document.hasFocus = () => true; window.focus = () => true; // 捕获阶段拦截所有失焦/可见性事件 ['visibilitychange', 'blur', 'focusout', 'pagehide'].forEach(evt => { window.addEventListener(evt, e => e.stopImmediatePropagation(), true); document.addEventListener(evt, e => e.stopImmediatePropagation(), true); }); // 注入页面级覆盖脚本 const injectJS = ` (function(){ const _origDesc = Object.getOwnPropertyDescriptor(Document.prototype, 'hidden'); Object.defineProperty(document, 'hidden', { value: false, writable: false, configurable: false }); Object.defineProperty(document, 'visibilityState', { value: 'visible', writable: false, configurable: false }); document.hasFocus = function(){ return true; }; })(); `; const script = document.createElement('script'); script.textContent = injectJS; document.documentElement.appendChild(script); script.remove(); }, // 真人活跃度模拟 startActivitySimulation() { setInterval(() => { if (!window.autoRunning) return; // 随机滚动页面 window.scrollBy({ top: Utils.randomDelay(-60, 120), behavior: 'smooth' }); // 随机鼠标移动 const x = Utils.randomDelay(100, window.innerWidth - 100); const y = Utils.randomDelay(100, window.innerHeight - 100); document.dispatchEvent(new MouseEvent('mousemove', { clientX: x, clientY: y, bubbles: true })); window.mouseX = x; window.mouseY = y; // 30%概率点击空白区域 if (Math.random() > 0.7) { document.body.dispatchEvent(new MouseEvent('click', { clientX: x, clientY: y, bubbles: true })); } }, GLOBAL_CONFIG.activityInterval); }, // 视频防暂停钩子 hookVideoAntiPause() { const observer = new MutationObserver(() => { const videos = document.querySelectorAll('video'); videos.forEach(v => { // 强制静音 if (GLOBAL_CONFIG.videoMuted) { v.muted = true; v.volume = 0; } // 拦截暂停事件,自动恢复播放 v.addEventListener('pause', () => { if (window.autoRunning && SPECIAL.antiPause) { setTimeout(() => v.play().catch(() => { }), 500); } }); // 禁止快进检测:不修改currentTime,仅自然播放 }); }); observer.observe(document.body, { childList: true, subtree: true }); }, // 东奥专属反作弊优化 dongaoSpecial() { Utils.log('加载东奥专属反作弊策略:播放器区域模拟交互、防中断'); setInterval(() => { if (!window.autoRunning) return; const player = document.querySelector(SELECTORS.playerBox); if (player) { // 模拟鼠标在播放器内移动,防止挂机判定 const rect = player.getBoundingClientRect(); const x = rect.left + Utils.randomDelay(50, rect.width - 50); const y = rect.top + Utils.randomDelay(50, rect.height - 50); player.dispatchEvent(new MouseEvent('mousemove', { clientX: x, clientY: y, bubbles: true })); } }, 15000); }, // 正保专属反作弊优化 chinaaccSpecial() { Utils.log('加载正保专属策略:自动同步学时、拦截中断弹窗'); if (SPECIAL.autoSyncStudy) { setInterval(() => { if (!window.autoRunning) return; // 自动触发学时同步 const syncBtn = document.querySelector('.sync-btn, .tongbu_btn'); if (syncBtn) syncBtn.click(); // 自动关闭学习提示弹窗 document.querySelectorAll('.dialog-close, .close-btn').forEach(btn => { if (btn.offsetParent !== null) btn.click(); }); }, SPECIAL.syncInterval * 1000); } } } // ===================== 验证码模块 ===================== const CaptchaSolver = { async init() { if (window.Tesseract) return; const script = document.createElement('script'); script.src = 'https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js'; document.head.appendChild(script); await new Promise(resolve => script.onload = resolve); Utils.log('OCR验证码识别引擎加载完成'); }, async solve(imgSelector) { try { const img = document.querySelector(imgSelector); if (!img) return null; await this.init(); const result = await Tesseract.recognize(img.src, 'eng', { tessedit_char_whitelist: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' }); const code = result.data.text.trim().replace(/\s/g, '').substring(0, 4); Utils.log(`验证码识别结果: ${code}`); return code; } catch (e) { Utils.log(`验证码识别失败: ${e.message}`, 'error'); return null; } }, // 检测并处理所有验证码弹窗 async checkAndSolve() { const modal = document.querySelector(SELECTORS.captchaModal); if (!modal || modal.offsetParent === null) return false; Utils.log('检测到验证码弹窗,正在识别...'); const code = await this.solve(SELECTORS.captchaImg); if (!code) return false; const input = document.querySelector(SELECTORS.captchaInput); const submit = document.querySelector(SELECTORS.captchaSubmit); if (!input || !submit) return false; await Utils.humanMoveTo(input); input.focus(); input.value = code; input.dispatchEvent(new Event('input', { bubbles: true })); input.dispatchEvent(new Event('change', { bubbles: true })); await Utils.sleep(800); await Utils.humanMoveTo(submit); submit.click(); Utils.log('验证码已提交'); await Utils.sleep(1500); return true; } } // ===================== 课程学习模块 ===================== const CourseLearner = { async start() { Utils.log('=== 自动学习模块启动(课程→章节→小节 三级遍历) ==='); UI.updateStatus('学习中', '正在扫描未完成课程...'); // 1. 获取课程列表 const courses = document.querySelectorAll(SELECTORS.unfinishedCourse); if (courses.length === 0) { Utils.log('课程列表页未找到未完成课程,尝试检测章节页...'); // 如果已经在课程内,直接学习章节 if (document.querySelector(SELECTORS.chapterItem)) { await this.studyAllChapters(); return true; } Utils.log('未发现可学习内容,学习阶段结束'); return true; } Utils.log(`共找到 ${courses.length} 门未完成课程,将按顺序逐章学习`); // 2. 遍历每门课程 for (let i = 0; i < courses.length; i++) { if (!window.autoRunning) break; const course = courses[i]; const title = course.querySelector(SELECTORS.courseTitle)?.textContent.trim() || `第${i + 1}门课程`; UI.updateStatus('课程学习中', title, courses.length - i); Utils.log(`===== 进入课程:${title} =====`); // 进入课程 const enterBtn = course.querySelector(SELECTORS.courseEnterBtn); await Utils.humanMoveTo(enterBtn); enterBtn.click(); await Utils.sleep(3500); // 学习该课程下所有章节 await this.studyAllChapters(); Utils.log(`课程《${title}》全部章节学习完成`); // 返回课程列表 history.back(); await Utils.sleep(2500); } Utils.log('=== 全部课程学习完成 ==='); UI.updateStatus('学习完成', '所有课程已结束'); return true; }, // 学习当前课程下所有章节 async studyAllChapters() { await Utils.sleep(2000); const chapters = document.querySelectorAll(SELECTORS.unfinishedChapter); if (chapters.length === 0) { Utils.log('当前课程无未完成章节'); return; } Utils.log(`当前课程共 ${chapters.length} 个未完成小节`); for (let j = 0; j < chapters.length; j++) { if (!window.autoRunning) break; const chapter = chapters[j]; const title = chapter.querySelector(SELECTORS.chapterTitle)?.textContent.trim() || `第${j + 1}小节`; Utils.log(`开始学习小节:${title}`); // 点击播放 const playBtn = chapter.querySelector(SELECTORS.chapterPlayBtn) || chapter; await Utils.humanMoveTo(playBtn); playBtn.click(); await Utils.sleep(3000); // 监听播放进度 await this.watchVideoProgress(title); Utils.log(`小节完成:${title}`); } }, // 监听单个视频播放进度 async watchVideoProgress(title) { return new Promise(resolve => { const timer = setInterval(async () => { if (!window.autoRunning) { clearInterval(timer); resolve(); return; } // 定时检查验证码 await CaptchaSolver.checkAndSolve(); // 获取播放进度 const video = document.querySelector(SELECTORS.videoPlayer); if (video && video.duration && !isNaN(video.duration)) { const progress = video.currentTime / video.duration; if (progress >= 0.98) { clearInterval(timer); resolve(); } } }, 6000); }); } } // ===================== 题库答题模块 ===================== const ExamTaker = { async start() { Utils.log('=== 自动考试模块启动 ==='); let retryCount = 0; while (retryCount < GLOBAL_CONFIG.maxRetry && window.autoRunning) { UI.updateStatus('考试中', `第 ${retryCount + 1} 次考试`); Utils.log(`第 ${retryCount + 1} 次考试开始`); // 处理入场验证码 await CaptchaSolver.checkAndSolve(); await Utils.sleep(2000); // 获取所有题目 const questions = document.querySelectorAll(SELECTORS.questionItem); if (questions.length === 0) { Utils.log('未找到考试题目,页面可能未加载完成', 'error'); retryCount++; continue; } Utils.log(`本次考试共 ${questions.length} 道题`); // 逐题作答 for (let i = 0; i < questions.length; i++) { if (!window.autoRunning) break; await this.answerQuestion(questions[i], i + 1); } // 提交试卷 Utils.log('答题完成,准备提交试卷'); const submitBtn = document.querySelector(SELECTORS.submitPaperBtn); if (submitBtn) { await Utils.humanMoveTo(submitBtn); submitBtn.click(); await Utils.sleep(2000); // 确认提交弹窗 const confirmBtn = document.querySelector(SELECTORS.confirmSubmitBtn); if (confirmBtn) { await Utils.humanMoveTo(confirmBtn); confirmBtn.click(); } } // 等待成绩加载 await Utils.sleep(5000); const scoreEl = document.querySelector(SELECTORS.scoreText); if (!scoreEl) { Utils.log('无法获取考试成绩,流程异常', 'error'); retryCount++; continue; } const score = parseFloat(scoreEl.textContent.trim()); Utils.log(`本次考试得分:${score} 分`); if (score >= GLOBAL_CONFIG.passScore) { Utils.log('🎉 考试通过!'); UI.updateStatus('考试通过', `最终得分:${score}分`); return true; } else { retryCount++; if (retryCount >= GLOBAL_CONFIG.maxRetry) { Utils.log('已达最大重试次数,考试结束'); break; } Utils.log(`未及格,准备第 ${retryCount + 1} 次补考`); const retryBtn = document.querySelector(SELECTORS.retryBtn); if (retryBtn) { await Utils.humanMoveTo(retryBtn); retryBtn.click(); await Utils.sleep(3000); } else { Utils.log('未找到补考按钮,结束考试', 'error'); break; } } } UI.updateStatus('考试结束', '已达最大重试次数'); return false; }, async answerQuestion(questionEl, index) { const titleEl = questionEl.querySelector(SELECTORS.questionTitle); if (!titleEl) return; const title = titleEl.textContent.trim(); Utils.log(`作答第 ${index} 题:${title.substring(0, 35)}...`); // 题库模糊匹配 const match = this.matchBank(title); if (!match) { Utils.log(`第 ${index} 题未匹配到答案`, 'warn'); return; } switch (match.type) { case 'single': await this.answerSingle(questionEl, match.answer); await Utils.sleep(Utils.randomDelay(...GLOBAL_CONFIG.answerDelaySingle)); break; case 'multi': await this.answerMulti(questionEl, match.answer); await Utils.sleep(Utils.randomDelay(...GLOBAL_CONFIG.answerDelaySingle)); break; case 'judge': await this.answerJudge(questionEl, match.answer); await Utils.sleep(Utils.randomDelay(...GLOBAL_CONFIG.answerDelaySingle)); break; case 'fill': await this.answerFill(questionEl, match.answer); await Utils.sleep(Utils.randomDelay(...GLOBAL_CONFIG.answerDelayFill)); break; } }, matchBank(questionText) { let best = null; let bestScore = 0; for (const item of GLOBAL_CONFIG.questionBank) { const score = Utils.similarity(questionText, item.question); if (score > bestScore) { bestScore = score; best = item; } } return bestScore >= 0.78 ? best : null; }, async answerSingle(el, answer) { const options = el.querySelectorAll(SELECTORS.optionSingle); for (const opt of options) { if (opt.textContent.trim().includes(answer.trim())) { await Utils.humanMoveTo(opt); opt.click(); return; } } }, async answerMulti(el, answer) { const answers = answer.split(/[,,、]/).map(s => s.trim()); const options = el.querySelectorAll(SELECTORS.optionMulti); for (const opt of options) { const text = opt.textContent.trim(); if (answers.some(a => text.includes(a))) { await Utils.humanMoveTo(opt); opt.click(); await Utils.sleep(350); } } }, async answerJudge(el, answer) { const isTrue = answer.includes('正确') || answer.includes('对') || answer.includes('√'); const selector = isTrue ? SELECTORS.judgeTrue : SELECTORS.judgeFalse; const btn = el.querySelector(selector); if (btn) { await Utils.humanMoveTo(btn); btn.click(); } }, async answerFill(el, answer) { const input = el.querySelector(SELECTORS.fillInput); if (input) { await Utils.humanMoveTo(input); input.focus(); input.value = answer; input.dispatchEvent(new Event('input', { bubbles: true })); input.dispatchEvent(new Event('change', { bubbles: true })); } } } // ===================== 两轮答题模块(来自zhengbaodati.js)==================== var CAStorage = { prefix: "ca2_", get: function(k, def) { try { var v = localStorage.getItem(this.prefix + k); return v !== null ? v : def; } catch(e) { return def; } }, set: function(k, v) { try { localStorage.setItem(this.prefix + k, v); return true; } catch(e) { return false; } }, del: function(k) { try { localStorage.removeItem(this.prefix + k); } catch(e) {} } }; function detectPageType() { const html = document.body.innerHTML; const text = document.body.textContent; const hasQuestions = document.querySelector('input[name^="qt"]'); const hasSubmit = document.querySelector('#PostBtn'); const hasAnswer = text.includes('正确答案') || text.includes('【正确答案】'); if (hasQuestions && hasSubmit && !hasAnswer) { return 'exam'; // 答题页面 } if (hasAnswer) { return 'result'; // 答案页面 } return 'unknown'; } function getPaperId() { const html = document.documentElement.innerHTML; // 方法1: 使用ShowNum let match = html.match(/var ShowNum = '([^']+)'/); if (match && match[1]) { return 'paper_' + match[1].replace(/[^0-9,]/g, '').substring(0, 80); } // 方法2: 使用TIDList1 match = html.match(/var TIDList1 = '([^']+)'/); if (match && match[1]) { return 'paper_' + match[1].replace(/[^0-9,]/g, '').substring(0, 80); } return 'paper_default'; } function getAllQuestionIds() { const html = document.documentElement.innerHTML; const ids = []; // 优先使用ShowNum let match = html.match(/var ShowNum = '([^']+)'/); if (match) { const extracted = match[1].split(',').filter(id => id.trim() && /^\d+$/.test(id.trim())); ids.push(...extracted); } // 备用: 使用TIDList if (ids.length === 0) { for (let i = 1; i <= 4; i++) { match = html.match(new RegExp(`var TIDList${i} = '([^']+)'`)); if (match) { const extracted = match[1].split(',').filter(id => id.trim() && /^\d+$/.test(id.trim())); ids.push(...extracted); } } } console.log(`找到 ${ids.length} 道题:`, ids); return ids; } function getQuestionType(qid) { const inputs = document.querySelectorAll(`input[name='qt${qid}']`); if (inputs.length === 0) return null; if (inputs[0].type === 'checkbox') return 'multiple'; if (inputs.length === 2) { const values = Array.from(inputs).map(i => i.value); if (values.includes('Y') && values.includes('N')) { return 'judge'; } } return 'single'; } function clearAllAnswers() { const inputs = document.querySelectorAll('input[type="radio"], input[type="checkbox"]'); inputs.forEach(input => input.checked = false); console.log('✓ 已清空所有选项'); } function randomFillAnswer(qid, type) { if (type === 'judge') { const answer = Math.random() > 0.5 ? 'Y' : 'N'; const input = document.querySelector(`input[name='qt${qid}'][value='${answer}']`); if (input) input.checked = true; } else if (type === 'single') { const inputs = document.querySelectorAll(`input[name='qt${qid}']`); if (inputs.length > 0) { inputs[Math.floor(Math.random() * inputs.length)].checked = true; } } else if (type === 'multiple') { const inputs = document.querySelectorAll(`input[name='qt${qid}']`); const count = Math.min(inputs.length, Math.floor(Math.random() * 2) + 2); const selected = new Set(); while (selected.size < count) { selected.add(Math.floor(Math.random() * inputs.length)); } selected.forEach(idx => inputs[idx].checked = true); } } function firstSubmit() { console.log('%c===== 第一步: 获取答案 =====', 'color: #FF9800; font-weight: bold'); clearAllAnswers(); showMessage('正在随机填充并提交...', 'info'); const qids = getAllQuestionIds(); const paperId = getPaperId(); // 保存试卷信息 CAStorage.set('current_paper_id', paperId); CAStorage.set(paperId + '_question_ids', JSON.stringify(qids)); CAStorage.set('is_getting_answer', 'true'); console.log('试卷ID:', paperId); console.log('题目数:', qids.length); // 随机填充 qids.forEach(qid => { const type = getQuestionType(qid); if (type) randomFillAnswer(qid, type); }); setTimeout(() => { showMessage('提交中,请等待跳转...', 'info'); const btn = document.querySelector('#PostBtn'); if (btn) { btn.click(); } else { showMessage('找不到提交按钮', 'error'); } }, 1000); } function parseAnswersFromResultPage() { console.log('%c===== 第二步: 解析答案 =====', 'color: #4CAF50; font-weight: bold'); const paperId = CAStorage.get('current_paper_id'); if (!paperId) { console.error('未找到试卷ID'); showMessage('错误: 未找到试卷ID', 'error'); return; } const qidsJson = CAStorage.get(paperId + '_question_ids', '[]'); let qids = []; try { qids = JSON.parse(qidsJson); } catch (e) { console.error('解析题目列表失败:', e); return; } if (qids.length === 0) { console.error('题目列表为空'); return; } console.log(`试卷: ${paperId}`); console.log(`题数: ${qids.length}`); const answers = {}; let parsed = 0; qids.forEach((qid, idx) => { console.log(`\n[${idx + 1}/${qids.length}] 题目 ${qid}`); // 查找题目锚点 const anchor = document.querySelector(`a[name='md${qid}']`); if (!anchor) { console.warn(' ⚠️ 找不到锚点'); return; } // 找到容器 const container = anchor.closest('tr') || anchor.closest('div.showclass'); if (!container) { console.warn(' ⚠️ 找不到容器'); return; } const text = container.textContent || container.innerText; // 匹配答案: 【正确答案】D 或 【正确答案】AB const patterns = [ /【正确答案】([A-Z]+|对|错)/, /正确答案】([A-Z]+|对|错)/, /正确答案[::]([A-Z]+|对|错)/i ]; let found = null; for (let pattern of patterns) { const match = text.match(pattern); if (match && match[1]) { found = match[1].trim(); break; } } if (!found) { console.warn(' ⚠️ 未找到答案'); return; } // 处理答案 let answer = found; if (answer === '对') { answer = 'Y'; console.log(` ✓ 判断题: Y (对)`); } else if (answer === '错') { answer = 'N'; console.log(` ✓ 判断题: N (错)`); } else if (/^[A-Z]{2,}$/.test(answer)) { answer = answer.split(''); console.log(` ✓ 多选题: [${answer.join(', ')}]`); } else { console.log(` ✓ 单选题: ${answer}`); } answers[qid] = answer; parsed++; }); console.log(`\n解析完成: ${parsed}/${qids.length} 题`); console.table(answers); if (parsed > 0) { const cacheKey = paperId + '_answers'; CAStorage.set(cacheKey, JSON.stringify(answers)); CAStorage.set('is_getting_answer', 'false'); showMessage(`✅ 成功保存 ${parsed}/${qids.length} 题答案!\n\n5秒后自动返回`, 'success'); addReturnButton(); setTimeout(() => { console.log('返回答题页面...'); window.history.back(); }, 5000); } else { showMessage('未能解析到任何答案', 'error'); addReturnButton(); } } function autoFillWithCache() { console.log('%c===== 第三步: 使用答案 =====', 'color: #4CAF50; font-weight: bold'); const paperId = getPaperId(); const cacheKey = paperId + '_answers'; const cached = CAStorage.get(cacheKey); console.log(`试卷: ${paperId}`); console.log(`缓存: ${cached ? '存在' : '不存在'}`); if (!cached || cached === '{}') { showMessage('❌ 没有缓存答案\n\n请先"获取正确答案"', 'warning'); return; } let answers = {}; try { answers = JSON.parse(cached); } catch (e) { console.error('解析缓存失败:', e); showMessage('缓存数据错误', 'error'); return; } if (Object.keys(answers).length === 0) { showMessage('缓存为空', 'warning'); return; } console.log('缓存答案:', answers); clearAllAnswers(); const qids = getAllQuestionIds(); let filled = 0; let missing = 0; qids.forEach(qid => { const answer = answers[qid]; if (!answer) { console.warn(`题 ${qid}: 无缓存`); missing++; return; } const type = getQuestionType(qid); if (type === 'multiple' && Array.isArray(answer)) { answer.forEach(opt => { const input = document.querySelector(`input[name='qt${qid}'][value='${opt}']`); if (input) input.checked = true; }); filled++; console.log(`题 ${qid}: [${answer.join(',')}]`); } else if (typeof answer === 'string') { const input = document.querySelector(`input[name='qt${qid}'][value='${answer}']`); if (input) { input.checked = true; filled++; console.log(`题 ${qid}: ${answer}`); } else { console.error(`题 ${qid}: 找不到选项 ${answer}`); } } }); console.log(`填充: ${filled}/${qids.length}, 缺失: ${missing}`); if (filled > 0) { showMessage(`✅ 已填充 ${filled}/${qids.length} 题\n${missing > 0 ? `⚠️ ${missing}题无缓存\n` : ''}\n请检查后手动提交`, 'success'); } else { showMessage('未能填充任何题目', 'error'); } } function addReturnButton() { const btn = document.createElement('button'); btn.textContent = '🔙 立即返回'; btn.style.cssText = ` position: fixed; bottom: 20px; right: 20px; padding: 15px 30px; background: #4CAF50; color: white; border: none; border-radius: 8px; font-size: 16px; font-weight: bold; cursor: pointer; z-index: 99999; box-shadow: 0 4px 15px rgba(0,0,0,0.3); `; btn.onclick = () => window.history.back(); document.body.appendChild(btn); } function showMessage(msg, type = 'info') { const colors = { success: '#4CAF50', info: '#2196F3', warning: '#FF9800', error: '#F44336' }; const old = document.getElementById('autoAnswerMessage'); if (old) old.remove(); const div = document.createElement('div'); div.id = 'autoAnswerMessage'; div.style.cssText = ` position: fixed; top: 20px; left: 50%; transform: translateX(-50%); background: ${colors[type]}; color: white; padding: 20px 30px; border-radius: 8px; font-size: 16px; z-index: 99999; box-shadow: 0 4px 15px rgba(0,0,0,0.3); text-align: center; white-space: pre-line; font-weight: bold; `; div.textContent = msg; document.body.appendChild(div); if (type !== 'error') { setTimeout(() => div.remove(), 8000); } } function addControlPanel() { const paperId = getPaperId(); const cacheKey = paperId + '_answers'; const cached = CAStorage.get(cacheKey); let cacheCount = 0; if (cached && cached !== '{}') { try { cacheCount = Object.keys(JSON.parse(cached)).length; } catch (e) {} } const panel = document.createElement('div'); panel.style.cssText = ` position: fixed; top: 120px; right: 20px; background: white; border: 3px solid #2196F3; border-radius: 10px; padding: 20px; z-index: 10000; box-shadow: 0 4px 15px rgba(0,0,0,0.3); width: 260px; `; const qcount = getAllQuestionIds().length; panel.innerHTML = `
🤖 猪猪的自动答题助手
📋 题数: ${qcount}
💾 缓存: ${cacheCount} 题
📖 使用说明:
1️⃣ 清空表单
2️⃣ 获取正确答案(自动提交)
3️⃣ 等待解析(自动返回)
4️⃣ 使用缓存答案(自动填充)
5️⃣ 检查后手动提交 ✅
`; document.body.appendChild(panel); // 事件绑定 document.getElementById('clearBtn').onclick = () => { clearAllAnswers(); showMessage('✓ 已清空', 'success'); }; document.getElementById('getBtn').onclick = () => { if (confirm('将随机填充并提交以获取答案\n\n确定继续吗?')) { firstSubmit(); } }; document.getElementById('fillBtn').onclick = () => { autoFillWithCache(); }; document.getElementById('viewBtn').onclick = () => { const data = CAStorage.get(cacheKey); if (data && data !== '{}') { try { const obj = JSON.parse(data); console.log('%c=== 缓存答案 ===', 'color: #2196F3; font-weight: bold'); console.table(obj); showMessage(`已在控制台输出\n共 ${Object.keys(obj).length} 题`, 'info'); } catch (e) { showMessage('缓存格式错误', 'error'); } } else { showMessage('暂无缓存', 'warning'); } }; document.getElementById('delBtn').onclick = () => { if (confirm('确定清除缓存?')) { CAStorage.set(cacheKey, '{}'); showMessage('已清除', 'success'); setTimeout(() => location.reload(), 1000); } }; } function init() { const pageType = detectPageType(); console.log('页面类型:', pageType); if (pageType === 'exam') { console.log('✓ 答题页面'); // 检查是否从答案页返回 if (CAStorage.get('is_getting_answer') === 'true') { console.log('检测到从答案页返回,清空表单'); setTimeout(() => { clearAllAnswers(); CAStorage.set('is_getting_answer', 'false'); }, 500); } addControlPanel(); } else if (pageType === 'result') { console.log('✓ 答案页面'); showMessage('检测到答案页面\n正在解析...', 'info'); setTimeout(() => { parseAnswersFromResultPage(); }, 2000); } else { console.log('⚠️ 未识别的页面'); } } // ===================== 统一UI面板 ===================== const UI = { panel: null, logBox: null, statusText: null, courseText: null, logExpanded: false, init() { this.createPanel(); this.bindDrag(); AntiCheat.init(); }, createPanel() { const panel = document.createElement('div'); panel.id = 'auto-study-panel'; panel.style.cssText = ` position: fixed; top: 100px; right: 20px; z-index: 2147483647; width: 300px; background: #ffffff; border-radius: 10px; box-shadow: 0 6px 20px rgba(0,0,0,0.18); font-family: "Microsoft YaHei", "PingFang SC", sans-serif; font-size: 13px; user-select: none; overflow: hidden; border: 1px solid #e5e7eb; `; panel.innerHTML = `
继教助手 | ${currentPlatform?.name || '通用'} ×
当前状态:待启动
进度:等待启动
▼ 展开运行日志
`; document.body.appendChild(panel); this.panel = panel; this.logBox = panel.querySelector('#log-container'); this.statusText = panel.querySelector('#status-text'); this.courseText = panel.querySelector('#course-text'); // 绑定事件 panel.querySelector('#btn-full-auto').addEventListener('click', () => this.startFullAuto()); panel.querySelector('#btn-exam-only').addEventListener('click', () => this.startExamOnly()); panel.querySelector('#panel-close-btn').addEventListener('click', () => { window.autoRunning = false; panel.remove(); }); panel.querySelector('#log-toggle-btn').addEventListener('click', () => { this.logExpanded = !this.logExpanded; this.logBox.style.display = this.logExpanded ? 'block' : 'none'; panel.querySelector('#log-toggle-btn').textContent = this.logExpanded ? '▲ 收起运行日志' : '▼ 展开运行日志'; }); }, // 拖拽功能 bindDrag() { const titleBar = this.panel.querySelector('#panel-title-bar'); let dragging = false; let offsetX = 0; let offsetY = 0; titleBar.addEventListener('mousedown', e => { dragging = true; const rect = this.panel.getBoundingClientRect(); offsetX = e.clientX - rect.left; offsetY = e.clientY - rect.top; e.preventDefault(); }); document.addEventListener('mousemove', e => { if (!dragging) return; this.panel.style.left = (e.clientX - offsetX) + 'px'; this.panel.style.top = (e.clientY - offsetY) + 'px'; this.panel.style.right = 'auto'; }); document.addEventListener('mouseup', () => { dragging = false; }); }, updateStatus(status, course, remain = '') { this.statusText.textContent = status; this.courseText.textContent = course + (remain ? ` (剩余${remain}项)` : ''); }, appendLog(text) { if (!this.logBox) return; const line = document.createElement('div'); line.textContent = text; line.style.marginBottom = '3px'; this.logBox.appendChild(line); this.logBox.scrollTop = this.logBox.scrollHeight; }, async startFullAuto() { if (window.autoRunning) return; window.autoRunning = true; Utils.log('全程自动模式启动:课程学习→自动考试 全流程无人干预'); const studySuccess = await CourseLearner.start(); if (studySuccess && window.autoRunning) { await ExamTaker.start(); } }, async startExamOnly() { if (window.autoRunning) return; window.autoRunning = true; Utils.log('单独考试模式启动'); await ExamTaker.start(); } } // ===================== 主程序入口 ===================== function main() { if (!PLATFORM_NAME) { return; } console.log("[da] 东奥会计在线刷课助手启动,当前平台:", PLATFORM_NAME); AntiCheat.init(); setTimeout(function() { if (window.__popupGuide) { window.__popupGuide([ { text: "脚本仅作研究用途,风险自担,转滚压状态将被检测", ok: false }, { text: "建议选择适当倍速(推荐 4~8倍),过快可能被检测", ok: true }, { text: "如有打赏意愿,点击底部「打赏支持」按钮,屏幕外我们无法提供资源维护", ok: true }, { text: "继续教育需要按照官方要求完成,请努力学习", ok: true } ], "我已知晓", function() { setTimeout(function() { if (window.__popupDonate) { if (!GM.get("donate_shown", false)) { window.__popupDonate("https://i.postimg.cc/QdhkjkFG/wxpay.png", "自愿打赏,您的支持是持续更新的动力", function() { GM.set("donate_shown", true); }); } } }, 2000); }); } }, 1500); UI.init(); init(); } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", main); } else { setTimeout(main, 1000); } })(); // 东奥江西站 | 客服微信:wkds995