chore: 初始化仓库基线(AGENTS.md、git 规范、敏感文件排除)
This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { NavigationContainer, useNavigation } from '@react-navigation/native';
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
||||
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
||||
import { Provider as PaperProvider, useTheme, MD3LightTheme } from 'react-native-paper';
|
||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import { setNavigationRef } from '../api/client';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
import { useAppStore } from '../store/appStore';
|
||||
import { wsManager } from '../utils/ws';
|
||||
import type { RootStackParamList, MainTabParamList } from '../types';
|
||||
|
||||
import LoginScreen from '../screens/LoginScreen';
|
||||
import DashboardScreen from '../screens/DashboardScreen';
|
||||
import RoomsScreen from '../screens/RoomsScreen';
|
||||
import RoomDetailScreen from '../screens/RoomDetailScreen';
|
||||
import DevicesScreen from '../screens/DevicesScreen';
|
||||
import DeviceControlScreen from '../screens/DeviceControlScreen';
|
||||
import AlertsScreen from '../screens/AlertsScreen';
|
||||
import ThresholdsScreen from '../screens/ThresholdsScreen';
|
||||
import VideoScreen from '../screens/VideoScreen';
|
||||
import VideoPlayerScreen from '../screens/VideoPlayerScreen';
|
||||
import SettingsScreen from '../screens/SettingsScreen';
|
||||
|
||||
const Stack = createNativeStackNavigator<RootStackParamList>();
|
||||
const Tab = createBottomTabNavigator<MainTabParamList>();
|
||||
|
||||
const TabIcon: React.FC<{ name: string; activeName: string; color: string; size: number; focused: boolean }> = ({ name, activeName, color, size, focused }) => (
|
||||
<Icon name={focused ? activeName : name} size={focused ? 26 : 22} color={color} />
|
||||
);
|
||||
|
||||
function MainTabs() {
|
||||
const navigation = useNavigation<any>();
|
||||
|
||||
return (
|
||||
<Tab.Navigator
|
||||
screenOptions={{
|
||||
headerShown: true,
|
||||
tabBarActiveTintColor: '#5C7D60',
|
||||
tabBarInactiveTintColor: '#C4BFB6',
|
||||
tabBarStyle: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderTopColor: '#F0EDE8',
|
||||
borderTopWidth: 1,
|
||||
paddingBottom: 6,
|
||||
paddingTop: 6,
|
||||
height: 60,
|
||||
},
|
||||
tabBarLabelStyle: {
|
||||
fontSize: 15,
|
||||
fontWeight: '700',
|
||||
marginTop: 2,
|
||||
},
|
||||
tabBarIconStyle: {
|
||||
marginBottom: 2,
|
||||
},
|
||||
headerStyle: {
|
||||
backgroundColor: '#FAF8F5',
|
||||
},
|
||||
headerTitleStyle: {
|
||||
color: '#2D2A26',
|
||||
fontSize: 18,
|
||||
fontWeight: '500',
|
||||
},
|
||||
headerTintColor: '#5C7D60',
|
||||
headerRight: () => (
|
||||
<Icon
|
||||
name="cog-outline"
|
||||
size={24}
|
||||
color="#8C8780"
|
||||
style={{ marginRight: 12 }}
|
||||
onPress={() => navigation.navigate('Settings')}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
>
|
||||
<Tab.Screen
|
||||
name="Dashboard"
|
||||
component={DashboardScreen}
|
||||
options={{
|
||||
title: '仪表盘',
|
||||
tabBarIcon: ({ color, size, focused }) => <TabIcon name="view-dashboard-outline" activeName="view-dashboard" color={color} size={size} focused={focused} />,
|
||||
}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="Rooms"
|
||||
component={RoomsScreen}
|
||||
options={{
|
||||
title: '蚕房',
|
||||
tabBarIcon: ({ color, size, focused }) => <TabIcon name="home-outline" activeName="home-variant" color={color} size={size} focused={focused} />,
|
||||
}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="Devices"
|
||||
component={DevicesScreen}
|
||||
options={{
|
||||
title: '设备',
|
||||
tabBarIcon: ({ color, size, focused }) => <TabIcon name="router-wireless" activeName="router-wireless" color={color} size={size} focused={focused} />,
|
||||
}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="Alerts"
|
||||
component={AlertsScreen}
|
||||
options={{
|
||||
title: '告警',
|
||||
tabBarIcon: ({ color, size, focused }) => <TabIcon name="bell-alert-outline" activeName="bell-alert" color={color} size={size} focused={focused} />,
|
||||
}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="Video"
|
||||
component={VideoScreen}
|
||||
options={{
|
||||
title: '视频',
|
||||
tabBarIcon: ({ color, size, focused }) => <TabIcon name="video-outline" activeName="video" color={color} size={size} focused={focused} />,
|
||||
}}
|
||||
/>
|
||||
</Tab.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
function AppContent() {
|
||||
const token = useAuthStore((s) => s.token);
|
||||
const restoreSession = useAuthStore((s) => s.restoreSession);
|
||||
const setRealtimeData = useAppStore((s) => s.setRealtimeData);
|
||||
const [isReady, setIsReady] = React.useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
await restoreSession();
|
||||
setIsReady(true);
|
||||
})();
|
||||
}, [restoreSession]);
|
||||
|
||||
// Subscribe to WebSocket telemetry
|
||||
useEffect(() => {
|
||||
const unsub = wsManager.subscribe((data) => {
|
||||
if (data?.type === 'telemetry' || data?.metric) {
|
||||
const telemetry = useAppStore.getState().realtimeData;
|
||||
setRealtimeData([...telemetry, data].slice(-100));
|
||||
}
|
||||
});
|
||||
return unsub;
|
||||
}, [setRealtimeData]);
|
||||
|
||||
if (!isReady) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<NavigationContainer
|
||||
ref={(ref) => {
|
||||
if (ref) {
|
||||
setNavigationRef({
|
||||
navigate: (screen: string) => {
|
||||
(ref as any).navigate(screen);
|
||||
},
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Stack.Navigator screenOptions={{ headerShown: false }} initialRouteName={token ? 'Main' : 'Login'}>
|
||||
<Stack.Screen name="Login" component={LoginScreen} />
|
||||
<Stack.Screen name="Main" component={MainTabs} />
|
||||
<Stack.Screen
|
||||
name="RoomDetail"
|
||||
component={RoomDetailScreen}
|
||||
options={{ headerShown: true, title: '蚕房详情', headerBackTitle: '返回' }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="DeviceControl"
|
||||
component={DeviceControlScreen}
|
||||
options={{ headerShown: true, title: '设备控制', headerBackTitle: '返回' }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="VideoPlayer"
|
||||
component={VideoPlayerScreen}
|
||||
options={{ headerShown: false }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="Thresholds"
|
||||
component={ThresholdsScreen}
|
||||
options={{ headerShown: true, title: '阈值管理', headerBackTitle: '返回' }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="Settings"
|
||||
component={SettingsScreen}
|
||||
options={{ headerShown: true, title: '设置', headerBackTitle: '返回' }}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
</NavigationContainer>
|
||||
);
|
||||
}
|
||||
|
||||
export default function AppNavigator() {
|
||||
const silkTheme = {
|
||||
...MD3LightTheme,
|
||||
colors: {
|
||||
...MD3LightTheme.colors,
|
||||
primary: '#7A9E7E',
|
||||
primaryContainer: '#E8F0E9',
|
||||
onPrimary: '#FFFFFF',
|
||||
onPrimaryContainer: '#5C7D60',
|
||||
secondary: '#6B8F71',
|
||||
secondaryContainer: '#F0EDE8',
|
||||
onSecondary: '#FFFFFF',
|
||||
onSecondaryContainer: '#5C7D60',
|
||||
error: '#D4847A',
|
||||
errorContainer: '#F9E8E5',
|
||||
onError: '#FFFFFF',
|
||||
background: '#FAF8F5',
|
||||
onBackground: '#2D2A26',
|
||||
surface: '#FFFFFF',
|
||||
onSurface: '#2D2A26',
|
||||
surfaceVariant: '#F5F0E8',
|
||||
onSurfaceVariant: '#8C8780',
|
||||
outline: '#E8E4DE',
|
||||
outlineVariant: '#F0EDE8',
|
||||
elevation: {
|
||||
...MD3LightTheme.colors.elevation,
|
||||
level0: 'transparent',
|
||||
level1: '#FFFFFF',
|
||||
level2: '#FFFFFF',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<PaperProvider theme={silkTheme}>
|
||||
<AppContent />
|
||||
</PaperProvider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user