import { Ionicons } from '@expo/vector-icons'; import { Tabs } from 'expo-router/js-tabs'; import type { BottomTabBarProps } from 'expo-router/js-tabs'; import { useFocusEffect } from 'expo-router'; import { useCallback, useEffect, useRef } from 'react'; import { Animated, Easing, Pressable, StyleSheet, View } from 'react-native'; import { colors } from '../../src/theme'; import { useRole } from '../../src/context/RoleContext'; /** 企业端默认落地「岗位」Tab(与求职端首屏一致) */ export const unstable_settings = { initialRouteName: 'job-management', }; /** 企业端底部 Tab 与求职端共用品牌主色 primary;未选中 -outline,选中填充实心 */ const ICON_MAP = { 'enterprise-overview': { outline: 'person-outline', filled: 'person' }, 'job-management': { outline: 'folder-outline', filled: 'folder' }, 'talent-recommendation': { outline: 'people-outline', filled: 'people' }, 'enterprise-chat': { outline: 'chatbubble-outline', filled: 'chatbubble' }, } as const; type TabRoute = keyof typeof ICON_MAP; function TabItem({ focused, route, label, onPress, onLongPress, }: { focused: boolean; route: TabRoute; label: string; onPress: () => void; onLongPress: () => void; }) { const { outline, filled } = ICON_MAP[route]; const translateY = useRef(new Animated.Value(focused ? -2 : 0)).current; const progress = useRef(new Animated.Value(focused ? 1 : 0)).current; useEffect(() => { const translateAnim = Animated.timing(translateY, { toValue: focused ? -2 : 0, duration: 150, easing: Easing.out(Easing.ease), useNativeDriver: true, }); const progressAnim = Animated.timing(progress, { toValue: focused ? 1 : 0, duration: 200, easing: Easing.inOut(Easing.ease), useNativeDriver: true, }); translateAnim.start(); progressAnim.start(); return () => { translateAnim.stop(); progressAnim.stop(); }; }, [focused, translateY, progress]); const inactiveOpacity = progress.interpolate({ inputRange: [0, 1], outputRange: [1, 0], }); return ( [styles.tabItem, pressed && styles.tabItemPressed]} onPress={onPress} onLongPress={onLongPress} accessibilityRole="button" accessibilityState={{ selected: focused }} > {label} {label} ); } function TabBar({ state, descriptors, navigation, insets }: BottomTabBarProps) { return ( {state.routes.map((route, index) => { const { options } = descriptors[route.key]; const focused = state.index === index; const label = typeof options.tabBarLabel === 'string' ? options.tabBarLabel : options.title ?? ''; const onPress = () => { const event = navigation.emit({ type: 'tabPress', target: route.key, canPreventDefault: true, }); if (!focused && !event.defaultPrevented) { navigation.navigate(route.name); } }; const onLongPress = () => navigation.emit({ type: 'tabLongPress', target: route.key }); return ( ); })} ); } /** * 企业端底部 Tab 导航:岗位 / 人才 / 沟通 / 我的 * 绿色 success 强调,与求职端蓝色 primary 形成视觉区分。 */ export default function EnterpriseTabLayout() { const { setRole } = useRole(); // 用 useFocusEffect:进入/返回该端时随焦点写入角色, // 避免「切换到企业端」后返回时 layout 未重新挂载导致 role 残留 candidate。 useFocusEffect( useCallback(() => { setRole('enterprise'); }, [setRole]), ); return ( } > ); } const styles = StyleSheet.create({ tabBar: { flexDirection: 'row', alignItems: 'center', backgroundColor: colors.white, paddingTop: 4, }, tabItem: { flex: 1, alignItems: 'center', justifyContent: 'center', paddingVertical: 2, }, tabItemPressed: { transform: [{ scale: 0.92 }], }, iconBox: { width: 22, height: 22, }, center: { alignItems: 'center', justifyContent: 'center', }, labelBox: { height: 14, marginTop: 1, alignSelf: 'stretch', }, labelLayer: { position: 'absolute', top: 0, left: 0, right: 0, }, tabLabel: { fontSize: 11, lineHeight: 14, fontWeight: '400', textAlign: 'center', color: colors.textHint, }, tabLabelActive: { fontWeight: '600', color: colors.primary, }, });