import { Images } from '@/constants/images'; import { Image } from 'expo-image'; import React, { useMemo } from 'react'; import { Dimensions, ImageBackground, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; const { width } = Dimensions.get('window'); interface ProductListYfsProps { products: any[]; poolId: string; box: any; onProductClick?: (product: any) => void; } // Level Configuration - reused from ProductList logic const LEVEL_CONFIG: Record = { A: { title: '超神款', color: '#fff', bgColor: '#FF4444', productItem: Images.box.detail.productItemA }, B: { title: '欧皇款', color: '#fff', bgColor: '#FF9900', productItem: Images.box.detail.productItemB }, C: { title: '隐藏款', color: '#fff', bgColor: '#9966FF', productItem: Images.box.detail.productItemC }, D: { title: '普通款', color: '#fff', bgColor: '#00CCFF', productItem: Images.box.detail.productItemD }, }; export default function ProductListYfs({ products = [], poolId, box, onProductClick }: ProductListYfsProps) { const levels = useMemo(() => { // Group by level const grouped: Record = { A: [], B: [], C: [], D: [] }; products.forEach(p => { const level = p.level || 'D'; if (grouped[level]) { grouped[level].push(p); } }); const result = [ { level: 'A', list: grouped.A }, { level: 'B', list: grouped.B }, { level: 'C', list: grouped.C }, { level: 'D', list: grouped.D }, ].filter(g => g.list && g.list.length > 0); return result; }, [products]); const getLeftNum = (item: any) => { // Robust check for box and usedStat (camelCase or snake_case) const usedStat = box?.usedStat || box?.used_stat; if (!box || !usedStat) { return item.quantity; } // Try multiple key variations for robustness const spuId = String(item.spu?.id || item.spu_id); const itemId = String(item.id); let used: any = null; // Check if usedStat is an Array (based on logs showing keys 0,1,2...) if (Array.isArray(usedStat)) { // Debug log to see structure of array items once if (!global.hasLoggedUsedStatStructure) { console.log('[DEBUG-ICHIBAN] usedStat is Array. First item:', usedStat[0]); global.hasLoggedUsedStatStructure = true; } // Search in array used = usedStat.find((u: any) => { const uSpuId = String(u.spuId || u.spu_id || u.id); return uSpuId === spuId || uSpuId === itemId; }); } else { // Object lookup used = usedStat[spuId] || usedStat[itemId] || (item.spu?.id && usedStat[item.spu.id]); } if (used) { return item.quantity - (used.quantity || 0); } return item.quantity; }; const getProbability = (item: any) => { if (!box || !box.leftQuantity) return '0'; const left = getLeftNum(item); const prob = (left / box.leftQuantity * 100).toFixed(4); return parseFloat(prob) === 0 ? '0' : prob; }; const getLevelProbability = (level: string) => { if (!box || !box.leftQuantity) return '0%'; let sumLeft = 0; products.filter(p => p.level === level).forEach(p => { sumLeft += getLeftNum(p); }); const prob = (sumLeft / box.leftQuantity * 100).toFixed(4); return parseFloat(prob) === 0 ? '0%' : `${prob}%`; }; if (!products || products.length === 0) return null; return ( {levels.map((levelItem) => { const config = LEVEL_CONFIG[levelItem.level] || LEVEL_CONFIG['D']; return ( {/* Level Title Row */} {config.title} 概率: {getLevelProbability(levelItem.level)} {/* Horizontal List */} {levelItem.list.map((item, index) => ( onProductClick && onProductClick(item)} activeOpacity={0.8} > {/* Cover Image */} {/* Bottom Banner (Probability + Quantity Badge) */} {/* Probability centered */} 概率: {getProbability(item)}% {/* Quantity Tag (positioned top right of the banner, overlapping image) */} {getLeftNum(item)}/{item.quantity} ))} ); })} ); } const styles = StyleSheet.create({ // ... (previous styles) // Only changing countTag and related if needed container: { paddingHorizontal: 10, marginTop: 0, }, levelGroup: { marginBottom: 20, }, levelHeader: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', marginBottom: 10, position: 'relative', height: 30, }, levelTitle: { fontSize: 18, fontWeight: 'bold', textShadowColor: '#000', textShadowOffset: { width: 1, height: 1 }, textShadowRadius: 1, }, levelProportion: { position: 'absolute', right: 0, bottom: 5, flexDirection: 'row', alignItems: 'center', }, probabilityLabel: { fontSize: 12, color: '#ffc901', }, probabilityValue: { fontSize: 12, color: '#fff', }, scrollContent: { paddingRight: 10, }, itemContainer: { width: 88, height: 110, marginRight: 10, }, itemBg: { width: '100%', height: '100%', alignItems: 'center', }, itemImage: { width: 88, height: 90, }, textBox: { width: 88, height: 53, marginTop: -18, justifyContent: 'center', paddingTop: 12, alignItems: 'center', position: 'relative', // Ensure absolute children position relative to this }, probTag: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', }, probLabel: { fontSize: 8, color: '#fff', marginRight: 2, }, probValue: { fontSize: 9, fontWeight: 'bold', color: '#fff', }, countTag: { position: 'absolute', top: -6, // Shift up to overlap image (~ -15rpx) right: 0, paddingHorizontal: 4, borderTopLeftRadius: 4, borderBottomRightRadius: 4, // Maybe just border radius? Original had border-radius: 5rpx (2.5px) borderRadius: 2, zIndex: 10, minWidth: 30, alignItems: 'center', }, countText: { color: '#fff', fontSize: 8, fontWeight: 'bold', } });