// ==UserScript==
// @name 『帮帮客网课助手』
// @namespace http://tampermonkey.net/
// @version 1.2
// @description 【2026】动态加载模块版 - 带实时信息面板
// @author 帮帮客
// @license MIT
// @match *://*.91huayi.com/*
// @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')
}
};
// ==================== 加载模块 ====================
function loadModule(moduleName) {
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', '$',
response.responseText)(module, unsafeWindow, window, document, jQuery);
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)
.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();
}
})();