// ==UserScript== // @name 『帮帮客网课助手』 // @namespace http://tampermonkey.net/ // @version 1.3 // @description 动态加载模块版 - 带实时信息面板 // @author 帮帮客 // @license MIT // @match *://*.91huayi.com/* // @match *://*zhgbpx.gov.cn/* // @match *://*.yxlearning.com/* // @match *://*.cmechina.net/* // @match *://*.ghlearning.com/* // @match *://basic.smartedu.cn/teacherTraining* // @match *://*.zxx.edu.cn/teacherTraining/courseDetail* // @match *://*.qutjxjy.cn/* // @match *://*.hbysw.org/* // @match *://*.jxjyedu.org.cn/* // @match *://*.xjzyysxh.cn/* // @match *://*.mtnet.com.cn/* // @grant GM_setValue // @grant GM_getValue // @grant GM_listValues // @grant GM_xmlhttpRequest // @grant unsafeWindow // @connect gitee.com // @require https://lib.baomitu.com/jquery/1.12.4/jquery.min.js // @icon https://mmbiz.qpic.cn/mmbiz_jpg/nc15h3nWHMVYP16HAuFe6PNJcic7mB6GFnNmk61LSHfH9ZPUoOWKnZiaaB9Jze8hCyrEYzIyicOzibs3e6ZIJTlcgw/640?wx_fmt=jpeg // @run-at document-start // ==/UserScript== (function() { 'use strict'; // 只在顶层窗口执行 if (window.self !== window.top) { return; } // 防止重复执行 if (window.bbk_initialized) { console.log('帮帮客: 已执行过,跳过重复初始化'); return; } window.bbk_initialized = true; // 标记模块是否已加载 let moduleLoaded = false; // ==================== 信息面板类 ==================== class InfoPanel { constructor() { // 检查是否已存在面板 const existingPanel = document.getElementById('bbk-panel'); if (existingPanel) { console.log('面板已存在,返回现有面板'); return existingPanel.__bbkPanel; } this.messages = []; this.maxMessages = 50; this.panel = null; this.isMinimized = false; this.createPanel(); } // 创建面板 createPanel() { // 创建样式(带唯一ID) if (!document.getElementById('bbk-style')) { const style = document.createElement('style'); style.id = 'bbk-style'; style.textContent = ` #bbk-panel { position: fixed; top: 20px; right: 20px; width: 350px; max-height: 500px; background: rgba(0, 0, 0, 0.85); color: #fff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.5); z-index: 2147483647; font-family: 'Microsoft YaHei', sans-serif; font-size: 13px; transition: all 0.3s ease; border-left: 4px solid #ff7f01; } #bbk-panel.minimized { width: 200px; cursor: pointer; } #bbk-panel.minimized .bbk-content, #bbk-panel.minimized .bbk-footer { display: none; } #bbk-panel .bbk-header { padding: 10px 15px; background: rgba(255, 127, 1, 0.2); border-bottom: 1px solid rgba(255,255,255,0.1); cursor: move; user-select: none; display: flex; justify-content: space-between; align-items: center; } #bbk-panel .bbk-title { font-weight: bold; color: #ff7f01; } #bbk-panel .bbk-title i { margin-right: 5px; } #bbk-panel .bbk-controls { display: flex; gap: 8px; } #bbk-panel .bbk-controls span { cursor: pointer; opacity: 0.7; transition: opacity 0.2s; width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; border-radius: 3px; } #bbk-panel .bbk-controls span:hover { opacity: 1; background: rgba(255,255,255,0.2); } #bbk-panel .bbk-content { max-height: 350px; overflow-y: auto; padding: 10px; } #bbk-panel .bbk-message { padding: 6px 8px; margin-bottom: 4px; border-radius: 4px; background: rgba(255,255,255,0.05); border-left: 2px solid transparent; word-break: break-word; animation: fadeIn 0.3s; } #bbk-panel .bbk-message.info { border-left-color: #2196F3; } #bbk-panel .bbk-message.success { border-left-color: #4CAF50; } #bbk-panel .bbk-message.warning { border-left-color: #FFC107; } #bbk-panel .bbk-message.error { border-left-color: #F44336; } #bbk-panel .bbk-message.debug { border-left-color: #9C27B0; opacity: 0.7; } #bbk-panel .bbk-time { color: #888; font-size: 11px; margin-right: 6px; } #bbk-panel .bbk-footer { padding: 8px 15px; background: rgba(0,0,0,0.3); border-top: 1px solid rgba(255,255,255,0.1); display: flex; justify-content: space-between; font-size: 11px; color: #aaa; } #bbk-panel .bbk-footer span { cursor: pointer; } #bbk-panel .bbk-footer span:hover { color: #ff7f01; } @keyframes fadeIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } #bbk-panel .bbk-content::-webkit-scrollbar { width: 6px; } #bbk-panel .bbk-content::-webkit-scrollbar-track { background: rgba(255,255,255,0.05); } #bbk-panel .bbk-content::-webkit-scrollbar-thumb { background: rgba(255,127,1,0.5); border-radius: 3px; } #bbk-panel .bbk-debug-badge { background: #ff7f01; color: #000; padding: 2px 6px; border-radius: 10px; font-size: 10px; margin-left: 8px; } `; document.head.appendChild(style); } // 创建面板(带唯一ID) this.panel = document.createElement('div'); this.panel.id = 'bbk-panel'; this.panel.innerHTML = `
📋 帮帮客运行日志 正式版
🗑️ ×
`; document.body.appendChild(this.panel); // 保存实例到DOM元素 this.panel.__bbkPanel = this; // 绑定事件 this.bindEvents(); // 使面板可拖动 this.makeDraggable(); this.info('面板已初始化'); } // 绑定事件 bindEvents() { const minimize = this.panel.querySelector('.bbk-minimize'); const clear = this.panel.querySelector('.bbk-clear'); const close = this.panel.querySelector('.bbk-close'); const copy = this.panel.querySelector('.bbk-copy'); const toggleDebug = this.panel.querySelector('.bbk-toggle-debug'); minimize.addEventListener('click', (e) => { e.stopPropagation(); this.toggleMinimize(); }); clear.addEventListener('click', (e) => { e.stopPropagation(); this.clear(); }); close.addEventListener('click', (e) => { e.stopPropagation(); this.panel.remove(); window.bbk_initialized = false; // 允许重新创建 }); copy.addEventListener('click', (e) => { e.stopPropagation(); this.copyLogs(); }); toggleDebug.addEventListener('click', (e) => { e.stopPropagation(); this.toggleDebug(); }); } // 使面板可拖动 makeDraggable() { const header = this.panel.querySelector('.bbk-header'); let isDragging = false; let offsetX, offsetY; header.addEventListener('mousedown', (e) => { if (e.target.classList.contains('bbk-controls') || e.target.parentElement.classList.contains('bbk-controls')) { return; } isDragging = true; offsetX = e.clientX - this.panel.offsetLeft; offsetY = e.clientY - this.panel.offsetTop; this.panel.style.cursor = 'grabbing'; }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; e.preventDefault(); this.panel.style.left = (e.clientX - offsetX) + 'px'; this.panel.style.top = (e.clientY - offsetY) + 'px'; this.panel.style.right = 'auto'; }); document.addEventListener('mouseup', () => { isDragging = false; this.panel.style.cursor = ''; }); } // 切换最小化 toggleMinimize() { this.isMinimized = !this.isMinimized; if (this.isMinimized) { this.panel.classList.add('minimized'); this.panel.querySelector('.bbk-minimize').textContent = '□'; } else { this.panel.classList.remove('minimized'); this.panel.querySelector('.bbk-minimize').textContent = '−'; } } // 添加消息 addMessage(text, type = 'info') { // 过滤干扰信息 if (text.includes('继续教育 >>') || text.includes('2025年公需课') || text.includes('华南理工大学')) { return; } const time = new Date().toLocaleTimeString(); const message = { text, type, time }; this.messages.push(message); if (this.messages.length > this.maxMessages) { this.messages.shift(); } this.render(); // 自动滚动到底部 const content = this.panel.querySelector('.bbk-content'); content.scrollTop = content.scrollHeight; } // 渲染消息 render() { const content = this.panel.querySelector('.bbk-content'); content.innerHTML = this.messages.map(msg => `
[${msg.time}] ${this.escapeHtml(msg.text)}
`).join(''); } // 转义HTML escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // 清空消息 clear() { this.messages = []; this.render(); } // 复制日志 copyLogs() { const text = this.messages.map(msg => `[${msg.time}] [${msg.type}] ${msg.text}` ).join('\n'); navigator.clipboard.writeText(text).then(() => { this.success('日志已复制到剪贴板'); }).catch(() => { this.error('复制失败'); }); } // 切换调试信息显示 toggleDebug() { const btn = this.panel.querySelector('.bbk-toggle-debug'); if (btn.textContent.includes('显示')) { btn.textContent = '🐞 隐藏调试'; this.render(); } else { btn.textContent = '🐞 显示调试'; const filtered = this.messages.filter(m => m.type !== 'debug'); const content = this.panel.querySelector('.bbk-content'); content.innerHTML = filtered.map(msg => `
[${msg.time}] ${this.escapeHtml(msg.text)}
`).join(''); } } // 各种类型的消息 info(text, source = '') { const prefix = source ? `[${source}] ` : ''; this.addMessage(`ℹ️ ${prefix}${text}`, 'info'); } success(text, source = '') { const prefix = source ? `[${source}] ` : ''; this.addMessage(`✅ ${prefix}${text}`, 'success'); } warning(text, source = '') { const prefix = source ? `[${source}] ` : ''; this.addMessage(`⚠️ ${prefix}${text}`, 'warning'); } error(text, source = '') { const prefix = source ? `[${source}] ` : ''; this.addMessage(`❌ ${prefix}${text}`, 'error'); } debug(text, source = '') { const prefix = source ? `[${source}] ` : ''; this.addMessage(`🔍 ${prefix}${text}`, 'debug'); } } // ==================== 全局变量 ==================== let infoPanel = null; // ==================== 初始化面板 ==================== function initInfoPanel() { if (!infoPanel) { infoPanel = new InfoPanel(); // 拦截console.log,同时输出到面板 const originalLog = console.log; console.log = function(...args) { originalLog.apply(console, args); if (infoPanel) { infoPanel.debug(args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : arg ).join(' '), 'console'); } }; } return infoPanel; } // ==================== Gitee仓库地址 ==================== const GITEE_BASE = 'https://gitee.com/wild-goose-dayan/bbk-assistant/raw/master'; // ==================== 平台配置 ==================== const PLATFORMS = { 'ghlearning.com': { name: '河南专技', module: 'henan.js', check: (url) => url.includes('ghlearning.com') }, 'zxx.edu.cn': { name: '国家中小学教育', module: 'edu.js', check: (url) => url.includes('zxx.edu.cn') && url.includes('courseDetail') }, '91huayi.com': { name: '华医网继续医学教育', module: 'huayi.js', check: (url) => url.includes('91huayi.com') }, 'zhgbpx.gov.cn': { name: '珠海干部网络学院', module: 'zhgbpx.js', check: (url) => url.includes('zhgbpx.gov.cn') } }; // ==================== 加载模块 ==================== function loadModule(moduleName, platformName) { return new Promise((resolve, reject) => { if (moduleLoaded) { console.log('模块已加载,跳过'); return; } const url = `${GITEE_BASE}/modules/${moduleName}`; GM_xmlhttpRequest({ method: 'GET', url: url, onload: function(response) { if (response.status === 200) { try { // 创建模块容器,并传入 unsafeWindow const module = {}; // 执行模块代码,传入 unsafeWindow 和其他需要的全局变量 new Function('module', 'unsafeWindow', 'window', 'document', '$', 'platformName', response.responseText)(module, unsafeWindow, window, document, jQuery, platformName); if (module && module.exports) { infoPanel.success(`模块解析成功: ${moduleName}`); resolve(module.exports); } else { throw new Error('模块格式错误'); } } catch (e) { infoPanel.error(`模块执行错误: ${e.message}`, 'loader'); reject(e); } } else { infoPanel.error(`HTTP错误: ${response.status}`, 'loader'); reject(new Error(`HTTP ${response.status}`)); } }, onerror: function(err) { infoPanel.error(`网络错误: ${err}`, 'loader'); reject(err); } }); }); } // ==================== 主程序 ==================== function init() { if (moduleLoaded) { console.log('主程序已执行,跳过'); return; } // 等待DOM就绪 if (!document.body) { setTimeout(init, 100); return; } // 初始化信息面板 const panel = initInfoPanel(); const url = window.location.href; // 检测平台 let platformFound = false; for (const [domain, config] of Object.entries(PLATFORMS)) { if (config.check(url)) { platformFound = true; panel.success(`检测到平台: ${config.name}`, 'main'); loadModule(config.module, config.name) .then(module => { if (module && module.init) { // 给模块传递面板实例 if (module.setPanel) { module.setPanel(panel); } module.init(); panel.success(`✅ ${config.name} 启动成功`, 'main'); } }) .catch(err => { panel.error(`❌ ${config.name} 加载失败: ${err.message}`, 'main'); }); break; } } if (!platformFound) { panel.warning('未检测到支持的平台', 'main'); } } // ==================== 启动脚本 ==================== if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();