2025-11-12 00:13:26 +08:00
|
|
|
|
/**
|
2025-11-13 16:47:10 +08:00
|
|
|
|
* Header 组件 - 增强版
|
|
|
|
|
|
* 基于 xinyong-web 的 header 组件重建
|
|
|
|
|
|
* 功能包括:
|
|
|
|
|
|
* - 顶部导航栏(logo、搜索、用户按钮)
|
|
|
|
|
|
* - 左侧菜单(侧边栏)
|
|
|
|
|
|
* - 登录/注册弹窗
|
|
|
|
|
|
* - 钱包信息显示
|
|
|
|
|
|
* - 主题适配
|
2025-11-12 00:13:26 +08:00
|
|
|
|
*/
|
|
|
|
|
|
|
2025-11-13 16:47:10 +08:00
|
|
|
|
import React, { useState, useCallback, useMemo } from 'react';
|
2025-11-12 00:13:26 +08:00
|
|
|
|
import {
|
|
|
|
|
|
View,
|
|
|
|
|
|
Text,
|
|
|
|
|
|
StyleSheet,
|
|
|
|
|
|
TouchableOpacity,
|
|
|
|
|
|
TextInput,
|
|
|
|
|
|
Image,
|
|
|
|
|
|
Dimensions,
|
2025-11-13 16:47:10 +08:00
|
|
|
|
Modal,
|
|
|
|
|
|
ScrollView,
|
|
|
|
|
|
SafeAreaView,
|
2025-11-12 00:13:26 +08:00
|
|
|
|
} from 'react-native';
|
2025-11-13 16:47:10 +08:00
|
|
|
|
import { useColorScheme, useThemeColors } from '@/theme';
|
|
|
|
|
|
import { useIsLoggedIn, useUser } from '@/stores/userStore';
|
|
|
|
|
|
import { useLogo } from '@/stores/tenantStore';
|
|
|
|
|
|
import { Ionicons, AntDesign } from '@expo/vector-icons';
|
|
|
|
|
|
import LeftMenu from './LeftMenu';
|
|
|
|
|
|
import LoginRegisterModal from './LoginRegisterModal';
|
|
|
|
|
|
import WalletAmount from '../WalletAmount';
|
|
|
|
|
|
import { styles } from './styles';
|
2025-11-12 00:13:26 +08:00
|
|
|
|
|
|
|
|
|
|
const { width } = Dimensions.get('window');
|
|
|
|
|
|
|
|
|
|
|
|
interface HeaderProps {
|
|
|
|
|
|
onSearch?: (keyword: string) => void;
|
|
|
|
|
|
onMessagePress?: () => void;
|
2025-11-13 16:47:10 +08:00
|
|
|
|
onMenuPress?: () => void;
|
2025-11-12 00:13:26 +08:00
|
|
|
|
unreadCount?: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2025-11-13 16:47:10 +08:00
|
|
|
|
* Header 组件 - 增强版
|
2025-11-12 00:13:26 +08:00
|
|
|
|
*/
|
|
|
|
|
|
export default function Header({
|
|
|
|
|
|
onSearch,
|
|
|
|
|
|
onMessagePress,
|
2025-11-13 16:47:10 +08:00
|
|
|
|
onMenuPress,
|
2025-11-12 00:13:26 +08:00
|
|
|
|
unreadCount = 0,
|
|
|
|
|
|
}: HeaderProps) {
|
2025-11-13 16:47:10 +08:00
|
|
|
|
const colorScheme = useColorScheme();
|
|
|
|
|
|
const s = styles[colorScheme];
|
|
|
|
|
|
const themeColors = useThemeColors();
|
|
|
|
|
|
const isLoggedIn = useIsLoggedIn();
|
|
|
|
|
|
const user = useUser();
|
|
|
|
|
|
const logoUrl = useLogo();
|
2025-11-12 00:13:26 +08:00
|
|
|
|
|
|
|
|
|
|
const [searchText, setSearchText] = useState('');
|
2025-11-13 16:47:10 +08:00
|
|
|
|
const [showLeftMenu, setShowLeftMenu] = useState(false);
|
|
|
|
|
|
const [showLoginModal, setShowLoginModal] = useState(false);
|
2025-11-12 00:13:26 +08:00
|
|
|
|
|
|
|
|
|
|
const handleSearch = useCallback(() => {
|
|
|
|
|
|
if (searchText.trim()) {
|
|
|
|
|
|
onSearch?.(searchText);
|
2025-11-13 16:47:10 +08:00
|
|
|
|
setSearchText('');
|
2025-11-12 00:13:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
}, [searchText, onSearch]);
|
|
|
|
|
|
|
2025-11-13 16:47:10 +08:00
|
|
|
|
const handleMenuPress = useCallback(() => {
|
|
|
|
|
|
setShowLeftMenu(true);
|
|
|
|
|
|
onMenuPress?.();
|
|
|
|
|
|
}, [onMenuPress]);
|
|
|
|
|
|
|
|
|
|
|
|
const handleLoginPress = useCallback(() => {
|
|
|
|
|
|
setShowLoginModal(true);
|
2025-11-12 00:13:26 +08:00
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
2025-11-13 16:47:10 +08:00
|
|
|
|
<>
|
|
|
|
|
|
<View style={s.container}>
|
|
|
|
|
|
{/* 左侧部分 */}
|
|
|
|
|
|
<View style={s.leftSection}>
|
|
|
|
|
|
{/* 菜单按钮 */}
|
|
|
|
|
|
<TouchableOpacity style={s.menuButton} onPress={handleMenuPress} activeOpacity={0.7}>
|
|
|
|
|
|
<AntDesign name="menu-unfold" size={22} color={themeColors.text} />
|
|
|
|
|
|
</TouchableOpacity>
|
2025-11-12 00:13:26 +08:00
|
|
|
|
|
2025-11-13 16:47:10 +08:00
|
|
|
|
{/* Logo */}
|
|
|
|
|
|
{logoUrl ? <Image source={{ uri: logoUrl }} style={s.logoImage} /> : null}
|
2025-11-12 00:13:26 +08:00
|
|
|
|
</View>
|
|
|
|
|
|
|
2025-11-13 16:47:10 +08:00
|
|
|
|
{/* 搜索框 */}
|
|
|
|
|
|
{/*<View style={s.searchContainer}>*/}
|
|
|
|
|
|
{/* <Ionicons name="search" size={16} color={themeColors.text + '60'} />*/}
|
|
|
|
|
|
{/* <TextInput*/}
|
|
|
|
|
|
{/* style={s.searchInput}*/}
|
|
|
|
|
|
{/* placeholder="搜索游戏..."*/}
|
|
|
|
|
|
{/* placeholderTextColor={themeColors.text + '60'}*/}
|
|
|
|
|
|
{/* value={searchText}*/}
|
|
|
|
|
|
{/* onChangeText={setSearchText}*/}
|
|
|
|
|
|
{/* onSubmitEditing={handleSearch}*/}
|
|
|
|
|
|
{/* returnKeyType="search"*/}
|
|
|
|
|
|
{/* />*/}
|
|
|
|
|
|
{/* {searchText ? (*/}
|
|
|
|
|
|
{/* <TouchableOpacity onPress={() => setSearchText('')}>*/}
|
|
|
|
|
|
{/* <Ionicons name="close" size={16} color={themeColors.text} />*/}
|
|
|
|
|
|
{/* </TouchableOpacity>*/}
|
|
|
|
|
|
{/* ) : null}*/}
|
|
|
|
|
|
{/*</View>*/}
|
|
|
|
|
|
|
|
|
|
|
|
{/* 右侧部分 */}
|
|
|
|
|
|
<View style={s.rightSection}>
|
|
|
|
|
|
{isLoggedIn && user ? (
|
|
|
|
|
|
<>
|
|
|
|
|
|
{/* 消息按钮 */}
|
|
|
|
|
|
<TouchableOpacity style={s.iconButton} onPress={onMessagePress} activeOpacity={0.7}>
|
|
|
|
|
|
<Ionicons name="chatbubble-outline" size={20} color={themeColors.text} />
|
|
|
|
|
|
{unreadCount > 0 && (
|
|
|
|
|
|
<View style={s.badge}>
|
|
|
|
|
|
<Text style={s.badgeText}>{unreadCount > 99 ? '99+' : unreadCount}</Text>
|
|
|
|
|
|
</View>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</TouchableOpacity>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 用户头像 */}
|
|
|
|
|
|
<TouchableOpacity style={s.iconButton} activeOpacity={0.7}>
|
|
|
|
|
|
{user.avatar ? (
|
|
|
|
|
|
<Image
|
|
|
|
|
|
source={{ uri: user.avatar }}
|
|
|
|
|
|
style={{ width: 32, height: 32, borderRadius: 16 }}
|
|
|
|
|
|
/>
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<Ionicons name="person-circle" size={24} color={themeColors.primary} />
|
|
|
|
|
|
)}
|
|
|
|
|
|
</TouchableOpacity>
|
|
|
|
|
|
</>
|
|
|
|
|
|
) : (
|
|
|
|
|
|
/* 登录/注册按钮 */
|
|
|
|
|
|
<View style={s.authButtons}>
|
|
|
|
|
|
<TouchableOpacity
|
|
|
|
|
|
style={[s.authButton, s.registerButton]}
|
|
|
|
|
|
onPress={() => setShowLoginModal(true)}
|
|
|
|
|
|
activeOpacity={0.7}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Text style={s.registerButtonText}>注册</Text>
|
|
|
|
|
|
</TouchableOpacity>
|
|
|
|
|
|
<TouchableOpacity
|
|
|
|
|
|
style={[s.authButton, s.loginButton]}
|
|
|
|
|
|
onPress={() => setShowLoginModal(true)}
|
|
|
|
|
|
activeOpacity={0.7}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Text style={s.loginButtonText}>登录</Text>
|
|
|
|
|
|
</TouchableOpacity>
|
2025-11-12 00:13:26 +08:00
|
|
|
|
</View>
|
|
|
|
|
|
)}
|
2025-11-13 16:47:10 +08:00
|
|
|
|
</View>
|
2025-11-12 00:13:26 +08:00
|
|
|
|
</View>
|
2025-11-13 16:47:10 +08:00
|
|
|
|
|
|
|
|
|
|
{/* 左侧菜单 */}
|
|
|
|
|
|
<LeftMenu visible={showLeftMenu} onClose={() => setShowLeftMenu(false)} />
|
|
|
|
|
|
|
|
|
|
|
|
{/* 登录/注册弹窗 */}
|
|
|
|
|
|
<LoginRegisterModal visible={showLoginModal} onClose={() => setShowLoginModal(false)} />
|
|
|
|
|
|
</>
|
2025-11-12 00:13:26 +08:00
|
|
|
|
);
|
|
|
|
|
|
}
|