|
|
@@ -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,
|
|
|
+ },
|
|
|
+});
|