import { Image } from 'expo-image'; import { useRouter } from 'expo-router'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { Animated, Dimensions, ImageBackground, ScrollView, StatusBar, StyleSheet, Text, TouchableOpacity, View, } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { get } from '@/services/http'; const { width: SCREEN_WIDTH } = Dimensions.get('window'); const CDN_BASE = 'https://cdn.acetoys.cn/kai_xin_ma_te/supermart'; const catchDollImages = { bg: `${CDN_BASE}/common/commonBg.png`, dollBox: `${CDN_BASE}/welfare/qijiWelfareDollBox.png`, dollBall: `${CDN_BASE}/welfare/qijiWelfareDollBall.png`, dollOne: `${CDN_BASE}/welfare/qijiWelfareDollOne.png`, dollFive: `${CDN_BASE}/welfare/qijiWelfareDollFive.png`, recordBg: `${CDN_BASE}/welfare/qijiWelfareRecordBg.png`, ruleBtn: `${CDN_BASE}/welfare/catchDollRule.png`, molibiBoxBtn: `${CDN_BASE}/welfare/molibiBoxBtn.png`, opening: `${CDN_BASE}/welfare/opening.png`, dollBi1: `${CDN_BASE}/welfare/qijiWelfareDollBi1.png`, dollBi5: `${CDN_BASE}/welfare/qijiWelfareDollBi5.png`, }; interface GoodsItem { id: string; cover: string; name: string; } export default function CatchDollScreen() { const router = useRouter(); const insets = useSafeAreaInsets(); const [goodsList, setGoodsList] = useState([]); const [molibi, setMolibi] = useState(0); const [balls] = useState(() => Array.from({ length: 50 }, (_, i) => ({ id: i, bottom: Math.random() * 80, left: Math.random() * 172, })) ); // 动画 const ballAnimations = useRef(balls.map(() => new Animated.ValueXY({ x: 0, y: 0 }))).current; const ballRotations = useRef(balls.map(() => new Animated.Value(0))).current; const loadData = useCallback(async () => { try { const res = await get('/api/luckWheel/detail'); if (res.data) { setGoodsList(res.data.luckWheelGoodsList || []); } } catch (error) { console.error('加载扭蛋机数据失败:', error); } }, []); const loadMolibi = useCallback(async () => { try { const res = await get('/api/wallet/info', { type: 'MAGIC_POWER_COIN' }); if (res.data) { setMolibi(res.data.balance || 0); } } catch (error) { console.error('加载源力币失败:', error); } }, []); useEffect(() => { loadData(); loadMolibi(); }, [loadData, loadMolibi]); const animateBalls = () => { const animations = balls.map((_, i) => { const randomX = (Math.random() - 0.5) * 50; const randomY = (Math.random() - 0.5) * 100; const randomRotate = Math.random() * 360; return Animated.parallel([ Animated.sequence([ Animated.timing(ballAnimations[i], { toValue: { x: randomX, y: randomY }, duration: 200, useNativeDriver: true, }), Animated.timing(ballAnimations[i], { toValue: { x: randomX * 0.5, y: randomY * 0.5 }, duration: 300, useNativeDriver: true, }), Animated.timing(ballAnimations[i], { toValue: { x: 0, y: 0 }, duration: 300, useNativeDriver: true, }), ]), Animated.timing(ballRotations[i], { toValue: randomRotate, duration: 800, useNativeDriver: true, }), ]); }); Animated.parallel(animations).start(() => { ballRotations.forEach((rot) => rot.setValue(0)); }); }; const handlePress = (count: number) => { if (molibi < count) { // TODO: 显示源力币不足弹窗 return; } animateBalls(); // TODO: 调用抽奖接口 }; return ( {/* 固定头部 */} router.back()}> 扭蛋机 {/* 规则按钮 - 固定位置 */} {/* 中奖记录按钮 - 固定位置 */} {/* 扭蛋机主体 */} {/* 奖品列表 */} {goodsList.map((item, index) => ( ))} {/* 扭蛋球区域 */} {balls.map((ball, i) => ( ))} {/* 源力币信息框 */} 源力币:{molibi} router.push('/award' as any)}> {/* 开口动画区域 */} {/* 扭蛋把手 */} handlePress(1)}> handlePress(5)}> {/* 底部按钮 */} handlePress(1)}> handlePress(5)}> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#1a1a2e' }, background: { flex: 1 }, header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: 10, paddingBottom: 10, position: 'absolute', top: 0, left: 0, right: 0, zIndex: 100, }, backBtn: { width: 40, height: 40, justifyContent: 'center', alignItems: 'center' }, backText: { color: '#fff', fontSize: 20 }, title: { color: '#fff', fontSize: 15, fontWeight: 'bold' }, placeholder: { width: 40 }, scrollView: { flex: 1 }, // 规则按钮 ruleBtn: { position: 'absolute', left: 13, zIndex: 99 }, ruleBtnImg: { width: 62, height: 20 }, // 中奖记录按钮 recordBtn: { position: 'absolute', right: 0, zIndex: 99 }, recordBtnBg: { width: 26, height: 70, justifyContent: 'center', alignItems: 'center', paddingVertical: 9, }, recordText: { color: '#fff', fontSize: 12, fontWeight: 'bold', textShadowColor: '#6C3200', textShadowOffset: { width: 1, height: 1 }, textShadowRadius: 1, }, // 扭蛋机主体 machineWrapper: { width: SCREEN_WIDTH, alignItems: 'center', }, machineImg: { width: SCREEN_WIDTH, height: SCREEN_WIDTH * 1.88, position: 'relative', }, // 奖品列表 goodsListWrapper: { position: 'absolute', top: SCREEN_WIDTH * 0.29, left: 0, right: 0, alignItems: 'center', }, goodsScroll: { paddingHorizontal: SCREEN_WIDTH * 0.18, }, goodsItem: { width: 46, height: 46, borderRadius: 4, backgroundColor: '#ADAEF6', borderWidth: 2.5, borderColor: '#8687E4', marginRight: 5, overflow: 'hidden', }, goodsImg: { width: '100%', height: '100%' }, // 扭蛋球区域 ballsBox: { position: 'absolute', top: SCREEN_WIDTH * 0.33, left: SCREEN_WIDTH * 0.115, width: SCREEN_WIDTH * 0.73, height: SCREEN_WIDTH * 0.74, overflow: 'hidden', }, ball: { position: 'absolute', width: 66, height: 66, }, ballImg: { width: '100%', height: '100%' }, // 源力币信息框 molibiBox: { position: 'absolute', top: SCREEN_WIDTH * 1.24, left: 42, width: 120, height: 67, backgroundColor: '#1E1C5B', borderRadius: 8, paddingTop: 5, alignItems: 'center', }, molibiLabel: { color: '#7982CB', fontSize: 12, }, molibiNum: { color: '#FF8400', fontSize: 18, fontWeight: 'bold', }, molibiBtn: { marginTop: 5, }, molibiBtnImg: { width: 105, height: 30, }, // 开口动画区域 openingBox: { position: 'absolute', top: SCREEN_WIDTH * 1.21, right: 42, width: 133, height: 82, }, openingImg: { width: '100%', height: '100%' }, // 扭蛋把手 switchBox: { position: 'absolute', top: SCREEN_WIDTH * 1.49, width: 65, height: 65, }, switchBox1: { left: 42 }, switchBox5: { right: 42 }, switchImg: { width: '100%', height: '100%' }, // 底部按钮 bottomBtns: { flexDirection: 'row', justifyContent: 'center', marginTop: -SCREEN_WIDTH * 0.24, paddingHorizontal: 20, }, submitBtn: { marginHorizontal: SCREEN_WIDTH * 0.08, }, submitBtnImg: { width: 73, height: 50, }, });