import { Image } from 'expo-image'; import React, { forwardRef, useCallback, useImperativeHandle, useState } from 'react'; import { ActivityIndicator, ImageBackground, Modal, ScrollView, StyleSheet, Text, TouchableOpacity, View, } from 'react-native'; import { Images } from '@/constants/images'; import { getBoxList } from '@/services/award'; // 等级筛选标签 const TABS = [ { title: '全部', value: '' }, { title: '超神款', value: 'A' }, { title: '欧皇款', value: 'B' }, { title: '隐藏款', value: 'C' }, { title: '普通款', value: 'D' }, ]; interface BoxItem { number: string; quantity: number; leftQuantity: number; quantityA: number; quantityB: number; quantityC: number; quantityD: number; leftQuantityA: number; leftQuantityB: number; leftQuantityC: number; leftQuantityD: number; } interface BoxChooseModalProps { poolId: string; onChoose: (boxNumber: string) => void; } export interface BoxChooseModalRef { show: () => void; close: () => void; } export const BoxChooseModal = forwardRef( ({ poolId, onChoose }, ref) => { const [visible, setVisible] = useState(false); const [loading, setLoading] = useState(false); const [currentTab, setCurrentTab] = useState(TABS[0]); const [boxList, setBoxList] = useState([]); const [pageNum, setPageNum] = useState(1); const [hasMore, setHasMore] = useState(true); const loadData = useCallback(async (page: number, level?: string) => { if (page === 1) setLoading(true); try { const levelValue = level === '' ? undefined : level === 'A' ? 1 : level === 'B' ? 2 : level === 'C' ? 3 : level === 'D' ? 4 : undefined; const res = await getBoxList(poolId, levelValue, page, 20); if (res && res.records) { const newList = res.records.filter((item: BoxItem) => item.leftQuantity > 0); if (page === 1) { setBoxList(newList); } else { setBoxList(prev => [...prev, ...newList]); } setHasMore(res.records.length >= 20); setPageNum(page); } } catch (error) { console.error('加载盒子列表失败:', error); } finally { setLoading(false); } }, [poolId]); useImperativeHandle(ref, () => ({ show: () => { setVisible(true); setCurrentTab(TABS[0]); setPageNum(1); loadData(1, ''); }, close: () => { setVisible(false); setBoxList([]); }, })); const close = () => { setVisible(false); }; const clickTab = (tab: typeof TABS[0]) => { setCurrentTab(tab); setPageNum(1); loadData(1, tab.value); }; const loadMore = () => { if (!loading && hasMore) { loadData(pageNum + 1, currentTab.value); } }; const choose = (item: BoxItem) => { if (item.leftQuantity <= 0) return; onChoose(item.number); close(); }; const handleScroll = (event: any) => { const { layoutMeasurement, contentOffset, contentSize } = event.nativeEvent; const isCloseToBottom = layoutMeasurement.height + contentOffset.y >= contentSize.height - 50; if (isCloseToBottom) { loadMore(); } }; return ( {/* 标题 */} 换盒 × {/* 标签页 */} {TABS.map((tab) => ( clickTab(tab)} > {tab.title} ))} {/* 盒子列表 */} {loading && pageNum === 1 ? ( ) : boxList.length === 0 ? ( 暂无可用盒子 ) : ( boxList.map((item, index) => ( choose(item)} activeOpacity={0.8} > {index + 1} 剩{item.leftQuantity}发 {item.leftQuantityA} /{item.quantityA} {item.leftQuantityB} /{item.quantityB} {item.leftQuantityC} /{item.quantityC} {item.leftQuantityD} /{item.quantityD} )) )} {loading && pageNum > 1 && ( )} ); } ); const styles = StyleSheet.create({ overlay: { flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'flex-end', }, mask: { flex: 1 }, container: { borderTopLeftRadius: 15, borderTopRightRadius: 15, paddingTop: 15, paddingBottom: 34, maxHeight: '80%', }, titleSection: { alignItems: 'center', paddingVertical: 15, position: 'relative', }, title: { fontSize: 16, fontWeight: 'bold', color: '#fff', textShadowColor: '#000', textShadowOffset: { width: 1, height: 1 }, textShadowRadius: 2, }, closeBtn: { position: 'absolute', right: 15, top: 10, width: 24, height: 24, backgroundColor: '#ebebeb', borderRadius: 12, justifyContent: 'center', alignItems: 'center', }, closeText: { fontSize: 18, color: '#a2a2a2', marginTop: -2 }, tabsScroll: { maxHeight: 40, marginHorizontal: 10, marginBottom: 10, }, tabs: { flexDirection: 'row', }, tabItem: { paddingHorizontal: 12, paddingVertical: 6, backgroundColor: 'rgba(255,255,255,0.2)', borderRadius: 15, marginRight: 8, }, tabItemActive: { backgroundColor: '#FFC900', }, tabText: { fontSize: 12, color: '#fff', }, tabTextActive: { color: '#000', fontWeight: 'bold', }, listScroll: { height: 400, marginHorizontal: 10, }, listContainer: { backgroundColor: '#f3f3f3', borderWidth: 2, borderColor: '#000', padding: 15, borderRadius: 4, }, loadingBox: { height: 200, justifyContent: 'center', alignItems: 'center', }, emptyBox: { height: 200, justifyContent: 'center', alignItems: 'center', }, emptyText: { fontSize: 14, color: '#999', }, boxItem: { backgroundColor: '#fff', borderWidth: 3, borderColor: '#000', borderRadius: 4, marginBottom: 10, position: 'relative', shadowColor: '#FFC900', shadowOffset: { width: 0, height: 3 }, shadowOpacity: 1, shadowRadius: 0, elevation: 3, }, itemIndex: { position: 'absolute', left: 0, top: 0, width: 22, height: 22, borderWidth: 1.5, borderColor: '#000', backgroundColor: '#fff', justifyContent: 'center', alignItems: 'center', zIndex: 1, }, itemIndexText: { fontSize: 14, fontWeight: 'bold', color: '#000', }, itemContent: { flexDirection: 'row', alignItems: 'center', padding: 12, }, leftSection: { width: 74, alignItems: 'center', }, boxIcon: { width: 24, height: 24, }, leftText: { fontSize: 12, color: '#000', marginTop: 4, }, divider: { width: 1, height: 40, backgroundColor: '#dcdad3', opacity: 0.5, marginRight: 10, }, levelList: { flex: 1, flexDirection: 'row', flexWrap: 'wrap', }, levelBox: { width: '50%', flexDirection: 'row', alignItems: 'center', marginBottom: 4, }, levelIcon: { width: 45, height: 16, marginRight: 4, }, numBox: { flexDirection: 'row', alignItems: 'center', }, currentNum: { fontSize: 13, fontWeight: '500', color: '#000', }, totalNum: { fontSize: 11, color: '#666', }, loadMoreBox: { paddingVertical: 15, alignItems: 'center', }, });