|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
@ -0,0 +1,165 @@
|
||||
/** |
||||
* 首页 Header 组件 |
||||
* 包含搜索、用户信息、消息等功能 |
||||
*/ |
||||
|
||||
import React, { useState, useCallback } from 'react'; |
||||
import { |
||||
View, |
||||
Text, |
||||
StyleSheet, |
||||
TouchableOpacity, |
||||
TextInput, |
||||
Image, |
||||
Dimensions, |
||||
} from 'react-native'; |
||||
import { createThemeStyles, useColorScheme, useThemeInfo } from '@/theme'; |
||||
|
||||
|
||||
const { width } = Dimensions.get('window'); |
||||
|
||||
/** |
||||
* 创建主题样式 |
||||
*/ |
||||
const styles = createThemeStyles((colors) => ({ |
||||
container: { |
||||
backgroundColor: colors.background, |
||||
paddingHorizontal: 12, |
||||
paddingVertical: 8, |
||||
borderBottomWidth: 1, |
||||
borderBottomColor: colors.border, |
||||
}, |
||||
header: { |
||||
flexDirection: 'row', |
||||
alignItems: 'center', |
||||
justifyContent: 'space-between', |
||||
paddingVertical: 8, |
||||
}, |
||||
logo: { |
||||
fontSize: 18, |
||||
fontWeight: '600', |
||||
color: colors.primary, |
||||
}, |
||||
searchContainer: { |
||||
flex: 1, |
||||
marginHorizontal: 12, |
||||
flexDirection: 'row', |
||||
alignItems: 'center', |
||||
backgroundColor: colors.card, |
||||
borderRadius: 20, |
||||
paddingHorizontal: 12, |
||||
height: 36, |
||||
}, |
||||
searchInput: { |
||||
flex: 1, |
||||
marginLeft: 8, |
||||
fontSize: 14, |
||||
color: colors.text, |
||||
}, |
||||
searchPlaceholder: { |
||||
color: colors.text + '80', |
||||
}, |
||||
iconButton: { |
||||
width: 36, |
||||
height: 36, |
||||
borderRadius: 18, |
||||
justifyContent: 'center', |
||||
alignItems: 'center', |
||||
marginLeft: 8, |
||||
}, |
||||
badge: { |
||||
position: 'absolute', |
||||
top: -4, |
||||
right: -4, |
||||
backgroundColor: colors.primary, |
||||
borderRadius: 8, |
||||
minWidth: 16, |
||||
height: 16, |
||||
justifyContent: 'center', |
||||
alignItems: 'center', |
||||
}, |
||||
badgeText: { |
||||
color: '#fff', |
||||
fontSize: 10, |
||||
fontWeight: '600', |
||||
textAlign: 'center', |
||||
}, |
||||
})); |
||||
|
||||
interface HeaderProps { |
||||
onSearch?: (keyword: string) => void; |
||||
onMessagePress?: () => void; |
||||
onUserPress?: () => void; |
||||
unreadCount?: number; |
||||
} |
||||
|
||||
/** |
||||
* Header 组件 |
||||
*/ |
||||
export default function Header({ |
||||
onSearch, |
||||
onMessagePress, |
||||
onUserPress, |
||||
unreadCount = 0, |
||||
}: HeaderProps) { |
||||
const theme = useColorScheme(); |
||||
const s = styles[theme]; |
||||
const { colors } = useThemeInfo(); |
||||
|
||||
const [searchText, setSearchText] = useState(''); |
||||
const [isSearching, setIsSearching] = useState(false); |
||||
|
||||
const handleSearch = useCallback(() => { |
||||
if (searchText.trim()) { |
||||
onSearch?.(searchText); |
||||
} |
||||
}, [searchText, onSearch]); |
||||
|
||||
const handleClearSearch = useCallback(() => { |
||||
setSearchText(''); |
||||
}, []); |
||||
|
||||
return ( |
||||
<View style={s.container}> |
||||
{/* 顶部栏 */} |
||||
<View style={s.header}> |
||||
{/* Logo */} |
||||
<Text style={s.logo}>🎮 游戏大厅</Text> |
||||
|
||||
{/* 搜索框 */} |
||||
<View style={s.searchContainer}> |
||||
<Text style={{ color: colors.text + '60', fontSize: 16 }}>🔍</Text> |
||||
<TextInput |
||||
style={[s.searchInput, s.searchPlaceholder]} |
||||
placeholder="搜索游戏..." |
||||
placeholderTextColor={colors.text + '60'} |
||||
value={searchText} |
||||
onChangeText={setSearchText} |
||||
onSubmitEditing={handleSearch} |
||||
returnKeyType="search" |
||||
/> |
||||
{searchText ? ( |
||||
<TouchableOpacity onPress={handleClearSearch}> |
||||
<Text style={{ fontSize: 16 }}>✕</Text> |
||||
</TouchableOpacity> |
||||
) : null} |
||||
</View> |
||||
|
||||
{/* 消息按钮 */} |
||||
<TouchableOpacity style={s.iconButton} onPress={onMessagePress} activeOpacity={0.7}> |
||||
<Text style={{ fontSize: 18 }}>💬</Text> |
||||
{unreadCount > 0 && ( |
||||
<View style={s.badge}> |
||||
<Text style={s.badgeText}>{unreadCount > 99 ? '99+' : unreadCount}</Text> |
||||
</View> |
||||
)} |
||||
</TouchableOpacity> |
||||
|
||||
{/* 用户按钮 */} |
||||
<TouchableOpacity style={s.iconButton} onPress={onUserPress} activeOpacity={0.7}> |
||||
<Text style={{ fontSize: 18 }}>👤</Text> |
||||
</TouchableOpacity> |
||||
</View> |
||||
</View> |
||||
); |
||||
} |
||||
@ -1,180 +0,0 @@
|
||||
/** |
||||
* 完整首页容器 |
||||
* 包含 Header、内容区域、BottomTabs |
||||
* 支持主题切换和真实数据 |
||||
*/ |
||||
|
||||
import React, { useState, useEffect, useCallback } from 'react'; |
||||
import { View, ScrollView, RefreshControl, StyleSheet, SafeAreaView, Alert } from 'react-native'; |
||||
import { useColorScheme } from '@/hooks'; |
||||
import { createThemeStyles } from '@/theme'; |
||||
import Colors from '@/constants/Colors'; |
||||
import Header from './components/Header'; |
||||
import BannerSwiper from './components/BannerSwiper'; |
||||
import NoticeBar from './components/NoticeBar'; |
||||
import GameMainMenus from './components/GameMainMenus'; |
||||
import Lobby from './components/Lobby'; |
||||
import HighPrizeGame from './components/HighPrizeGame'; |
||||
import FastFootNav from './components/FastFootNav'; |
||||
import { requestHomePageData } from '@/stores/gameStore'; |
||||
import { useTenantLoad } from '@/stores/tenantStore'; |
||||
import type { |
||||
Banner, |
||||
Notice, |
||||
GameCategory, |
||||
Game, |
||||
HighPrizeGame as HighPrizeGameType, |
||||
} from '@/types/home'; |
||||
|
||||
/** |
||||
* 创建主题样式 |
||||
*/ |
||||
const styles = createThemeStyles((colors) => ({ |
||||
container: { |
||||
flex: 1, |
||||
backgroundColor: colors.background, |
||||
}, |
||||
contentContainer: { |
||||
flex: 1, |
||||
}, |
||||
scrollContent: { |
||||
paddingBottom: 20, |
||||
}, |
||||
})); |
||||
|
||||
interface HomeScreenCompleteProps { |
||||
theme?: 'light' | 'dark'; |
||||
isDarkTheme?: boolean; |
||||
} |
||||
|
||||
/** |
||||
* 完整首页容器 |
||||
*/ |
||||
export default function HomeScreenComplete({ |
||||
theme = 'light', |
||||
isDarkTheme = false, |
||||
}: HomeScreenCompleteProps) { |
||||
const colorScheme = useColorScheme(); |
||||
const actualTheme = theme === 'light' || theme === 'dark' ? theme : colorScheme; |
||||
const s = styles[actualTheme]; |
||||
|
||||
const [refreshing, setRefreshing] = useState(false); |
||||
const [selectedCategory, setSelectedCategory] = useState<number>(0); |
||||
const tenantLoad = useTenantLoad(); |
||||
|
||||
// 加载首页数据
|
||||
const loadHomePageData = useCallback(async () => { |
||||
try { |
||||
await requestHomePageData(); |
||||
} catch (error) { |
||||
console.error('加载首页数据失败:', error); |
||||
} |
||||
}, []); |
||||
|
||||
// 初始化加载
|
||||
useEffect(() => { |
||||
console.log('租户数据加载完成:', tenantLoad); |
||||
if (tenantLoad) { |
||||
loadHomePageData(); |
||||
} |
||||
}, [loadHomePageData, tenantLoad]); |
||||
|
||||
// 下拉刷新
|
||||
const handleRefresh = useCallback(async () => { |
||||
setRefreshing(true); |
||||
try { |
||||
await loadHomePageData(); |
||||
} finally { |
||||
setRefreshing(false); |
||||
} |
||||
}, [loadHomePageData]); |
||||
|
||||
// 处理分类选择
|
||||
const handleCategorySelect = useCallback((categoryId: number) => { |
||||
setSelectedCategory(categoryId); |
||||
// 这里可以根据分类过滤游戏
|
||||
}, []); |
||||
|
||||
// 处理游戏点击
|
||||
const handleGamePress = useCallback((game: Game) => { |
||||
Alert.alert('游戏', `点击了: ${game.play_up_name}`); |
||||
// 这里可以添加打开游戏的逻辑
|
||||
}, []); |
||||
|
||||
// 处理底部 Tab 点击
|
||||
const handleTabPress = useCallback((tabId: string, action: string) => { |
||||
Alert.alert('导航', `点击了: ${tabId}`); |
||||
// 这里可以添加导航逻辑
|
||||
}, []); |
||||
|
||||
// 处理搜索
|
||||
const handleSearch = useCallback((keyword: string) => { |
||||
Alert.alert('搜索', `搜索关键词: ${keyword}`); |
||||
// 这里可以添加搜索逻辑
|
||||
}, []); |
||||
|
||||
// 根据主题选择要显示的组件
|
||||
const renderContent = () => { |
||||
if (isDarkTheme || actualTheme === 'dark') { |
||||
// 深色主题布局
|
||||
return ( |
||||
<> |
||||
<GameMainMenus |
||||
theme={actualTheme} |
||||
selectedCategory={selectedCategory} |
||||
onCategorySelect={handleCategorySelect} |
||||
/> |
||||
<BannerSwiper theme={actualTheme} /> |
||||
<NoticeBar theme={actualTheme} /> |
||||
<HighPrizeGame theme={actualTheme} onGamePress={handleGamePress} /> |
||||
<Lobby theme={actualTheme} onGamePress={handleGamePress} /> |
||||
<FastFootNav theme={actualTheme} onTabPress={handleTabPress} /> |
||||
</> |
||||
); |
||||
} else { |
||||
// 浅色主题布局
|
||||
return ( |
||||
<> |
||||
<BannerSwiper theme={actualTheme} /> |
||||
<NoticeBar theme={actualTheme} /> |
||||
<GameMainMenus |
||||
theme={actualTheme} |
||||
selectedCategory={selectedCategory} |
||||
onCategorySelect={handleCategorySelect} |
||||
/> |
||||
<Lobby theme={actualTheme} onGamePress={handleGamePress} /> |
||||
</> |
||||
); |
||||
} |
||||
}; |
||||
|
||||
return ( |
||||
<SafeAreaView style={s.container}> |
||||
{/* Header */} |
||||
<Header |
||||
theme={actualTheme} |
||||
onSearch={handleSearch} |
||||
onMessagePress={() => Alert.alert('消息', '消息功能')} |
||||
onUserPress={() => Alert.alert('用户', '用户中心')} |
||||
unreadCount={3} |
||||
/> |
||||
|
||||
{/* 内容区域 */} |
||||
<View style={s.contentContainer}> |
||||
<ScrollView |
||||
style={s.contentContainer} |
||||
refreshControl={ |
||||
<RefreshControl |
||||
refreshing={refreshing} |
||||
onRefresh={handleRefresh} |
||||
tintColor={Colors[actualTheme].primary} |
||||
/> |
||||
} |
||||
showsVerticalScrollIndicator={false} |
||||
> |
||||
<View style={s.scrollContent}>{renderContent()}</View> |
||||
</ScrollView> |
||||
</View> |
||||
</SafeAreaView> |
||||
); |
||||
} |
||||
@ -80,6 +80,9 @@ importers:
|
||||
react-native: |
||||
specifier: 0.81.5 |
||||
version: 0.81.5(@babel/[email protected])(@types/[email protected])([email protected]) |
||||
react-native-linear-gradient: |
||||
specifier: ^2.8.3 |
||||
version: 2.8.3([email protected](@babel/[email protected])(@types/[email protected])([email protected]))([email protected]) |
||||
react-native-paper: |
||||
specifier: ^5.14.5 |
||||
version: 5.14.5([email protected]([email protected](@babel/[email protected])(@types/[email protected])([email protected]))([email protected]))([email protected](@babel/[email protected])(@types/[email protected])([email protected]))([email protected]) |
||||
@ -2985,6 +2988,12 @@ packages:
|
||||
react: '*' |
||||
react-native: '*' |
||||
|
||||
[email protected]: |
||||
resolution: {integrity: sha512-KflAXZcEg54PXkLyflaSZQ3PJp4uC4whM7nT/Uot9m0e/qxFV3p6uor1983D1YOBJbJN7rrWdqIjq0T42jOJyA==} |
||||
peerDependencies: |
||||
react: '*' |
||||
react-native: '*' |
||||
|
||||
[email protected]: |
||||
resolution: {integrity: sha512-eaIH5bUQjJ/mYm4AkI6caaiyc7BcHDwX6CqNDi6RIxfxfWxROsHpll1oBuwn/cFvknvA8uEAkqLk/vzVihI3AQ==} |
||||
peerDependencies: |
||||
@ -7208,6 +7217,11 @@ snapshots:
|
||||
react: 19.1.0 |
||||
react-native: 0.81.5(@babel/[email protected])(@types/[email protected])([email protected]) |
||||
|
||||
[email protected]([email protected](@babel/[email protected])(@types/[email protected])([email protected]))([email protected]): |
||||
dependencies: |
||||
react: 19.1.0 |
||||
react-native: 0.81.5(@babel/[email protected])(@types/[email protected])([email protected]) |
||||
|
||||
[email protected]([email protected]([email protected](@babel/[email protected])(@types/[email protected])([email protected]))([email protected]))([email protected](@babel/[email protected])(@types/[email protected])([email protected]))([email protected]): |
||||
dependencies: |
||||
'@callstack/react-theme-provider': 3.0.9([email protected]) |
||||
|
||||