import { Image } from "expo-image"; import { useRouter } from "expo-router"; import React from "react"; import { ImageBackground, ScrollView, StyleSheet, Text, TouchableOpacity, View, } from "react-native"; import { Images } from "@/constants/images"; interface ProductItem { id: string; name: string; cover: string; level: string; probability: number; price?: number; quantity?: number; spu?: { id: string; cover: string; name: string; }; } interface ProductListProps { products: ProductItem[]; levelList?: any[]; poolId: string; price: number; } // 等级配置 - 对应小程序的 LEVEL_MAP const LEVEL_CONFIG: Record< string, { title: string; color: string; bgColor: string; productItem: string } > = { 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, }, }; const ignoreRatio0 = (val: number) => { // Revert to original logic: Do NOT multiply. Assume API sends WYSIWYG value (e.g. 99.05 or 0.001) // Just format string to remove trailing zeros. let str = String(val); // Match original logic: strip trailing zeros if decimal if (str.indexOf(".") > -1) { str = str.replace(/0+$/, "").replace(/\.$/, ""); } return str; }; export const ProductList: React.FC = ({ products, levelList, poolId, }) => { const router = useRouter(); // 按等级分组 const groupedProducts = products.reduce( (acc, item) => { const level = item.level || "D"; if (!acc[level]) acc[level] = []; acc[level].push(item); return acc; }, {} as Record, ); // 计算各等级概率 const getLevelProbability = (level: string) => { const item = levelList?.find((e) => e.level === level); return item ? `${item.probability}%` : "0%"; }; // 点击产品跳转到详情页 const handleProductPress = (item: ProductItem) => { // Look up by object reference to handle duplicate IDs correctly const index = products.indexOf(item); router.push({ pathname: "/treasure-hunt/swipe" as any, params: { poolId, index: index >= 0 ? index : 0 }, }); }; const renderLevelSection = (level: string, items: ProductItem[]) => { const config = LEVEL_CONFIG[level] || LEVEL_CONFIG["D"]; return ( {/* 等级标题行 */} {config.title} 概率: {getLevelProbability(level)} {/* 商品横向滚动列表 */} {items.map((item, index) => { const cover = item.spu?.cover || item.cover; return ( handleProductPress(item)} activeOpacity={0.8} > {/* 商品图片 */} {/* 概率标签背景 */} 概率: {ignoreRatio0(item.probability)}% ); })} ); }; const levelOrder = ["A", "B", "C", "D"]; return ( {/* 标题 */} {levelOrder.map((level) => { const items = groupedProducts[level]; if (!items || items.length === 0) return null; return renderLevelSection(level, items); })} ); }; const styles = StyleSheet.create({ container: { paddingHorizontal: 10, marginTop: -40, }, titleBox: { alignItems: "center", marginBottom: 15, }, titleImg: { width: 121, height: 29, }, levelBox: { marginBottom: 20, }, levelTitleRow: { flexDirection: "row", alignItems: "center", justifyContent: "center", paddingHorizontal: 14, paddingBottom: 10, position: "relative", }, levelTitle: { fontSize: 18, fontWeight: "bold", textAlign: "center", textShadowColor: "#000", textShadowOffset: { width: 1, height: 1 }, textShadowRadius: 1, }, levelProportion: { position: "absolute", right: 0, bottom: 10, flexDirection: "row", alignItems: "center", }, probabilityLabel: { fontSize: 12, color: "#ffc901", }, probabilityValue: { fontSize: 12, color: "#fff", }, scrollContent: { paddingHorizontal: 5, }, productItem: { width: 88, height: 110, marginRight: 10, alignItems: "center", }, productImage: { width: 88, height: 90, }, levelTagBg: { width: 88, height: 53, marginTop: -18, justifyContent: "center", paddingTop: 12, }, levelTagContent: { flexDirection: "row", justifyContent: "center", alignItems: "center", }, levelTagLabel: { fontSize: 8, color: "#fff", }, levelTagText: { fontSize: 9, color: "#fff", fontWeight: "bold", }, });