import { Barrage } from '@/components/Barrage'; import { Image } from 'expo-image'; import { useRouter } from 'expo-router'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { ActivityIndicator, FlatList, ImageBackground, RefreshControl, ScrollView, StatusBar, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { Images } from '@/constants/images'; import { getFeedbackList, getPoolList, PoolItem } from '@/services/award'; const typeList = [ { label: '全部', value: '', type: 0, img: Images.box.type1, imgOn: Images.box.type1On }, { label: '高保赏', value: 'UNLIMITED', type: 2, img: Images.box.type3, imgOn: Images.box.type3On }, { label: '高爆赏', value: 'UNLIMITED', type: 1, img: Images.box.type2, imgOn: Images.box.type2On }, { label: '擂台赏', value: 'YFS_PRO', type: 7, img: Images.box.type5, imgOn: Images.box.type5On }, { label: '一番赏', value: 'YFS_PRO', type: 0, img: Images.box.type4, imgOn: Images.box.type4On }, ]; interface BarrageItem { id: string; content: string; nickname?: string; avatar: string; poolName?: string; type?: string; text?: string; poolId?: string; } // Static Header Component - Memoized to prevent re-renders const StaticHeader = React.memo(({ barrageList }: { barrageList: BarrageItem[] }) => ( {/* 占位空间 - 给顶部搜索栏留出空间 */} {/* 顶部主图 - 绝对定位,叠在背景上 */} {/* 占位空间 - 主图高度 */} {/* 弹幕区域 */} {barrageList && barrageList.length > 0 && ( )} )); // Type Selector Component const TypeSelector = React.memo(({ typeIndex, priceSort, onTypeChange, onSortChange }: { typeIndex: number; priceSort: number; onTypeChange: (index: number) => void; onSortChange: () => void; }) => ( {typeList.map((item, index) => ( onTypeChange(index)} activeOpacity={0.7} > ))} )); export default function BoxScreen() { const router = useRouter(); const insets = useSafeAreaInsets(); const [keyword, setKeyword] = useState(''); const [typeIndex, setTypeIndex] = useState(0); const [priceSort, setPriceSort] = useState(0); const [list, setList] = useState([]); const [loading, setLoading] = useState(false); const [refreshing, setRefreshing] = useState(false); const [current, setCurrent] = useState(1); const [total, setTotal] = useState(0); const [hasMore, setHasMore] = useState(true); const [barrageList, setBarrageList] = useState([]); // 加载弹幕 const loadBarrage = useCallback(async () => { try { const res = await getFeedbackList(); if (res.data) { setBarrageList(res.data); } } catch (error) { console.error('加载弹幕失败:', error); } }, []); const loadData = useCallback(async (isRefresh = false) => { if (loading) return; const page = isRefresh ? 1 : current; if (!isRefresh && !hasMore) return; setLoading(true); try { const selectedType = typeList[typeIndex]; const res = await getPoolList({ current: page, size: 10, mode: selectedType.value || undefined, type: selectedType.type, keyword: keyword || undefined, priceSort: priceSort || undefined, }); if (res.success && res.data) { const newList = isRefresh ? res.data : [...list, ...res.data]; setList(newList); setTotal(res.count || 0); setCurrent(page + 1); setHasMore(newList.length < (res.count || 0)); } } catch (error) { console.error('加载奖池列表失败:', error); } setLoading(false); setRefreshing(false); }, [current, hasMore, loading, typeIndex, list, keyword, priceSort]); useEffect(() => { loadData(true); loadBarrage(); }, [typeIndex, priceSort]); // 执行搜索 const handleSearch = () => { setList([]); setCurrent(1); setHasMore(true); // 需要延迟一下让状态更新 setTimeout(() => { loadData(true); }, 100); }; const handleRefresh = () => { setRefreshing(true); loadData(true); }; const handleLoadMore = () => { if (!loading && hasMore) { loadData(false); } }; const handleTypeChange = useCallback((index: number) => { setTypeIndex(index); setList([]); setCurrent(1); setHasMore(true); }, []); const handlePriceSort = useCallback(() => { setPriceSort((prev) => (prev + 1) % 3); }, []); const handleItemPress = useCallback((item: PoolItem) => { // 检查商品状态 if (item.status !== undefined && item.status !== 1) return; console.log('点击商品:', item.id, 'mode:', item.mode, 'type:', item.type); // 根据类型跳转到不同页面 - 按照小程序逻辑 if (item.type === 7) { // 擂台赏跳转到 boxInBox 页面 router.push({ pathname: '/boxInBox', params: { poolId: item.id } } as any); } else if (item.mode === 'UNLIMITED') { // 高爆赏/高保赏 router.push({ pathname: '/award-detail', params: { poolId: item.id } } as any); } else if (item.mode === 'YFS_PRO') { // 一番赏 router.push({ pathname: '/award-detail-yfs', params: { poolId: item.id } } as any); } else { // 其他商品 router.push(`/product/${item.id}` as any); } }, [router]); const renderItem = useCallback(({ item }: { item: PoolItem }) => ( handleItemPress(item)} activeOpacity={0.8} > {item.name} ¥ {item.price}起 ), [handleItemPress]); const ListHeader = useMemo(() => ( ), [barrageList, typeIndex, priceSort, handleTypeChange, handlePriceSort]); const renderFooter = useCallback(() => { if (!loading) return null; return ( 加载中... ); }, [loading]); const renderEmpty = useCallback(() => { if (loading) return null; return ( 暂无数据 ); }, [loading]); return ( {/* 顶部搜索栏 */} {keyword.length > 0 && ( 搜索 )} {/* 列表 */} item.id} ListHeaderComponent={ListHeader} ListFooterComponent={renderFooter} ListEmptyComponent={renderEmpty} contentContainerStyle={styles.listContent} showsVerticalScrollIndicator={false} refreshControl={ } onEndReached={handleLoadMore} onEndReachedThreshold={0.3} /> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#1a1a2e', }, background: { flex: 1, }, header: { position: 'relative', zIndex: 11, flexDirection: 'row', alignItems: 'center', paddingHorizontal: 15, paddingBottom: 10, }, logo: { width: 67, height: 25, marginRight: 20, }, searchBar: { flex: 1, flexDirection: 'row', alignItems: 'center', backgroundColor: 'rgba(255,255,255,0.38)', borderRadius: 180, paddingHorizontal: 15, height: 28, }, searchIcon: { width: 15, height: 15, marginRight: 5, }, searchInput: { flex: 1, color: '#fff', fontSize: 12, padding: 0, }, searchBtn: { paddingHorizontal: 8, paddingVertical: 2, }, searchBtnText: { color: '#fff', fontSize: 12, }, mainImageContainer: { position: 'absolute', left: 0, top: 0, zIndex: 2, width: '100%', height: 395, }, mainImage: { width: '100%', height: '100%', }, typeSection: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 10, paddingVertical: 10, position: 'relative', zIndex: 10, backgroundColor: 'transparent', }, typeListContainer: { flex: 1, marginRight: 10, }, typeListContent: { paddingRight: 10, }, typeItem: { width: 73, height: 34, marginRight: 4, }, typeImage: { width: '100%', height: '100%', }, sortBtn: { width: 38, height: 38, alignItems: 'center', justifyContent: 'center', }, sortIcon: { width: 38, height: 38, }, listContent: { paddingHorizontal: 10, paddingBottom: 100, }, itemContainer: { marginBottom: 8, }, itemBg: { width: '100%', height: 230, // Increased total height slightly for safety // Remove padding to control children individually }, itemImage: { width: '95%', // Very tight fit (leaving ~2.5% gap on sides = small gap) height: 142, // restore height borderRadius: 6, alignSelf: 'center', marginTop: 13, // Tighter top fit (approx 1px-2px visual gap) }, itemInfo: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: 20, // Visual padding for text paddingTop: 12, // Space between image and text }, itemName: { flex: 1, color: '#fff', fontSize: 14, }, itemPrice: { color: '#ff0000', fontSize: 12, fontWeight: 'bold', marginLeft: 10, }, priceUnit: { fontSize: 12, marginRight: 2, }, footer: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', paddingVertical: 15, }, footerText: { color: 'rgba(255,255,255,0.6)', fontSize: 12, marginLeft: 8, }, empty: { alignItems: 'center', paddingVertical: 50, }, emptyText: { color: 'rgba(255,255,255,0.6)', fontSize: 14, }, barrageSection: { marginVertical: 10, paddingHorizontal: 10, }, barrageRow: { flexDirection: 'row', marginBottom: 5, }, barrageItem: { backgroundColor: 'rgba(0,0,0,0.5)', borderRadius: 15, paddingHorizontal: 12, paddingVertical: 6, marginRight: 8, maxWidth: 150, }, barrageText: { color: '#fff', fontSize: 12, }, });