feat: 精简日志

This commit is contained in:
zdl
2025-11-26 15:34:11 +08:00
parent 64f8914951
commit 9df725b748
4 changed files with 83 additions and 252 deletions

View File

@@ -15,6 +15,10 @@
import { useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
// ⚡ 模块级变量:防止 React StrictMode 双重初始化
let widgetInitialized = false;
let idleCallbackId = null;
const BytedeskWidget = ({
config,
autoLoad = true,
@@ -27,110 +31,98 @@ const BytedeskWidget = ({
useEffect(() => {
// 如果不自动加载或配置未设置,跳过
if (!autoLoad || !config) {
if (!config) {
console.warn('[Bytedesk] 配置未设置,客服组件未加载');
}
return;
}
console.log('[Bytedesk] 开始加载客服Widget...', config);
// ⚡ 防止重复初始化React StrictMode 会双重调用 useEffect
if (widgetInitialized) {
return;
}
// 加载Bytedesk Widget脚本
const script = document.createElement('script');
script.src = 'https://www.weiyuai.cn/embed/bytedesk-web.js';
script.async = true;
script.id = 'bytedesk-web-script';
// ⚡ 使用 requestIdleCallback 延迟加载,不阻塞首屏
const loadWidget = () => {
// 再次检查,防止竞态条件
if (widgetInitialized) return;
widgetInitialized = true;
script.onload = () => {
console.log('[Bytedesk] Widget脚本加载成功');
// 检查脚本是否已存在
if (document.getElementById('bytedesk-web-script')) {
return;
}
try {
if (window.BytedeskWeb) {
console.log('[Bytedesk] 初始化Widget');
const bytedesk = new window.BytedeskWeb(config);
bytedesk.init();
// 加载Bytedesk Widget脚本
const script = document.createElement('script');
script.src = 'https://www.weiyuai.cn/embed/bytedesk-web.js';
script.async = true;
script.id = 'bytedesk-web-script';
widgetRef.current = bytedesk;
console.log('[Bytedesk] Widget初始化成功');
script.onload = () => {
try {
if (window.BytedeskWeb) {
const bytedesk = new window.BytedeskWeb(config);
bytedesk.init();
widgetRef.current = bytedesk;
// ⚡ 屏蔽 STOMP WebSocket 错误日志(不影响功能)
// Bytedesk SDK 内部的 /stomp WebSocket 连接失败不影响核心客服功能
// SDK 会自动降级使用 HTTP 轮询
const originalConsoleError = console.error;
console.error = function(...args) {
const errorMsg = args.join(' ');
// 忽略 /stomp 和 STOMP 相关错误
if (errorMsg.includes('/stomp') ||
errorMsg.includes('stomp onWebSocketError') ||
(errorMsg.includes('WebSocket connection to') && errorMsg.includes('/stomp'))) {
return; // 不输出日志
// ⚡ 屏蔽 STOMP WebSocket 错误日志(不影响功能)
const originalConsoleError = console.error;
console.error = function(...args) {
const errorMsg = args.join(' ');
if (errorMsg.includes('/stomp') ||
errorMsg.includes('stomp onWebSocketError') ||
(errorMsg.includes('WebSocket connection to') && errorMsg.includes('/stomp'))) {
return;
}
originalConsoleError.apply(console, args);
};
if (onLoad) {
onLoad(bytedesk);
}
originalConsoleError.apply(console, args);
};
if (onLoad) {
onLoad(bytedesk);
} else {
throw new Error('BytedeskWeb对象未定义');
}
} catch (error) {
console.error('[Bytedesk] 初始化失败:', error);
if (onError) {
onError(error);
}
} else {
throw new Error('BytedeskWeb对象未定义');
}
} catch (error) {
console.error('[Bytedesk] Widget初始化失败:', error);
};
script.onerror = (error) => {
console.error('[Bytedesk] 脚本加载失败:', error);
widgetInitialized = false; // 允许重试
if (onError) {
onError(error);
}
}
};
document.body.appendChild(script);
scriptRef.current = script;
};
script.onerror = (error) => {
console.error('[Bytedesk] Widget脚本加载失败:', error);
if (onError) {
onError(error);
}
};
// ⚡ 使用 requestIdleCallback 在浏览器空闲时加载
if ('requestIdleCallback' in window) {
idleCallbackId = requestIdleCallback(loadWidget, { timeout: 3000 });
} else {
// 降级:使用 setTimeout
idleCallbackId = setTimeout(loadWidget, 100);
}
// 添加脚本到页面
document.body.appendChild(script);
scriptRef.current = script;
// 清理函数 - 增强错误处理,防止 React 18 StrictMode 双重清理报错
// 清理函数
return () => {
console.log('[Bytedesk] 清理Widget');
// 移除脚本
try {
if (scriptRef.current && scriptRef.current.parentNode) {
scriptRef.current.parentNode.removeChild(scriptRef.current);
// 取消待执行的 idle callback
if (idleCallbackId) {
if ('cancelIdleCallback' in window) {
cancelIdleCallback(idleCallbackId);
} else {
clearTimeout(idleCallbackId);
}
scriptRef.current = null;
} catch (error) {
console.warn('[Bytedesk] 移除脚本失败(可能已被移除):', error.message);
idleCallbackId = null;
}
// 移除Widget DOM元素
try {
const widgetElements = document.querySelectorAll('[class*="bytedesk"], [id*="bytedesk"]');
widgetElements.forEach(el => {
try {
if (el && el.parentNode && el.parentNode.contains(el)) {
el.parentNode.removeChild(el);
}
} catch (err) {
// 忽略单个元素移除失败(可能已被移除)
}
});
} catch (error) {
console.warn('[Bytedesk] 清理Widget DOM元素失败:', error.message);
}
// 清理全局对象
try {
if (window.BytedeskWeb) {
delete window.BytedeskWeb;
}
} catch (error) {
console.warn('[Bytedesk] 清理全局对象失败:', error.message);
}
// ⚠️ 不重置 widgetInitialized保持单例
// 不清理 DOM因为客服 Widget 应该持久存在
};
}, [config, autoLoad, onLoad, onError]);