Browse Source

添加A赏出视频

zbb 3 tháng trước cách đây
mục cha
commit
2eff4c89eb
2 tập tin đã thay đổi với 106 bổ sung45 xóa
  1. 36 37
      app/award-detail/components/LotteryResultModal.tsx
  2. 70 8
      app/lottery/index.tsx

+ 36 - 37
app/award-detail/components/LotteryResultModal.tsx

@@ -3,6 +3,7 @@ import { Image } from 'expo-image';
 import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
 import {
     ActivityIndicator,
+    Alert,
     Animated,
     Dimensions,
     ImageBackground,
@@ -141,7 +142,19 @@ export const LotteryResultModal = forwardRef<LotteryResultModalRef, LotteryResul
     const [videoVisible, setVideoVisible] = useState(false);
     const [videoUrl, setVideoUrl] = useState('');
 
+    const videoRef = useRef<Video>(null);
     const flipAnims = useRef<Animated.Value[]>([]);
+
+    const startFlow = (data: LotteryItem[]) => {
+        setVideoVisible(false);
+        const levelAItem = data.find((item: LotteryItem) => ['A', 'a'].includes(item.level));
+        if (levelAItem) {
+            setKingData(levelAItem);
+            setKingVisible(true);
+        } else {
+            setTimeout(() => flipCards(data), 500);
+        }
+    };
     const dataLoadedRef = useRef(false);
 
     useImperativeHandle(ref, () => ({
@@ -228,40 +241,28 @@ export const LotteryResultModal = forwardRef<LotteryResultModalRef, LotteryResul
             if (res.video) {
                 playVideoUrl = res.video;
             } else {
-                // Check if any Level A item exists
-                const hasLevelA = array.some((item: LotteryItem) => item.level === 'A');
+                // Check if any Level A item exists (Robust check)
+                const hasLevelA = array.some((item: LotteryItem) => ['A', 'a'].includes(item.level));
                 if (hasLevelA) {
                     playVideoUrl = DEFAULT_JACKPOT_VIDEO;
                 }
             }
 
-            // Check for Level A item for KingModal logic (which happens after video)
-            const levelAItem = array.find((item: LotteryItem) => item.level === 'A');
-
-            const startFlow = () => {
-                setVideoVisible(false);
-                if (levelAItem) {
-                    setKingData(levelAItem);
-                    setKingVisible(true);
-                } else {
-                    setTimeout(() => flipCards(array), 500);
-                }
-            };
-
             if (playVideoUrl) {
                 setVideoUrl(playVideoUrl);
                 setVideoVisible(true);
             } else {
-                startFlow();
+                startFlow(array);
             }
           } else if (attempts < maxAttempts) {
             attempts++;
             timeoutId = setTimeout(fetchData, 400);
           } else {
             setLoading(false);
-            window.alert('获取结果超时,请在仓库中查看');
+            Alert.alert('提示', '获取结果超时,请在仓库中查看');
           }
         } catch (error) {
+          console.error(error);
           if (attempts < maxAttempts) {
             attempts++;
             timeoutId = setTimeout(fetchData, 400);
@@ -294,10 +295,11 @@ export const LotteryResultModal = forwardRef<LotteryResultModalRef, LotteryResul
         if (res) {
           setTableData((prev) => prev.map((item) => ({ ...item, magicAmount: 0 })));
           setTotal(0);
-          window.alert('兑换成功');
+          setTotal(0);
+          Alert.alert('提示', '兑换成功');
         }
       } catch {
-        window.alert('兑换失败,请重试');
+        Alert.alert('提示', '兑换失败,请重试');
       }
     };
 
@@ -468,23 +470,27 @@ export const LotteryResultModal = forwardRef<LotteryResultModalRef, LotteryResul
         {videoVisible && videoUrl ? (
             <View style={styles.videoContainer}>
                 <Video
+                    key={videoUrl}
+                    ref={videoRef}
                     source={{ uri: videoUrl }}
                     style={styles.video}
                     resizeMode={ResizeMode.COVER}
                     shouldPlay
                     isLooping={false}
+                    useNativeControls={false}
+                    onLoad={() => {
+                        videoRef.current?.playAsync();
+                    }}
+                    onError={(error) => {
+                        console.error('Video playback error:', error);
+                        setVideoVisible(false);
+                        startFlow(tableData);
+                    }}
                     onPlaybackStatusUpdate={(status: AVPlaybackStatus) => {
-                        if (status.isLoaded && status.didJustFinish) {
-                             // Video finished
+                        if (!status.isLoaded) return;
+                        if (status.didJustFinish) {
                              setVideoVisible(false);
-                             // Proceed to next step
-                             const levelAItem = tableData.find((item: LotteryItem) => item.level === 'A');
-                             if (levelAItem) {
-                                 setKingData(levelAItem);
-                                 setKingVisible(true);
-                             } else {
-                                 setTimeout(() => flipCards(tableData), 300);
-                             }
+                             startFlow(tableData);
                         }
                     }}
                 />
@@ -492,14 +498,7 @@ export const LotteryResultModal = forwardRef<LotteryResultModalRef, LotteryResul
                     style={styles.skipVideoBtn} 
                     onPress={() => {
                         setVideoVisible(false);
-                         // Proceed to next step
-                         const levelAItem = tableData.find((item: LotteryItem) => item.level === 'A');
-                         if (levelAItem) {
-                             setKingData(levelAItem);
-                             setKingVisible(true);
-                         } else {
-                             setTimeout(() => flipCards(tableData), 300);
-                         }
+                        startFlow(tableData);
                     }}
                 >
                     <Text style={styles.skipText}>跳过</Text>

+ 70 - 8
app/lottery/index.tsx

@@ -1,4 +1,4 @@
-import { Audio } from 'expo-av';
+import { Audio, AVPlaybackStatus, ResizeMode, Video } from 'expo-av';
 import { Image } from 'expo-image';
 import { Stack, useLocalSearchParams, useRouter } from 'expo-router';
 import React, { useEffect, useRef, useState } from 'react';
@@ -15,6 +15,7 @@ const { width: SCREEN_WIDTH } = Dimensions.get('window');
 
 // Sound URL from Uniapp config
 const SOUND_URL = 'https://cdn.acetoys.cn/kai_xin_ma_te/resource/magic/lottery.mp3';
+const DEFAULT_JACKPOT_VIDEO = 'https://cdn.acetoys.cn/kai_xin_ma_te/supermart/box/lottery/jackpot.mp4';
 
 export default function LotteryScreen() {
   const router = useRouter();
@@ -33,6 +34,11 @@ export default function LotteryScreen() {
   const [sound, setSound] = useState<Audio.Sound>();
   const [animationFinished, setAnimationFinished] = useState(false);
   
+  // Video state
+  const [videoVisible, setVideoVisible] = useState(false);
+  const [videoUrl, setVideoUrl] = useState('');
+  const videoRef = useRef<Video>(null);
+  
   // Timer Ref for cleanup
   const timerRef = useRef<any>(null);
 
@@ -93,11 +99,23 @@ export default function LotteryScreen() {
              // Auto show result after animation
              if (timerRef.current) clearTimeout(timerRef.current);
              
-             if (!isGrid) {
-                // Reel mode uses timer
-                timerRef.current = setTimeout(() => {
-                    handleFinish(list);
-                }, 2800); 
+             // Check for Level A video
+             const hasLevelA = list.some((item: any) => ['A', 'a'].includes(item.level));
+             // Also check res.video if available
+             const playVideoUrl = res.video || (hasLevelA ? DEFAULT_JACKPOT_VIDEO : '');
+
+             if (playVideoUrl) {
+                 console.log('Found Level A, preparing video:', playVideoUrl);
+                 setVideoUrl(playVideoUrl);
+                 setVideoVisible(true);
+                 // Do NOT set timer here, wait for video to finish
+             } else {
+                 if (!isGrid) {
+                    // Reel mode uses timer
+                    timerRef.current = setTimeout(() => {
+                        handleFinish(list);
+                    }, 2800); 
+                 }
              }
              // Grid mode handles finish via callback
          } catch (error) {
@@ -134,6 +152,12 @@ export default function LotteryScreen() {
   };
   
   const handleSkip = () => {
+      if (videoVisible) {
+          setVideoVisible(false);
+          handleFinish();
+          return;
+      }
+
       if (isGrid) {
           if (animationFinished) {
               // User clicked "Claim Prize", exit
@@ -211,13 +235,42 @@ export default function LotteryScreen() {
          )}
       </View>
 
+      {/* Video Overlay */}
+      {videoVisible && videoUrl ? (
+        <View style={styles.videoContainer}>
+            <Video
+                ref={videoRef}
+                key={videoUrl}
+                source={{ uri: videoUrl }}
+                style={styles.video}
+                resizeMode={ResizeMode.COVER}
+                shouldPlay
+                isLooping={false}
+                useNativeControls={false}
+                onLoad={() => {
+                    videoRef.current?.playAsync();
+                }}
+                onPlaybackStatusUpdate={(status: AVPlaybackStatus) => {
+                    if (status.isLoaded && status.didJustFinish) {
+                         setVideoVisible(false);
+                         handleFinish();
+                    }
+                }}
+                onError={() => {
+                    setVideoVisible(false);
+                    handleFinish();
+                }}
+            />
+        </View>
+      ) : null}
+
       <View style={styles.bottom}>
         <TouchableOpacity 
             style={styles.skipBtn} 
             onPress={handleSkip}
         >
             <Text style={styles.skipText}>
-                {isGrid && animationFinished ? '收下奖品' : '跳过动画'}
+                {videoVisible ? '跳过动画' : (isGrid && animationFinished ? '收下奖品' : '跳过动画')}
             </Text>
         </TouchableOpacity>
       </View>
@@ -299,7 +352,7 @@ const styles = StyleSheet.create({
     bottom: 50,
      width: '100%',
      alignItems: 'center',
-     zIndex: 30,
+     zIndex: 60,
   },
   skipBtn: {
       backgroundColor: 'rgba(255,255,255,0.2)',
@@ -313,4 +366,13 @@ const styles = StyleSheet.create({
       color: '#fff',
       fontSize: 14,
   },
+  videoContainer: {
+      ...StyleSheet.absoluteFillObject,
+      backgroundColor: '#000',
+      zIndex: 50,
+  },
+  video: {
+      width: '100%',
+      height: '100%',
+  },
 });