diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index ad4378d..2f5e889 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -1,14 +1,163 @@ -import { Tabs } from 'expo-router'; -import React from 'react'; -import { Platform } from 'react-native'; - import { HapticTab } from '@/components/HapticTab'; import TabBarBackground from '@/components/ui/TabBarBackground'; import { Colors } from '@/constants/Colors'; import { useColorScheme } from '@/hooks/useColorScheme'; +import { fetchApi } from '@/lib/server-api-util'; +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 { Platform } from 'react-native'; +interface PollingData { + title: string; + id: string; + content: string; + extra: any; +} export default function TabLayout() { const colorScheme = useColorScheme(); + const [pollingData, setPollingData] = useState([]); + const pollingInterval = useRef(null); + const tokenInterval = useRef(null); + const isMounted = useRef(true); + const [token, setToken] = useState(''); + const sendNotification = async (item: PollingData) => { + // 请求通知权限 + const { status } = await Notifications.requestPermissionsAsync(); + if (status !== 'granted') { + alert('请先允许通知权限'); + 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); + }; + }, []); + + // 轮询获取推送消息 + 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作为依赖 return (