diff --git a/src/components/GlobalComponents.js b/src/components/GlobalComponents.js index 59b4afd8..1d7e673d 100644 --- a/src/components/GlobalComponents.js +++ b/src/components/GlobalComponents.js @@ -2,95 +2,48 @@ // 集中管理应用的全局组件 import React, { useMemo } from 'react'; -import { useLocation } from 'react-router-dom'; -import { useNotification } from '../contexts/NotificationContext'; -import { logger } from '../utils/logger'; +import { useSelector } from 'react-redux'; +import { selectIsMobile } from '@/store/slices/deviceSlice'; // Global Components import AuthModalManager from './Auth/AuthModalManager'; import NotificationContainer from './NotificationContainer'; -import ConnectionStatusBar from './ConnectionStatusBar'; import ScrollToTop from './ScrollToTop'; // Bytedesk客服组件 import BytedeskWidget from '../bytedesk-integration/components/BytedeskWidget'; import { getBytedeskConfig } from '../bytedesk-integration/config/bytedesk.config'; -/** - * ConnectionStatusBar 包装组件 - * 需要在 NotificationProvider 内部使用,所以在这里包装 - */ -function ConnectionStatusBarWrapper() { - const { connectionStatus, reconnectAttempt, maxReconnectAttempts, retryConnection } = useNotification(); - const [isDismissed, setIsDismissed] = React.useState(false); - - // 监听连接状态变化 - React.useEffect(() => { - // 重连成功后,清除 dismissed 状态 - if (connectionStatus === 'connected' && isDismissed) { - setIsDismissed(false); - // 从 localStorage 清除 dismissed 标记 - localStorage.removeItem('connection_status_dismissed'); - } - - // 从 localStorage 恢复 dismissed 状态 - if (connectionStatus !== 'connected' && !isDismissed) { - const dismissed = localStorage.getItem('connection_status_dismissed'); - if (dismissed === 'true') { - setIsDismissed(true); - } - } - }, [connectionStatus, isDismissed]); - - const handleClose = () => { - // 用户手动关闭,保存到 localStorage - setIsDismissed(true); - localStorage.setItem('connection_status_dismissed', 'true'); - logger.info('App', 'Connection status bar dismissed by user'); - }; - - return ( - - ); -} - /** * GlobalComponents - 全局组件容器 * 集中管理所有全局级别的组件,如弹窗、通知、状态栏等 * * 包含的组件: - * - ConnectionStatusBarWrapper: Socket 连接状态条 * - ScrollToTop: 路由切换时自动滚动到顶部 * - AuthModalManager: 认证弹窗管理器 - * - NotificationContainer: 通知容器 - * - BytedeskWidget: Bytedesk在线客服 (条件性显示,在/和/home页隐藏) + * - NotificationContainer: 通知容器(仅桌面端渲染) + * - BytedeskWidget: Bytedesk在线客服 + * + * 注意: + * - ConnectionStatusBar 已移除(所有端) + * - NotificationContainer 在移动端不渲染(通知功能已在 NotificationContext 层禁用) */ export function GlobalComponents() { - const location = useLocation(); + const isMobile = useSelector(selectIsMobile); // ✅ 缓存 Bytedesk 配置对象,避免每次渲染都创建新引用导致重新加载 const bytedeskConfigMemo = useMemo(() => getBytedeskConfig(), []); return ( <> - {/* Socket 连接状态条 */} - - {/* 路由切换时自动滚动到顶部 */} {/* 认证弹窗管理器 */} - {/* 通知容器 */} - + {/* 通知容器(仅桌面端渲染) */} + {!isMobile && } {/* Bytedesk在线客服 - 使用缓存的配置对象 */} { // 通知提供者组件 export const NotificationProvider = ({ children }) => { + // ⚡ 移动端检测(使用 Redux 状态) + const isMobile = useSelector(selectIsMobile); + + // ⚡ 移动端禁用完整通知能力:返回空壳 Provider + // 移动端不支持桌面通知,且不需要 Socket 实时推送 + if (isMobile) { + const emptyValue = { + notifications: [], + isConnected: false, + soundEnabled: false, + browserPermission: 'default', + connectionStatus: CONNECTION_STATUS.DISCONNECTED, + reconnectAttempt: 0, + maxReconnectAttempts: 0, + addNotification: () => null, + removeNotification: () => {}, + clearAllNotifications: () => {}, + toggleSound: () => {}, + requestBrowserPermission: () => Promise.resolve('default'), + trackNotificationClick: () => {}, + retryConnection: () => {}, + showWelcomeGuide: () => {}, + showCommunityGuide: () => {}, + showFirstFollowGuide: () => {}, + registerEventUpdateCallback: () => () => {}, + unregisterEventUpdateCallback: () => {}, + }; + + return ( + + {children} + + ); + } + + // ========== 桌面端:完整通知功能 ========== const toast = useToast(); const [notifications, setNotifications] = useState([]); const [isConnected, setIsConnected] = useState(false);