import { LEVEL_MAP } from '@/constants/config'; import { Images } from '@/constants/images'; import { countRecordsAfterLastLevel, getBuyRecord } from '@/services/award'; import { Image, ImageBackground } from 'expo-image'; import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react'; import { ActivityIndicator, Dimensions, FlatList, Modal, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; const { width, height } = Dimensions.get('window'); const TABS = [ { title: '全部', value: '' }, { title: '超神款', value: 'A' }, { title: '欧皇款', value: 'B' }, { title: '隐藏款', value: 'C' }, { title: '普通款', value: 'D' } ]; interface RecordModalProps { poolId: string; } export interface RecordModalRef { show: () => void; close: () => void; } export const RecordModal = forwardRef(({ poolId }, ref) => { const [visible, setVisible] = useState(false); const [data, setData] = useState([]); const [activeTab, setActiveTab] = useState(TABS[0]); const [loading, setLoading] = useState(false); const [refreshing, setRefreshing] = useState(false); const [lastId, setLastId] = useState(undefined); const [taggingA, setTaggingA] = useState(0); const [taggingB, setTaggingB] = useState(0); const [hasMore, setHasMore] = useState(true); useImperativeHandle(ref, () => ({ show: () => { setVisible(true); refresh(); }, close: () => setVisible(false) })); const refresh = () => { setLastId(undefined); setData([]); setHasMore(true); loadData(true); loadStats(); }; const loadStats = async () => { try { const resA = await countRecordsAfterLastLevel({ levelEnumList: ['A'], poolId }); setTaggingA(resA.data || 0); // Check API structure: {data: number} const resB = await countRecordsAfterLastLevel({ levelEnumList: ['B'], poolId }); setTaggingB(resB.data || 0); } catch (e) { console.error('Failed to load stats', e); } }; const loadData = async (isRefresh = false) => { if (loading || (!isRefresh && !hasMore)) return; setLoading(true); try { const currentLastId = isRefresh ? undefined : lastId; const res = await getBuyRecord(poolId, currentLastId, activeTab.value as any); if (res && res.length > 0) { setData(prev => isRefresh ? res : [...prev, ...res]); setLastId(res[res.length - 1].id); // Assuming page size is 10 or 20. If less than that, no more data. // Let's assume default is 10. If strictly < 10, definitely no more. // If == 10, maybe more. // Safer: if 0 returned, handled by outside if. } else { setHasMore(false); } if (res && res.length < 10) { setHasMore(false); } } catch (e) { console.error('Failed to load records', e); } setLoading(false); setRefreshing(false); }; const handleTabChange = (tab: any) => { setActiveTab(tab); // Reset and reload setLastId(undefined); setData([]); setHasMore(true); // We can't immediately call loadData due to state update async nature, // but let's assume useEffect or immediate call with arg works. // Actually best to useEffect on activeTab change? // Or specific effect for tab // Let's do explicit reload in effect or here // setData is sync-ish in RN usually batching, let's use effect. }; useEffect(() => { if (visible) { setLastId(undefined); setData([]); setHasMore(true); loadData(true); } }, [activeTab]); const renderItem = ({ item }: { item: any }) => ( {item.nickname} {/* Level Icon - Assuming we have images for level text similar to legacy */} {/* Legacy: :src="LEVEL_MAP[item.level].titleText" */} {/* We don't have titleText in our config yet, need to map or use text */} {/* For now use Text with color */} {LEVEL_MAP[item.level]?.title} {item.name} ×{item.lastCount} ); return ( setVisible(false)}> setVisible(false)} /> {/* Header */} 购买记录 setVisible(false)}> {/* Close Icon or Text */} × {/* Stats Banner */} {taggingA} 发未出 超神款 {taggingB} 发未出 欧皇款 {/* Tabs */} {TABS.map(tab => ( handleTabChange(tab)} > {tab.title} ))} {/* List */} item.id || String(index)} style={styles.list} contentContainerStyle={{ paddingBottom: 20 }} onEndReached={() => loadData(false)} onEndReachedThreshold={0.5} ListEmptyComponent={ !loading ? 暂无记录 : null } ListFooterComponent={loading ? : null} /> ); }); const styles = StyleSheet.create({ overlay: { flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'flex-end', }, mask: { flex: 1, }, container: { height: height * 0.7, paddingTop: 0, backgroundColor: '#fff', borderTopLeftRadius: 15, borderTopRightRadius: 15, overflow: 'hidden', }, header: { height: 50, justifyContent: 'center', alignItems: 'center', marginTop: 10, }, title: { fontSize: 18, fontWeight: 'bold', }, closeBtn: { position: 'absolute', right: 20, top: 15, width: 30, height: 30, alignItems: 'center', justifyContent: 'center', backgroundColor: '#eee', borderRadius: 15, }, statsBanner: { width: '90%', alignSelf: 'center', height: 50, flexDirection: 'row', justifyContent: 'space-around', alignItems: 'center', marginBottom: 10, }, statItem: { flexDirection: 'row', alignItems: 'center', }, statNum: { fontSize: 16, fontWeight: 'bold', color: '#fff', textShadowColor: '#000', textShadowOffset: { width: -1, height: -1 }, textShadowRadius: 1, }, statLabel: { fontSize: 12, color: '#928D81', fontWeight: '300', marginHorizontal: 8 }, statLevel: { fontSize: 12, fontWeight: 'bold' }, tabs: { flexDirection: 'row', justifyContent: 'space-around', paddingHorizontal: 10, marginBottom: 10, backgroundColor: 'rgba(255,255,255,0.1)', paddingVertical: 5, }, tab: { paddingVertical: 5, paddingHorizontal: 10, borderRadius: 5, backgroundColor: '#eee', }, activeTab: { backgroundColor: '#FEC433', }, tabText: { fontSize: 12, color: '#666' }, activeTabText: { color: '#000', fontWeight: 'bold' }, list: { flex: 1, paddingHorizontal: 15, }, item: { flexDirection: 'row', alignItems: 'center', backgroundColor: '#FFF7E3', marginBottom: 10, padding: 5, borderRadius: 8, height: 60, }, avatar: { width: 40, height: 40, borderRadius: 20 }, nickname: { flex: 1, marginLeft: 10, fontSize: 12, color: '#333' }, levelTag: { borderWidth: 1, paddingHorizontal: 4, borderRadius: 4, marginHorizontal: 5 }, levelText: { fontSize: 10, fontWeight: 'bold' }, itemName: { width: 80, fontSize: 12, color: '#FEC433', marginHorizontal: 5 }, countText: { fontSize: 12, color: '#000', fontWeight: 'bold', marginRight: 5 }, itemImage: { width: 40, height: 40, borderRadius: 20, backgroundColor: '#fff' }, emptyText: { textAlign: 'center', marginTop: 20, color: '#999' } });