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,
},
});