ソースを参照

fix: 修复正确仓库页面(store)的赏品点击跳转详情 build 29

zbb 1 ヶ月 前
コミット
81768c4539
4 ファイル変更306 行追加3 行削除
  1. 1 1
      app.json
  2. 1 0
      app/store/_layout.tsx
  3. 298 0
      app/store/detail.tsx
  4. 6 2
      app/store/index.tsx

+ 1 - 1
app.json

@@ -12,7 +12,7 @@
       "supportsTablet": false,
       "bundleIdentifier": "com.asios",
       "appleTeamId": "Y9ZVX3FRX6",
-      "buildNumber": "28",
+      "buildNumber": "29",
       "infoPlist": {
         "CFBundleDisplayName": "艾斯潮盒",
         "ITSAppUsesNonExemptEncryption": false,

+ 1 - 0
app/store/_layout.tsx

@@ -6,6 +6,7 @@ export default function StoreLayout() {
       <Stack.Screen name="index" />
       <Stack.Screen name="checkout" />
       <Stack.Screen name="packages" />
+      <Stack.Screen name="detail" />
     </Stack>
   );
 }

+ 298 - 0
app/store/detail.tsx

@@ -0,0 +1,298 @@
+import { Image } from "expo-image";
+import { useLocalSearchParams, useRouter } from "expo-router";
+import React, { useCallback, useEffect, useRef, useState } from "react";
+import {
+    ActivityIndicator,
+    Alert,
+    ImageBackground,
+    StatusBar,
+    StyleSheet,
+    Text,
+    TouchableOpacity,
+    View,
+} from "react-native";
+import { useSafeAreaInsets } from "react-native-safe-area-context";
+
+import { Images } from "@/constants/images";
+import { convertApply, convertPreview, getLuckDetail } from "@/services/award";
+
+const LEVEL_MAP: Record<string, { title: string; color: string }> = {
+  A: { title: "超神", color: "#FF3B30" },
+  B: { title: "欧皇", color: "#FF9500" },
+  C: { title: "隐藏", color: "#AF52DE" },
+  D: { title: "普通", color: "#8E8E93" },
+};
+
+const FROM_TYPE_MAP: Record<string, string> = {
+  MALL: "商城",
+  DISTRIBUTION: "分销",
+  LUCK: "奖池",
+  LUCK_PICKUP: "商品提货",
+  LUCK_EXCHANGE: "商品兑换",
+  SUBSTITUTE: "商品置换",
+  TRANSFER: "商品转赠",
+  LUCK_ROOM: "福利房",
+  LUCK_WHEEL: "魔天轮",
+  DOLL_MACHINE: "扭蛋",
+  RECHARGE: "充值",
+  OFFICIAL: "官方",
+  ACTIVITY: "活动",
+  LUCK_ACTIVITY: "奖池活动",
+  REDEEM_CODE_ACTIVITY: "兑换码活动",
+};
+
+export default function StoreDetailScreen() {
+  const params = useLocalSearchParams<{ id: string }>();
+  const id = params?.id;
+  const router = useRouter();
+  const insets = useSafeAreaInsets();
+
+  const [loading, setLoading] = useState(true);
+  const [item, setItem] = useState<any>(null);
+  const [converting, setConverting] = useState(false);
+  const [error, setError] = useState<string | null>(null);
+
+  console.log('[仓库详情] 页面加载, params:', JSON.stringify(params), 'id:', id);
+
+  const loadData = useCallback(async () => {
+    console.log('[仓库详情] loadData 开始, id:', id);
+    if (!id) {
+      setError('未获取到商品ID');
+      setLoading(false);
+      return;
+    }
+    setLoading(true);
+    setError(null);
+    try {
+      const data = await getLuckDetail(id);
+      console.log('[仓库详情] getLuckDetail 返回:', data ? '有数据' : 'null');
+      setItem(data);
+      if (!data) {
+        setError('商品数据为空');
+      }
+    } catch (e: any) {
+      console.error("[仓库详情] 加载失败:", e);
+      setError(`加载失败: ${e?.message || '未知错误'}`);
+    }
+    setLoading(false);
+  }, [id]);
+
+  useEffect(() => {
+    loadData();
+  }, [loadData]);
+
+  const handleConvert = async () => {
+    if (!item || item.magicAmount <= 0) {
+      Alert.alert("提示", "不可兑换");
+      return;
+    }
+    setConverting(true);
+    try {
+      const preview = await convertPreview([item.id]);
+      if (preview?.data) {
+        Alert.alert(
+          "确认兑换",
+          `将兑换 ${item.spu?.name} 获得 ${preview.data?.totalMagicAmount || item.magicAmount} 果实`,
+          [
+            { text: "取消", style: "cancel" },
+            {
+              text: "确定",
+              onPress: async () => {
+                const success = await convertApply([item.id]);
+                if (success) {
+                  Alert.alert("提示", "兑换成功", [
+                    { text: "确定", onPress: () => router.back() },
+                  ]);
+                }
+              },
+            },
+          ],
+        );
+      }
+    } catch (e) {
+      Alert.alert("提示", "兑换失败");
+    }
+    setConverting(false);
+  };
+
+  if (loading) {
+    return (
+      <View style={styles.loadingBox}>
+        <ActivityIndicator size="large" color="#fff" />
+      </View>
+    );
+  }
+
+  if (!item) {
+    return (
+      <View style={styles.loadingBox}>
+        <Text style={{ color: "#999", fontSize: 16 }}>{error || '商品不存在'}</Text>
+        <TouchableOpacity onPress={() => router.back()} style={{ marginTop: 20 }}>
+          <Text style={{ color: "#fff", fontSize: 14 }}>返回</Text>
+        </TouchableOpacity>
+      </View>
+    );
+  }
+
+  const levelInfo = LEVEL_MAP[item.level] || { title: "其他", color: "#999" };
+
+  return (
+    <View style={styles.container}>
+      <StatusBar barStyle="light-content" />
+      <ImageBackground
+        source={{ uri: Images.mine.kaixinMineBg }}
+        style={styles.background}
+        resizeMode="cover"
+      >
+        {/* 顶部导航 */}
+        <View style={[styles.header, { paddingTop: insets.top }]}>
+          <TouchableOpacity
+            style={styles.backBtn}
+            onPress={() => router.back()}
+          >
+            <Text style={styles.backText}>←</Text>
+          </TouchableOpacity>
+          <Text style={styles.title}>仓库</Text>
+          <View style={styles.placeholder} />
+        </View>
+
+        {/* 商品信息 */}
+        <View style={styles.content}>
+          <View style={styles.detailCard}>
+            <Image
+              source={{ uri: item.spu?.cover }}
+              style={styles.coverImage}
+              contentFit="contain"
+            />
+            <Text style={[styles.levelTag, { color: levelInfo.color }]}>
+              {levelInfo.title}
+            </Text>
+            <Text style={styles.goodsName}>{item.spu?.name}</Text>
+            <View style={styles.sourceBox}>
+              <Text style={styles.sourceText}>
+                从{FROM_TYPE_MAP[item.fromRelationType] || "其他"}获得
+              </Text>
+            </View>
+          </View>
+        </View>
+
+        {/* 兑换按钮 */}
+        {item.magicAmount > 0 && (
+          <View
+            style={[
+              styles.bottomBar,
+              { paddingBottom: Math.max(insets.bottom, 20) },
+            ]}
+          >
+            <TouchableOpacity
+              style={styles.convertBtn}
+              onPress={handleConvert}
+              disabled={converting}
+              activeOpacity={0.8}
+            >
+              <ImageBackground
+                source={{ uri: Images.common.loginBtn }}
+                style={styles.convertBtnBg}
+                resizeMode="stretch"
+              >
+                <Text style={styles.convertBtnText}>兑换果实</Text>
+                <Text style={styles.convertBtnSub}>
+                  可兑换 {item.magicAmount} 果实
+                </Text>
+              </ImageBackground>
+            </TouchableOpacity>
+          </View>
+        )}
+      </ImageBackground>
+    </View>
+  );
+}
+
+const styles = StyleSheet.create({
+  container: { flex: 1, backgroundColor: "#1a1a2e" },
+  background: { flex: 1 },
+  loadingBox: {
+    flex: 1,
+    backgroundColor: "#1a1a2e",
+    justifyContent: "center",
+    alignItems: "center",
+  },
+  header: {
+    flexDirection: "row",
+    alignItems: "center",
+    justifyContent: "space-between",
+    paddingHorizontal: 15,
+    paddingBottom: 10,
+  },
+  backBtn: {
+    width: 40,
+    height: 40,
+    justifyContent: "center",
+    alignItems: "center",
+  },
+  backText: { color: "#fff", fontSize: 20 },
+  title: { color: "#fff", fontSize: 16, fontWeight: "bold" },
+  placeholder: { width: 40 },
+
+  content: { flex: 1, paddingHorizontal: 20, paddingTop: 20 },
+  detailCard: {
+    backgroundColor: "rgba(255,255,255,0.95)",
+    borderRadius: 16,
+    padding: 24,
+    alignItems: "center",
+  },
+  coverImage: {
+    width: 180,
+    height: 180,
+    borderRadius: 10,
+    marginBottom: 16,
+  },
+  levelTag: {
+    fontSize: 16,
+    fontWeight: "bold",
+    marginBottom: 8,
+    textShadowColor: "#000",
+    textShadowOffset: { width: 1, height: 1 },
+    textShadowRadius: 0,
+  },
+  goodsName: {
+    fontSize: 16,
+    color: "#333",
+    fontWeight: "bold",
+    textAlign: "center",
+    marginBottom: 12,
+    lineHeight: 22,
+  },
+  sourceBox: {
+    backgroundColor: "rgba(0,0,0,0.05)",
+    borderRadius: 20,
+    paddingHorizontal: 16,
+    paddingVertical: 6,
+  },
+  sourceText: { fontSize: 13, color: "#666" },
+
+  bottomBar: {
+    paddingHorizontal: 30,
+    paddingTop: 10,
+    alignItems: "center",
+  },
+  convertBtn: {
+    width: "80%",
+    height: 60,
+  },
+  convertBtnBg: {
+    width: "100%",
+    height: "100%",
+    justifyContent: "center",
+    alignItems: "center",
+  },
+  convertBtnText: {
+    color: "#000",
+    fontSize: 16,
+    fontWeight: "bold",
+  },
+  convertBtnSub: {
+    color: "#735200",
+    fontSize: 11,
+  },
+});

+ 6 - 2
app/store/index.tsx

@@ -7,6 +7,7 @@ import {
     FlatList,
     ImageBackground,
     Platform,
+    Pressable,
     RefreshControl,
     ScrollView,
     StatusBar,
@@ -230,7 +231,10 @@ export default function StoreScreen() {
     const canSelect = mainTabIndex === 1 || item.safeFlag !== 1;
     return (
       <ImageBackground source={{ uri: Images.mine.storeItemBg }} style={styles.cell} resizeMode="stretch">
-        <View style={styles.cellContent}>
+        <Pressable style={styles.cellContent} onPress={() => {
+          console.log('[仓库store] 点击商品详情, id:', item.id);
+          router.push({ pathname: '/store/detail', params: { id: item.id } } as any);
+        }}>
           <TouchableOpacity style={styles.cellHeader} onPress={() => canSelect && handleChoose(item)}>
             <View style={styles.headerLeft}>
               {canSelect && (
@@ -255,7 +259,7 @@ export default function StoreScreen() {
             </View>
             <Text style={styles.arrow}>{'>'}</Text>
           </View>
-        </View>
+        </Pressable>
       </ImageBackground>
     );
   };