Преглед на файлове

fix: 修复Apple审核拒绝问题

- 实现首页三个快捷入口按钮: 领福利→客服二维码, 福利屋→每日补给, 攻略→游戏攻略
- App名称 asios → 艾斯潮盒 (匹配App Store)
- Build Number: 19
zbb преди 1 месец
родител
ревизия
f2b73d24f9
променени са 5 файла, в които са добавени 107 реда и са изтрити 52 реда
  1. 3 3
      app.json
  2. 26 3
      app/(tabs)/index.tsx
  3. 10 3
      app/award-detail/components/CheckoutModal.tsx
  4. 58 40
      app/happy-spin/index.tsx
  5. 10 3
      app/treasure-hunt/components/CheckoutModal.tsx

+ 3 - 3
app.json

@@ -1,8 +1,8 @@
 {
   "expo": {
-    "name": "asios",
+    "name": "艾斯潮盒",
     "slug": "asios",
-    "version": "1.0.2",
+    "version": "1.0.3",
     "orientation": "portrait",
     "icon": "./assets/images/icon.png",
     "scheme": ["asios", "alipay2021005175632205"],
@@ -12,7 +12,7 @@
       "supportsTablet": false,
       "bundleIdentifier": "com.asios",
       "appleTeamId": "Y9ZVX3FRX6",
-      "buildNumber": "17",
+      "buildNumber": "19",
       "infoPlist": {
         "ITSAppUsesNonExemptEncryption": false,
         "NSPhotoLibraryUsageDescription": "App需要访问您的相册以便您可以上传头像或保存商品分享图片。",

+ 26 - 3
app/(tabs)/index.tsx

@@ -1,5 +1,11 @@
 import { useRouter } from "expo-router";
-import React, { useCallback, useEffect, useMemo, useState } from "react";
+import React, {
+    useCallback,
+    useEffect,
+    useMemo,
+    useRef,
+    useState,
+} from "react";
 import {
     ActivityIndicator,
     FlatList,
@@ -7,10 +13,12 @@ import {
     StatusBar,
     StyleSheet,
     Text,
-    View
+    View,
 } from "react-native";
 import { useSafeAreaInsets } from "react-native-safe-area-context";
 
+import { KefuPopup, KefuPopupRef } from "@/components/mine/KefuPopup";
+
 import { Banner } from "@/components/home/Banner";
 import { GoodsCard } from "@/components/home/GoodsCard";
 import { IPFilter } from "@/components/home/IPFilter";
@@ -26,6 +34,7 @@ import { getGoodsList, GoodsItem, GoodsListParams } from "@/services/mall";
 export default function HomeScreen() {
   const insets = useSafeAreaInsets();
   const router = useRouter();
+  const kefuRef = useRef<KefuPopupRef>(null);
   const [refreshing, setRefreshing] = useState(false);
   const [loading, setLoading] = useState(true);
   const [listLoading, setListLoading] = useState(false);
@@ -131,7 +140,20 @@ export default function HomeScreen() {
 
   // 功能入口点击
   const handleQuickEntryPress = (item: TabItem) => {
-    console.log("Quick entry pressed:", item);
+    const title = item.title?.trim();
+    if (title === "领福利") {
+      kefuRef.current?.open();
+    } else if (title === "福利屋") {
+      router.push("/dimension/room" as any);
+    } else if (title === "攻略") {
+      router.push({
+        pathname: "/agreement" as any,
+        params: { type: "game_walkthrough" },
+      });
+    } else if (item.path?.url) {
+      // 通用跳转:后端配置了 URL 的按钮
+      router.push(item.path.url as any);
+    }
   };
 
   // IP 筛选
@@ -246,6 +268,7 @@ export default function HomeScreen() {
           onEndReachedThreshold={0.5}
         />
       </View>
+      <KefuPopup ref={kefuRef} />
     </View>
   );
 }

+ 10 - 3
app/award-detail/components/CheckoutModal.tsx

@@ -263,7 +263,7 @@ export const CheckoutModal = forwardRef<CheckoutModalRef, CheckoutModalProps>(
     const [verifyLoading, setVerifyLoading] = useState(false);
     const isNavigatingRef = useRef(false);
 
-    const handleSuccess = (tradeNo: string) => {
+    const handleSuccess = (tradeNo: string, inventoryList?: any[]) => {
       setVerifyLoading(false);
       setVisible(false);
 
@@ -272,7 +272,14 @@ export const CheckoutModal = forwardRef<CheckoutModalRef, CheckoutModalProps>(
 
       router.replace({
         pathname: "/lottery" as any,
-        params: { tradeNo, num, poolId },
+        params: {
+          tradeNo,
+          num,
+          poolId,
+          ...(inventoryList
+            ? { prefetchedResults: JSON.stringify(inventoryList) }
+            : {}),
+        },
       });
       onSuccess({ tradeNo, num });
     };
@@ -321,7 +328,7 @@ export const CheckoutModal = forwardRef<CheckoutModalRef, CheckoutModalProps>(
                       clearInterval(pollInterval);
                       clearTimeout(loadingTimer);
                       setVerifyLoading(false);
-                      handleSuccess(tradeNo);
+                      handleSuccess(tradeNo, res?.inventoryList);
                     }
                   } catch (e) {
                     console.log("Fallback poll failed", e);

+ 58 - 40
app/happy-spin/index.tsx

@@ -35,6 +35,7 @@ export default function LotteryScreen() {
 
   const tradeNo = params.tradeNo as string;
   const poolId = params.poolId as string;
+  const prefetchedResults = params.prefetchedResults as string | undefined;
 
   const [results, setResults] = useState<any[]>([]);
   const [pool, setPool] = useState<any[]>([]);
@@ -102,50 +103,67 @@ export default function LotteryScreen() {
   };
 
   const loadData = async () => {
-    if (tradeNo) {
-      try {
-        const res: any = await services.award.getApplyResult(tradeNo);
-        const list = res?.data?.inventoryList || res?.inventoryList || [];
-        setResults(list);
-
-        // 2. Fetch Pool (Goods) if not passed
-        if (poolId && !isGrid) {
-          const detailRes = await services.award.getPoolDetail(poolId);
-          const goods = detailRes?.luckGoodsList || [];
-          setPool(goods);
-        } else if (!isGrid) {
-          setPool(list);
+    if (!tradeNo) return;
+    try {
+      // 优先使用预取数据,避免重复网络请求
+      let list: any[] = [];
+      let videoFromRes = "";
+
+      if (prefetchedResults) {
+        try {
+          list = JSON.parse(prefetchedResults);
+        } catch (e) {
+          console.warn(
+            "Failed to parse prefetchedResults, falling back to API",
+          );
         }
+      }
+
+      if (list.length === 0) {
+        // fallback: 没有预取数据时才调用 API
+        const res: any = await services.award.getApplyResult(tradeNo);
+        list = res?.data?.inventoryList || res?.inventoryList || [];
+        videoFromRes = res?.video || "";
+      }
+
+      setResults(list);
+
+      // Pool 数据不阻塞动画,并行加载
+      if (poolId && !isGrid) {
+        services.award
+          .getPoolDetail(poolId)
+          .then((detailRes: any) => {
+            const goods = detailRes?.luckGoodsList || [];
+            setPool(goods);
+          })
+          .catch(() => setPool(list));
+      } else if (!isGrid) {
+        setPool(list);
+      }
+
+      // Auto show result after animation
+      if (timerRef.current) clearTimeout(timerRef.current);
 
-        // Auto show result after animation
-        if (timerRef.current) clearTimeout(timerRef.current);
-
-        // 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);
-          }
+      // Check for Level A video
+      const hasLevelA = list.some((item: any) =>
+        ["A", "a"].includes(item.level),
+      );
+      const playVideoUrl =
+        videoFromRes || (hasLevelA ? DEFAULT_JACKPOT_VIDEO : "");
+
+      if (playVideoUrl) {
+        console.log("Found Level A, preparing video:", playVideoUrl);
+        setVideoUrl(playVideoUrl);
+        setVideoVisible(true);
+      } else {
+        if (!isGrid) {
+          timerRef.current = setTimeout(() => {
+            handleFinish(list);
+          }, 2800);
         }
-        // Grid mode handles finish via callback
-      } catch (error) {
-        console.error("Load Data Error", error);
-        // Safety fallback?
       }
+    } catch (error) {
+      console.error("Load Data Error", error);
     }
   };
 

+ 10 - 3
app/treasure-hunt/components/CheckoutModal.tsx

@@ -263,7 +263,7 @@ export const CheckoutModal = forwardRef<CheckoutModalRef, CheckoutModalProps>(
     const [verifyLoading, setVerifyLoading] = useState(false);
     const isNavigatingRef = useRef(false);
 
-    const handleSuccess = (tradeNo: string) => {
+    const handleSuccess = (tradeNo: string, inventoryList?: any[]) => {
       setVerifyLoading(false);
       setVisible(false);
 
@@ -272,7 +272,14 @@ export const CheckoutModal = forwardRef<CheckoutModalRef, CheckoutModalProps>(
 
       router.replace({
         pathname: "/treasure-hunt/happy-spin" as any,
-        params: { tradeNo, num, poolId },
+        params: {
+          tradeNo,
+          num,
+          poolId,
+          ...(inventoryList
+            ? { prefetchedResults: JSON.stringify(inventoryList) }
+            : {}),
+        },
       });
       onSuccess({ tradeNo, num });
     };
@@ -321,7 +328,7 @@ export const CheckoutModal = forwardRef<CheckoutModalRef, CheckoutModalProps>(
                       clearInterval(pollInterval);
                       clearTimeout(loadingTimer);
                       setVerifyLoading(false);
-                      handleSuccess(tradeNo);
+                      handleSuccess(tradeNo, res?.inventoryList);
                     }
                   } catch (e) {
                     console.log("Fallback poll failed", e);