diff --git a/src/components/GlobalComponents.js b/src/components/GlobalComponents.js index fd1be054..f6231c23 100644 --- a/src/components/GlobalComponents.js +++ b/src/components/GlobalComponents.js @@ -9,7 +9,6 @@ import { logger } from '../utils/logger'; // Global Components import AuthModalManager from './Auth/AuthModalManager'; import NotificationContainer from './NotificationContainer'; -import NotificationTestTool from './NotificationTestTool'; import ConnectionStatusBar from './ConnectionStatusBar'; import ScrollToTop from './ScrollToTop'; @@ -71,7 +70,6 @@ function ConnectionStatusBarWrapper() { * - ScrollToTop: 路由切换时自动滚动到顶部 * - AuthModalManager: 认证弹窗管理器 * - NotificationContainer: 通知容器 - * - NotificationTestTool: 通知测试工具 (仅开发环境) * - BytedeskWidget: Bytedesk在线客服 (条件性显示,在/和/home页隐藏) */ export function GlobalComponents() { @@ -92,9 +90,6 @@ export function GlobalComponents() { {/* 通知容器 */} - {/* 通知测试工具 (仅开发环境) */} - - {/* Bytedesk在线客服 - 根据路径条件性显示 */} {showBytedesk && ( { - // 只在开发环境显示 - 必须在所有 Hooks 调用之前检查 - if (process.env.NODE_ENV !== 'development') { - return null; - } - - const { isOpen, onToggle } = useDisclosure(); - const { addNotification, soundEnabled, toggleSound, isConnected, clearAllNotifications, notifications, browserPermission, requestBrowserPermission } = useNotification(); - const [testCount, setTestCount] = useState(0); - - // 测试状态 - const [isTestingNotification, setIsTestingNotification] = useState(false); - const [testCountdown, setTestCountdown] = useState(0); - const [notificationShown, setNotificationShown] = useState(null); // null | true | false - - // 系统环境检测 - const [isFullscreen, setIsFullscreen] = useState(false); - const [isMacOS, setIsMacOS] = useState(false); - - // 故障排查面板 - const { isOpen: isTroubleshootOpen, onToggle: onTroubleshootToggle } = useDisclosure(); - - // 检测系统环境 - useEffect(() => { - // 检测是否为 macOS - const platform = navigator.platform.toLowerCase(); - setIsMacOS(platform.includes('mac')); - - // 检测全屏状态 - const checkFullscreen = () => { - setIsFullscreen(!!document.fullscreenElement); - }; - document.addEventListener('fullscreenchange', checkFullscreen); - checkFullscreen(); - - return () => { - document.removeEventListener('fullscreenchange', checkFullscreen); - }; - }, []); - - // 倒计时逻辑 - useEffect(() => { - if (testCountdown > 0) { - const timer = setTimeout(() => { - setTestCountdown(testCountdown - 1); - }, 1000); - return () => clearTimeout(timer); - } else if (testCountdown === 0 && isTestingNotification) { - // 倒计时结束,询问用户 - setIsTestingNotification(false); - - // 延迟一下再询问,确保用户有时间看到通知 - setTimeout(() => { - const sawNotification = window.confirm('您是否看到了浏览器桌面通知?\n\n点击"确定"表示看到了\n点击"取消"表示没看到'); - setNotificationShown(sawNotification); - - if (!sawNotification) { - // 没看到通知,展开故障排查面板 - if (!isTroubleshootOpen) { - onTroubleshootToggle(); - } - } - }, 500); - } - }, [testCountdown, isTestingNotification, isTroubleshootOpen, onTroubleshootToggle]); - - // 浏览器权限状态标签 - const getPermissionLabel = () => { - switch (browserPermission) { - case 'granted': - return '已授权'; - case 'denied': - return '已拒绝'; - case 'default': - return '未授权'; - default: - return '不支持'; - } - }; - - const getPermissionColor = () => { - switch (browserPermission) { - case 'granted': - return 'green'; - case 'denied': - return 'red'; - case 'default': - return 'gray'; - default: - return 'gray'; - } - }; - - // 请求浏览器权限 - const handleRequestPermission = async () => { - await requestBrowserPermission(); - }; - - // 公告通知测试数据 - const testAnnouncement = () => { - addNotification({ - type: NOTIFICATION_TYPES.ANNOUNCEMENT, - priority: PRIORITY_LEVELS.IMPORTANT, - title: '【测试】贵州茅台发布2024年度财报公告', - content: '2024年度营收同比增长15.2%,净利润创历史新高,董事会建议每10股派息180元', - publishTime: Date.now(), - pushTime: Date.now(), - isAIGenerated: false, - clickable: true, - link: '/event-detail/test001', - extra: { - announcementType: '财报', - companyCode: '600519', - companyName: '贵州茅台', - }, - autoClose: 10000, - }); - setTestCount(prev => prev + 1); - }; - - - // 事件动向测试数据 - const testEventAlert = () => { - addNotification({ - type: NOTIFICATION_TYPES.EVENT_ALERT, - priority: PRIORITY_LEVELS.IMPORTANT, - title: '【测试】央行宣布降准0.5个百分点', - content: '中国人民银行宣布下调金融机构存款准备金率0.5个百分点,释放长期资金约1万亿元,利好股市', - publishTime: Date.now(), - pushTime: Date.now(), - isAIGenerated: false, - clickable: true, - link: '/event-detail/test003', - extra: { - eventId: 'test003', - relatedStocks: 12, - impactLevel: '重大利好', - }, - autoClose: 12000, - }); - setTestCount(prev => prev + 1); - }; - - // 分析报告测试数据(非AI) - const testAnalysisReport = () => { - addNotification({ - type: NOTIFICATION_TYPES.ANALYSIS_REPORT, - priority: PRIORITY_LEVELS.IMPORTANT, - title: '【测试】医药行业深度报告:创新药迎来政策拐点', - content: 'CXO板块持续受益于全球创新药研发外包需求,建议关注药明康德、凯莱英等龙头企业', - publishTime: Date.now(), - pushTime: Date.now(), - author: { - name: '李明', - organization: '中信证券', - }, - isAIGenerated: false, - clickable: true, - link: '/forecast-report?id=test004', - extra: { - reportType: '行业研报', - industry: '医药', - }, - autoClose: 12000, - }); - setTestCount(prev => prev + 1); - }; - - - // 预测通知测试数据(不可跳转) - const testPrediction = () => { - addNotification({ - type: NOTIFICATION_TYPES.EVENT_ALERT, - priority: PRIORITY_LEVELS.NORMAL, - title: '【测试】【预测】央行可能宣布降准政策', - content: '基于最新宏观数据分析,预计央行将在本周宣布降准0.5个百分点,释放长期资金', - publishTime: Date.now(), - pushTime: Date.now(), - isAIGenerated: true, - clickable: false, // ❌ 不可点击 - link: null, - extra: { - isPrediction: true, - statusHint: '详细报告生成中...', - }, - autoClose: 15000, - }); - setTestCount(prev => prev + 1); - }; - - // 预测→详情流程测试(先推预测,5秒后推详情) - const testPredictionFlow = () => { - // 阶段 1: 推送预测 - addNotification({ - type: NOTIFICATION_TYPES.EVENT_ALERT, - priority: PRIORITY_LEVELS.NORMAL, - title: '【测试】【预测】新能源汽车补贴政策将延期', - content: '根据政策趋势分析,预计财政部将宣布新能源汽车购置补贴政策延长至2025年底', - publishTime: Date.now(), - pushTime: Date.now(), - isAIGenerated: true, - clickable: false, - link: null, - extra: { - isPrediction: true, - statusHint: '详细报告生成中...', - relatedPredictionId: 'pred_test_001', - }, - autoClose: 15000, - }); - setTestCount(prev => prev + 1); - - // 阶段 2: 5秒后推送详情 - setTimeout(() => { - addNotification({ - type: NOTIFICATION_TYPES.EVENT_ALERT, - priority: PRIORITY_LEVELS.IMPORTANT, - title: '【测试】新能源汽车补贴政策延期至2025年底', - content: '财政部宣布新能源汽车购置补贴政策延长至2025年底,涉及比亚迪、理想汽车等5家龙头企业', - publishTime: Date.now(), - pushTime: Date.now(), - isAIGenerated: false, - clickable: true, // ✅ 可点击 - link: '/event-detail/test_pred_001', - extra: { - isPrediction: false, - relatedPredictionId: 'pred_test_001', - eventId: 'test_pred_001', - relatedStocks: 5, - impactLevel: '重大利好', - }, - autoClose: 12000, - }); - setTestCount(prev => prev + 1); - }, 5000); - }; - - - return ( - - {/* 折叠按钮 */} - - - - 金融资讯测试工具 - - - {isConnected ? 'Connected' : 'Disconnected'} - - - REAL - - - 浏览器: {getPermissionLabel()} - - : } - size="xs" - variant="ghost" - colorScheme="whiteAlpha" - aria-label={isOpen ? '关闭' : '打开'} - /> - - - {/* 工具面板 */} - - - - 通知类型测试 - - - {/* 公告通知 */} - - - {/* 事件动向 */} - - - {/* 分析报告 */} - - - {/* 预测通知 */} - - - - - - 组合测试 - - - {/* 预测→详情流程测试 */} - - - - - - 浏览器通知 - - - {/* 请求权限按钮 */} - {browserPermission !== 'granted' && ( - - )} - - {/* 测试浏览器通知按钮 */} - {browserPermission === 'granted' && ( - - )} - - {/* 浏览器通知状态说明 */} - {browserPermission === 'granted' && ( - - ✅ 浏览器通知已启用 - - )} - {browserPermission === 'denied' && ( - - ❌ 请在浏览器设置中允许通知 - - )} - - {/* 实时权限状态 */} - - - 实际权限: - - - {('Notification' in window) ? Notification.permission : '不支持'} - - - - {/* 环境警告 */} - {isFullscreen && ( - - - - 全屏模式 - 某些浏览器在全屏模式下不显示通知 - - - )} - - {isMacOS && notificationShown === false && ( - - - - 未检测到通知显示 - 可能是专注模式阻止了通知 - - - )} - - - - {/* 故障排查面板 */} - - - - - - - 如果看不到浏览器通知,请检查: - - - {/* macOS 专注模式 */} - {isMacOS && ( - - - - macOS 专注模式 - - - 点击右上角控制中心 - 关闭「专注模式」或「勿扰模式」 - 或者:系统设置 → 专注模式 → 关闭 - - - - - )} - - {/* macOS 系统通知设置 */} - {isMacOS && ( - - - - macOS 系统通知设置 - - - 系统设置 → 通知 - 找到 Google ChromeMicrosoft Edge - 确保「允许通知」已开启 - 通知样式设置为「横幅」或「提醒」 - - - - - )} - - {/* Chrome 浏览器设置 */} - - - - Chrome 浏览器设置 - - - 地址栏输入: chrome://settings/content/notifications - 确保「网站可以请求发送通知」已开启 - 检查本站点是否在「允许」列表中 - - - - - - {/* 全屏模式提示 */} - {isFullscreen && ( - - - - 退出全屏模式 - - 按 ESC 键退出全屏,然后重新测试 - - - - )} - - {/* 测试结果反馈 */} - {notificationShown === true && ( - - - ✅ 通知功能正常! - - )} - - - - - - - {/* 功能按钮 */} - - - - : } - colorScheme={soundEnabled ? 'blue' : 'gray'} - onClick={toggleSound} - aria-label="切换音效" - /> - - - {/* 统计信息 */} - - - - 当前队列: - - = 5 ? 'red' : 'blue'}> - {notifications.length} / 5 - - - - 已测试: {testCount} 条通知 - - - - - - ); -}; - -export default NotificationTestTool; diff --git a/src/devtools/index.js b/src/devtools/index.js index cb672545..f0d3c746 100644 --- a/src/devtools/index.js +++ b/src/devtools/index.js @@ -10,20 +10,17 @@ * 全局 API: * - window.__DEBUG__ - 调试 API 主对象 * - window.__DEBUG__.api - API 调试工具 - * - window.__DEBUG__.notification - 通知调试工具 * - window.__DEBUG__.socket - Socket 调试工具 * - window.__DEBUG__.help() - 显示帮助信息 * - window.__DEBUG__.exportAll() - 导出所有日志 */ import { apiDebugger } from './apiDebugger'; -import { notificationDebugger } from './notificationDebugger'; import { socketDebugger } from './socketDebugger'; class DebugToolkit { constructor() { this.api = apiDebugger; - this.notification = notificationDebugger; this.socket = socketDebugger; } @@ -47,7 +44,6 @@ class DebugToolkit { // 初始化各个调试工具 this.api.init(); - this.notification.init(); this.socket.init(); // 暴露到全局 @@ -69,22 +65,13 @@ class DebugToolkit { console.log(' __DEBUG__.api.exportLogs() - 导出 API 日志'); console.log(' __DEBUG__.api.testRequest(method, endpoint, data) - 测试 API 请求'); console.log(''); - console.log('%c2️⃣ 通知调试:', 'color: #9C27B0; font-weight: bold;'); - console.log(' __DEBUG__.notification.getLogs() - 获取所有通知日志'); - console.log(' __DEBUG__.notification.forceNotification() - 发送测试浏览器通知'); - console.log(' __DEBUG__.notification.testWebNotification(type, priority) - 测试网页通知 🆕'); - console.log(' __DEBUG__.notification.testAllNotificationTypes() - 测试所有类型 🆕'); - console.log(' __DEBUG__.notification.testAllNotificationPriorities() - 测试所有优先级 🆕'); - console.log(' __DEBUG__.notification.checkPermission() - 检查通知权限'); - console.log(' __DEBUG__.notification.exportLogs() - 导出通知日志'); - console.log(''); - console.log('%c3️⃣ Socket 调试:', 'color: #00BCD4; font-weight: bold;'); + console.log('%c2️⃣ Socket 调试:', 'color: #00BCD4; font-weight: bold;'); console.log(' __DEBUG__.socket.getLogs() - 获取所有 Socket 日志'); console.log(' __DEBUG__.socket.getStatus() - 获取连接状态'); console.log(' __DEBUG__.socket.reconnect() - 手动重连'); console.log(' __DEBUG__.socket.exportLogs() - 导出 Socket 日志'); console.log(''); - console.log('%c4️⃣ 通用命令:', 'color: #4CAF50; font-weight: bold;'); + console.log('%c3️⃣ 通用命令:', 'color: #4CAF50; font-weight: bold;'); console.log(' __DEBUG__.help() - 显示帮助信息'); console.log(' __DEBUG__.exportAll() - 导出所有日志'); console.log(' __DEBUG__.printStats() - 打印所有统计信息'); @@ -113,7 +100,6 @@ class DebugToolkit { const allLogs = { timestamp: new Date().toISOString(), api: this.api.getLogs(), - notification: this.notification.getLogs(), socket: this.socket.getLogs(), }; @@ -138,15 +124,11 @@ class DebugToolkit { console.log('\n%c[API 统计]', 'color: #2196F3; font-weight: bold;'); const apiStats = this.api.printStats(); - console.log('\n%c[通知统计]', 'color: #9C27B0; font-weight: bold;'); - const notificationStats = this.notification.printStats(); - console.log('\n%c[Socket 统计]', 'color: #00BCD4; font-weight: bold;'); const socketStats = this.socket.printStats(); return { api: apiStats, - notification: notificationStats, socket: socketStats, }; } @@ -157,7 +139,6 @@ class DebugToolkit { clearAll() { console.log('[Debug Toolkit] Clearing all logs...'); this.api.clearLogs(); - this.notification.clearLogs(); this.socket.clearLogs(); console.log('[Debug Toolkit] ✅ All logs cleared'); } @@ -169,15 +150,11 @@ class DebugToolkit { console.log('\n%c=== 🔍 系统诊断 ===', 'color: #FF9800; font-weight: bold; font-size: 16px;'); // 1. Socket 状态 - console.log('\n%c[1/3] Socket 状态', 'color: #00BCD4; font-weight: bold;'); + console.log('\n%c[1/2] Socket 状态', 'color: #00BCD4; font-weight: bold;'); const socketStatus = this.socket.getStatus(); - // 2. 通知权限 - console.log('\n%c[2/3] 通知权限', 'color: #9C27B0; font-weight: bold;'); - const notificationStatus = this.notification.checkPermission(); - - // 3. API 错误 - console.log('\n%c[3/3] 最近的 API 错误', 'color: #F44336; font-weight: bold;'); + // 2. API 错误 + console.log('\n%c[2/2] 最近的 API 错误', 'color: #F44336; font-weight: bold;'); const recentErrors = this.api.getRecentErrors(5); if (recentErrors.length > 0) { console.table( @@ -193,11 +170,10 @@ class DebugToolkit { console.log('✅ 没有 API 错误'); } - // 4. 汇总报告 + // 3. 汇总报告 const report = { timestamp: new Date().toISOString(), socket: socketStatus, - notification: notificationStatus, apiErrors: recentErrors.length, }; diff --git a/src/devtools/notificationDebugger.js b/src/devtools/notificationDebugger.js deleted file mode 100644 index 0ed4867a..00000000 --- a/src/devtools/notificationDebugger.js +++ /dev/null @@ -1,204 +0,0 @@ -// src/debug/notificationDebugger.js -/** - * 通知系统调试工具 - * 扩展现有的 window.__NOTIFY_DEBUG__,添加更多生产环境调试能力 - */ - -import { browserNotificationService } from '@services/browserNotificationService'; - -class NotificationDebugger { - constructor() { - this.eventLog = []; - this.maxLogSize = 100; - } - - /** - * 初始化调试工具 - */ - init() { - console.log('%c[Notification Debugger] Initialized', 'color: #FF9800; font-weight: bold;'); - } - - /** - * 记录通知事件 - */ - logEvent(eventType, data) { - const logEntry = { - type: eventType, - timestamp: new Date().toISOString(), - data, - }; - - this.eventLog.unshift(logEntry); - if (this.eventLog.length > this.maxLogSize) { - this.eventLog = this.eventLog.slice(0, this.maxLogSize); - } - - console.log( - `%c[Notification Event] ${eventType}`, - 'color: #9C27B0; font-weight: bold;', - data - ); - } - - /** - * 获取所有事件日志 - */ - getLogs() { - return this.eventLog; - } - - /** - * 清空日志 - */ - clearLogs() { - this.eventLog = []; - console.log('[Notification Debugger] Logs cleared'); - } - - /** - * 导出日志 - */ - exportLogs() { - const blob = new Blob([JSON.stringify(this.eventLog, null, 2)], { - type: 'application/json', - }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = `notification-logs-${Date.now()}.json`; - a.click(); - URL.revokeObjectURL(url); - console.log('[Notification Debugger] Logs exported'); - } - - /** - * 强制发送浏览器通知(测试用) - */ - forceNotification(options = {}) { - const defaultOptions = { - title: '🧪 测试通知', - body: `测试时间: ${new Date().toLocaleString()}`, - tag: `test_${Date.now()}`, - requireInteraction: false, - autoClose: 5000, - }; - - const finalOptions = { ...defaultOptions, ...options }; - - console.log('[Notification Debugger] Sending test notification:', finalOptions); - - const notification = browserNotificationService.sendNotification(finalOptions); - - if (notification) { - console.log('[Notification Debugger] ✅ Notification sent successfully'); - } else { - console.error('[Notification Debugger] ❌ Failed to send notification'); - } - - return notification; - } - - /** - * 检查通知权限状态 - */ - checkPermission() { - const permission = browserNotificationService.getPermissionStatus(); - const isSupported = browserNotificationService.isSupported(); - - const status = { - supported: isSupported, - permission, - canSend: isSupported && permission === 'granted', - }; - - console.table(status); - return status; - } - - /** - * 请求通知权限 - */ - async requestPermission() { - console.log('[Notification Debugger] Requesting notification permission...'); - const result = await browserNotificationService.requestPermission(); - console.log(`[Notification Debugger] Permission result: ${result}`); - return result; - } - - /** - * 打印事件统计 - */ - printStats() { - const stats = { - total: this.eventLog.length, - byType: {}, - }; - - this.eventLog.forEach((log) => { - stats.byType[log.type] = (stats.byType[log.type] || 0) + 1; - }); - - console.log('=== Notification Stats ==='); - console.table(stats.byType); - console.log(`Total events: ${stats.total}`); - - return stats; - } - - /** - * 按类型过滤日志 - */ - getLogsByType(eventType) { - return this.eventLog.filter((log) => log.type === eventType); - } - - /** - * 获取最近的事件 - */ - getRecentEvents(count = 10) { - return this.eventLog.slice(0, count); - } - - /** - * 测试网页通知(需要 window.__TEST_NOTIFICATION__ 可用) - */ - testWebNotification(type = 'event_alert', priority = 'normal') { - if (typeof window !== 'undefined' && window.__TEST_NOTIFICATION__) { - console.log('[Notification Debugger] 调用测试 API'); - window.__TEST_NOTIFICATION__.testWebNotification(type, priority); - } else { - console.error('[Notification Debugger] ❌ window.__TEST_NOTIFICATION__ 不可用'); - console.error('💡 请确保:'); - console.error(' 1. REACT_APP_ENABLE_DEBUG=true'); - console.error(' 2. NotificationContext 已加载'); - console.error(' 3. 页面已刷新'); - } - } - - /** - * 测试所有通知类型 - */ - testAllNotificationTypes() { - if (typeof window !== 'undefined' && window.__TEST_NOTIFICATION__) { - window.__TEST_NOTIFICATION__.testAllTypes(); - } else { - console.error('[Notification Debugger] ❌ window.__TEST_NOTIFICATION__ 不可用'); - } - } - - /** - * 测试所有优先级 - */ - testAllNotificationPriorities() { - if (typeof window !== 'undefined' && window.__TEST_NOTIFICATION__) { - window.__TEST_NOTIFICATION__.testAllPriorities(); - } else { - console.error('[Notification Debugger] ❌ window.__TEST_NOTIFICATION__ 不可用'); - } - } -} - -// 导出单例 -export const notificationDebugger = new NotificationDebugger(); -export default notificationDebugger;