import { HapticTab } from '@/components/HapticTab'; import AskNavbar from '@/components/layout/ask'; import { TabBarIcon } from '@/components/navigation/TabBarIcon'; import { requestNotificationPermission } from '@/components/owner/utils'; import TabBarBackground from '@/components/ui/TabBarBackground'; import { Colors } from '@/constants/Colors'; import { useColorScheme } from '@/hooks/useColorScheme'; import { prefetchChats } from '@/lib/prefetch'; import { fetchApi } from '@/lib/server-api-util'; import { webSocketManager, WebSocketStatus } from '@/lib/websocket-util'; import { TransitionPresets } from '@react-navigation/bottom-tabs'; import * as Notifications from 'expo-notifications'; import { Tabs } from 'expo-router'; import * as SecureStore from 'expo-secure-store'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Platform } from 'react-native'; interface PollingData { title: string; id: string; content: string; extra: any; } export default function TabLayout() { const { t } = useTranslation(); const colorScheme = useColorScheme(); const [pollingData, setPollingData] = useState([]); const pollingInterval = useRef(null); const tokenInterval = useRef(null); const isMounted = useRef(true); const [token, setToken] = useState(''); const [wsStatus, setWsStatus] = useState('disconnected'); const sendNotification = async (item: PollingData) => { // 请求通知权限 const granted = await requestNotificationPermission(); if (!granted) { console.log('用户拒绝了通知权限'); return; } // 调度本地通知 await Notifications.scheduleNotificationAsync({ content: { title: item.title, body: item.content, data: { screen: 'ask', extra: item.extra, id: item.id }, priority: 'high', // 关键:设置 high 或 max }, trigger: { seconds: 2, // 延迟2秒显示 type: Notifications.SchedulableTriggerInputTypes.TIME_INTERVAL // 添加 type 字段 }, // 延迟2秒显示 }); }; // 监听通知点击事件 useEffect(() => { const notificationListener = Notifications.addNotificationResponseReceivedListener(response => { const data = response.notification.request.content.data; console.log('通知被点击,数据:', data); pollingData?.filter((item) => item.id !== data.id); }); // 清理监听器 return () => { Notifications.removeNotificationSubscription(notificationListener); }; }, []); useEffect(() => { const handleStatusChange = (status: WebSocketStatus) => { setWsStatus(status); }; webSocketManager.subscribeStatus(handleStatusChange); return () => { webSocketManager.unsubscribeStatus(handleStatusChange); }; }, []); // 轮询获取推送消息 const startPolling = useCallback(async (interval: number = 5000) => { // 设置轮询 pollingInterval.current = setInterval(async () => { if (isMounted.current) { await getMessageData(); } }, interval); // 返回清理函数 return () => { if (pollingInterval.current) { clearInterval(pollingInterval.current); } }; }, []); // 获取推送消息 const getMessageData = async () => { try { const response = await fetchApi("/notice/push/message", { method: "POST" }); setPollingData((prev) => ([...prev, ...response])); } catch (error) { console.error('获取轮询数据时出错:', error); } }; // 获取认证token const getAuthToken = async (): Promise => { let tokenValue = ''; if (Platform.OS === 'web') { tokenValue = localStorage.getItem('token') || ''; } else { tokenValue = (await SecureStore.getItemAsync('token')) || ''; } setToken(tokenValue); // 只在获取到新token时更新状态 return tokenValue; }; useEffect(() => { const checkAuthStatus = async () => { try { if (token) { // 启动轮询 startPolling(5000); } } catch (error) { console.error('获取推送消息出错:', error); } }; checkAuthStatus(); return () => { // 清理函数 if (pollingInterval.current) { clearInterval(pollingInterval.current); } isMounted.current = false; }; }, [token]); // 本地推送 useEffect(() => { pollingData?.map((item) => { sendNotification(item) }) }, [pollingData]) // 轮询获取token useEffect(() => { // 如果已经有token,直接返回 if (token) { if (tokenInterval.current) { clearInterval(tokenInterval.current); } return; } if (!tokenInterval.current) return; // 设置轮询 tokenInterval.current = setInterval(async () => { if (isMounted.current) { const currentToken = await getAuthToken(); // 如果获取到token,清除定时器 if (currentToken && tokenInterval.current) { clearInterval(tokenInterval.current); } } }, 5000); // 返回清理函数 return () => { if (tokenInterval.current) { clearInterval(tokenInterval.current); } }; }, [token]); // 添加token作为依赖 useEffect(() => { if (token) { prefetchChats().catch(console.error); } }, [token]); return ( <> {/* 落地页 */} null, // 隐藏底部标签栏 headerShown: false, // 隐藏导航栏 tabBarStyle: { display: 'none' } // 确保在标签栏中不显示 }} /> {/* 登录 */} null, // 隐藏底部标签栏 headerShown: false, // 隐藏导航栏 tabBarStyle: { display: 'none' } // 确保在标签栏中不显示 }} /> {/* 重置密码 */} null, // 隐藏底部标签栏 headerShown: false, // 隐藏导航栏 tabBarStyle: { display: 'none' } // 确保在标签栏中不显示 }} /> {/* loading页面 */} null, // 隐藏底部标签栏 headerShown: false, // 隐藏导航栏 tabBarStyle: { display: 'none' } // 确保在标签栏中不显示 }} /> {/* 用户信息收集 */} null, // 隐藏底部标签栏 headerShown: false, // 隐藏导航栏 tabBarStyle: { display: 'none' } // 确保在标签栏中不显示 }} /> {/* ask页面 */} null, // 隐藏底部标签栏 headerShown: false, // 隐藏导航栏 tabBarStyle: { display: 'none' }, // 确保在标签栏中不显示 ...TransitionPresets.ShiftTransition, }} /> {/* memo list */} null, // 隐藏底部标签栏 headerShown: false, // 隐藏导航栏 tabBarStyle: { display: 'none' }, // 确保在标签栏中不显示 ...TransitionPresets.ShiftTransition, }} /> {/* owner */} null, // 隐藏底部标签栏 headerShown: false, // 隐藏导航栏 tabBarStyle: { display: 'none' }, // 确保在标签栏中不显示 ...TransitionPresets.ShiftTransition, }} /> {/* 排行榜 */} null, // 隐藏底部标签栏 headerShown: false, // 隐藏导航栏 tabBarStyle: { display: 'none' } // 确保在标签栏中不显示 }} /> {/* 隐私协议 */} null, // 隐藏底部标签栏 headerShown: false, // 隐藏导航栏 tabBarStyle: { display: 'none' } // 确保在标签栏中不显示 }} /> {/* Support Screen */} null, // 隐藏底部标签栏 headerShown: false, // 隐藏导航栏 tabBarStyle: { display: 'none' } // 确保在标签栏中不显示 }} /> {/* Debug Screen - only in development */} {process.env.NODE_ENV === 'development' && ( ( ), }} /> )} {/* 下载页面 */} null, // 隐藏底部标签栏 headerShown: false, // 隐藏导航栏 tabBarStyle: { display: 'none' } // 确保在标签栏中不显示 }} /> {/* 购买权益页面 */} null, // 隐藏底部标签栏 headerShown: false, // 隐藏导航栏 tabBarStyle: { display: 'none' } // 确保在标签栏中不显示 }} /> {/* 设置页面 */} null, // 隐藏底部标签栏 headerShown: false, // 隐藏导航栏 tabBarStyle: { display: 'none' } // 确保在标签栏中不显示 }} /> ); }