| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678 |
- import { KefuPopup, KefuPopupRef } from "@/components/mine/KefuPopup";
- import { MenuCell } from "@/components/mine/MenuCell";
- import { Colors } from "@/constants/Colors";
- import { Images } from "@/constants/images";
- import { getMagicIndex } from "@/services/award";
- import { getParamConfig, getUserInfo, UserInfo } from "@/services/user";
- import * as Clipboard from "expo-clipboard";
- import { Image } from "expo-image";
- import { useFocusEffect, useRouter } from "expo-router";
- import React, { useCallback, useRef, useState } from "react";
- import {
- Alert,
- ScrollView,
- StatusBar,
- StyleSheet,
- Text,
- TouchableOpacity,
- View,
- } from "react-native";
- import { useSafeAreaInsets } from "react-native-safe-area-context";
- interface IndexData {
- couponCount?: number;
- inventoryCount?: number;
- magicBalance?: number;
- treasureBoxCount?: number;
- }
- export default function MineScreen() {
- const router = useRouter();
- const insets = useSafeAreaInsets();
- const [userInfo, setUserInfo] = useState<UserInfo | null>(null);
- const [indexData, setIndexData] = useState<IndexData | null>(null);
- const [inviteShow, setInviteShow] = useState(false);
- const [filingInfo, setFilingInfo] = useState<{
- state: number;
- data: string;
- } | null>(null);
- const [showWallet, setShowWallet] = useState(false);
- const [showExchange, setShowExchange] = useState(false);
- const kefuRef = useRef<KefuPopupRef>(null);
- const loadData = useCallback(async () => {
- try {
- const [info, magicData] = await Promise.all([
- getUserInfo(),
- getMagicIndex(),
- ]);
- setUserInfo(info);
- setIndexData(magicData);
- const inviteConfig = await getParamConfig("invite_config");
- setInviteShow(inviteConfig?.state !== 0);
- const filingConfig = await getParamConfig("beian_icp");
- if (filingConfig) {
- setFilingInfo({ state: filingConfig.state, data: filingConfig.data });
- }
- const walletConfig = await getParamConfig("wallet_recharge_show");
- setShowWallet(walletConfig?.state === 1);
- const exchangeConfig = await getParamConfig("harry_exchange_show");
- setShowExchange(exchangeConfig?.state === 1);
- } catch (error) {
- console.error("获取数据失败:", error);
- }
- }, []);
- useFocusEffect(
- useCallback(() => {
- loadData();
- }, [loadData]),
- );
- const handleLogin = () => {
- if (!userInfo) {
- router.push("/login" as any);
- }
- };
- const handleCopy = async (text: string) => {
- await Clipboard.setStringAsync(text);
- Alert.alert("提示", "复制成功");
- };
- const handleMenuPress = (route: string) => {
- if (!userInfo) {
- router.push("/login" as any);
- return;
- }
- if (route) {
- router.push(route as any);
- }
- };
- const handleMenuItemPress = (type: string) => {
- if (!userInfo && type !== "4_4") {
- router.push("/login" as any);
- return;
- }
- switch (type) {
- case "1_1": // 钱包
- router.push("/wallet" as any);
- break;
- case "2_0": // 全部订单
- router.push("/orders" as any);
- break;
- case "6_1": // 兑换码
- router.push("/exchange" as any);
- break;
- case "4_4": // 联系客服
- kefuRef.current?.open();
- break;
- case "4_3": // 地址
- router.push("/address" as any);
- break;
- case "4_9": // 意见反馈
- router.push("/feedback" as any);
- break;
- case "4_5": // 设置
- router.push("/setting" as any);
- break;
- default:
- break;
- }
- };
- const showNumber = (key: keyof IndexData) => {
- if (!indexData) return "-";
- if (typeof indexData[key] === "undefined") return "-";
- return bigNumberTransform(indexData[key]!);
- };
- const bigNumberTransform = (value: number) => {
- const newValue = ["", "", ""];
- let fr = 1000;
- let num = 3;
- let text1 = "";
- let fm = 1;
- let tempValue = value;
- while (tempValue / fr >= 1) {
- fr *= 10;
- num += 1;
- }
- if (num <= 4) {
- newValue[0] = parseInt(String(value / 1000)) + "";
- newValue[1] = "千";
- } else if (num <= 8) {
- text1 = (num - 4) / 3 > 1 ? "千万" : "万";
- fm = text1 === "万" ? 10000 : 10000000;
- if (value % fm === 0) {
- newValue[0] = parseInt(String(value / fm)) + "";
- } else {
- newValue[0] = String(Math.floor((value / fm) * 10) / 10);
- }
- newValue[1] = text1;
- } else if (num <= 16) {
- text1 = (num - 8) / 3 > 1 ? "千亿" : "亿";
- text1 = (num - 8) / 4 > 1 ? "万亿" : text1;
- text1 = (num - 8) / 7 > 1 ? "千万亿" : text1;
- fm = 1;
- if (text1 === "亿") {
- fm = 100000000;
- } else if (text1 === "千亿") {
- fm = 100000000000;
- } else if (text1 === "万亿") {
- fm = 1000000000000;
- } else if (text1 === "千万亿") {
- fm = 1000000000000000;
- }
- if (value % fm === 0) {
- newValue[0] = parseInt(String(value / fm)) + "";
- } else {
- newValue[0] = String(Math.floor((value / fm) * 10) / 10);
- }
- newValue[1] = text1;
- }
- if (value < 1000) {
- newValue[0] = String(value);
- newValue[1] = "";
- }
- return newValue.join("");
- };
- // Stat Card Component
- const StatCard = ({ num, label, onPress }: any) => (
- <TouchableOpacity style={styles.dataItem} onPress={onPress}>
- <Text style={styles.dataNum}>{num}</Text>
- <Text style={styles.dataLabel}>{label}</Text>
- <View style={styles.dataLine} />
- </TouchableOpacity>
- );
- return (
- <View style={styles.container}>
- <StatusBar barStyle="light-content" />
- {/* Scroll View */}
- <ScrollView
- style={styles.scrollView}
- contentContainerStyle={{
- paddingTop: insets.top + 20,
- paddingBottom: 100,
- }}
- showsVerticalScrollIndicator={false}
- >
- {/* Header Title */}
- <View style={styles.header}>
- <Text style={styles.title}>DATA CENTER</Text>
- <Text style={styles.subTitle}>个人档案</Text>
- </View>
- {/* User Info Card */}
- <View style={styles.userCard}>
- <View style={styles.userContent}>
- <TouchableOpacity
- style={styles.avatarContainer}
- onPress={handleLogin}
- activeOpacity={0.8}
- >
- <Image
- source={{
- uri: userInfo?.avatar || Images.common.defaultAvatar,
- }}
- style={styles.avatar}
- contentFit="cover"
- />
- <View style={styles.avatarBorder} />
- </TouchableOpacity>
- <View style={styles.userInfo}>
- <View style={styles.nicknameRow}>
- <Text style={styles.nickname}>
- {userInfo?.nickname || "未授权访问"}
- </Text>
- {userInfo && (
- <TouchableOpacity
- onPress={() => handleMenuPress("/profile")}
- style={styles.editBtn}
- >
- <Text style={styles.editBtnText}>EDIT</Text>
- </TouchableOpacity>
- )}
- </View>
- {userInfo ? (
- <View style={styles.idRow}>
- <TouchableOpacity
- style={styles.idItem}
- onPress={() =>
- handleCopy(userInfo.username || userInfo.id || "")
- }
- >
- <Text style={styles.idText}>
- ID: {userInfo.username || userInfo.id}
- </Text>
- <View style={styles.copyBadge}>
- <Text style={styles.copyText}>COPY</Text>
- </View>
- </TouchableOpacity>
- {(userInfo.mobile || userInfo.phone) && (
- <Text style={styles.phoneText}>
- Mobile: {userInfo.mobile || userInfo.phone}
- </Text>
- )}
- </View>
- ) : (
- <TouchableOpacity onPress={handleLogin}>
- <Text style={styles.loginTip}>点击获取访问权限</Text>
- </TouchableOpacity>
- )}
- </View>
- </View>
- {/* Tech Decoration */}
- <View style={styles.techDecoTR} />
- <View style={styles.techDecoBL} />
- </View>
- {/* Stats Grid */}
- <View style={styles.statsContainer}>
- <StatCard
- num={showNumber("couponCount")}
- label="优惠券"
- onPress={() => handleMenuPress("/coupon")}
- />
- <StatCard
- num={showNumber("inventoryCount")}
- label="仓库"
- onPress={() => handleMenuPress("/store")}
- />
- <StatCard
- num={showNumber("magicBalance")}
- label="果实"
- onPress={() => handleMenuPress("/magic")}
- />
- <StatCard
- num={showNumber("treasureBoxCount")}
- label="宝箱"
- onPress={() => handleMenuPress("/boxInBox/boxList")}
- />
- </View>
- {/* Shortcuts */}
- <View style={styles.shortcutsContainer}>
- <View style={styles.shortcutsHeader}>
- <Text style={styles.shortcutsTitle}>QUICK ACCESS</Text>
- </View>
- <View style={styles.shortcutsGrid}>
- {inviteShow && userInfo && (
- <TouchableOpacity
- style={styles.shortcutItem}
- onPress={() => Alert.alert("提示", "暂未开放")}
- >
- <View style={styles.shortcutIconBox}>
- <Image
- source={Images.mine.invite}
- style={styles.shortcutIcon}
- contentFit="contain"
- />
- </View>
- <Text style={styles.shortcutText}>邀新有礼</Text>
- </TouchableOpacity>
- )}
- <TouchableOpacity
- style={styles.shortcutItem}
- onPress={() => handleMenuPress("/message")}
- >
- <View style={styles.shortcutIconBox}>
- <Image
- source={Images.mine.message}
- style={styles.shortcutIcon}
- contentFit="contain"
- />
- </View>
- <Text style={styles.shortcutText}>系统消息</Text>
- </TouchableOpacity>
- <TouchableOpacity
- style={styles.shortcutItem}
- onPress={() => handleMenuPress("/orders")}
- >
- <View style={styles.shortcutIconBox}>
- <Image
- source={Images.mine.kaixinOrders}
- style={styles.shortcutIcon}
- contentFit="contain"
- />
- </View>
- <Text style={styles.shortcutText}>宝箱订单</Text>
- </TouchableOpacity>
- </View>
- </View>
- {/* Orders Entry */}
- <View style={styles.orderContainer}>
- <View style={styles.shortcutsHeader}>
- <Text style={styles.shortcutsTitle}>ORDERS</Text>
- </View>
- <View style={styles.orderGrid}>
- <TouchableOpacity
- style={styles.orderBtn}
- onPress={() => handleMenuPress("/orders/shop?active=1")}
- >
- <Text style={styles.orderBtnText}>待发货</Text>
- <View style={styles.orderBtnLine} />
- </TouchableOpacity>
- <TouchableOpacity
- style={styles.orderBtn}
- onPress={() => handleMenuPress("/orders/shop?active=4")}
- >
- <Text style={styles.orderBtnText}>已发货</Text>
- <View style={styles.orderBtnLine} />
- </TouchableOpacity>
- </View>
- </View>
- {/* Menu Section */}
- <View style={styles.menuSection}>
- <MenuCell onItemPress={handleMenuItemPress} showWallet={showWallet} showExchange={showExchange} />
- </View>
- {/* Footer Info */}
- {filingInfo && filingInfo.state !== 0 && (
- <View style={styles.filingBox}>
- <Text style={styles.filingText}>{filingInfo.data}</Text>
- </View>
- )}
- </ScrollView>
- <KefuPopup ref={kefuRef} />
- </View>
- );
- }
- const styles = StyleSheet.create({
- container: {
- flex: 1,
- backgroundColor: Colors.darkBg,
- },
- scrollView: {
- flex: 1,
- },
- header: {
- paddingHorizontal: 20,
- marginBottom: 20,
- },
- title: {
- color: "#fff",
- fontSize: 24,
- fontWeight: "bold",
- fontStyle: "italic",
- letterSpacing: 2,
- textShadowColor: Colors.neonBlue,
- textShadowRadius: 10,
- },
- subTitle: {
- color: Colors.neonBlue,
- fontSize: 12,
- letterSpacing: 4,
- },
- // User Card
- userCard: {
- marginHorizontal: 15,
- padding: 20,
- backgroundColor: "rgba(255, 255, 255, 0.05)",
- borderRadius: 12,
- borderWidth: 1,
- borderColor: Colors.neonBlue,
- position: "relative",
- marginBottom: 20,
- },
- userContent: {
- flexDirection: "row",
- alignItems: "center",
- },
- avatarContainer: {
- position: "relative",
- marginRight: 15,
- },
- avatar: {
- width: 60,
- height: 60,
- borderRadius: 30,
- borderWidth: 2,
- borderColor: "#fff",
- },
- avatarBorder: {
- position: "absolute",
- top: -4,
- left: -4,
- right: -4,
- bottom: -4,
- borderRadius: 34,
- borderWidth: 1,
- borderColor: Colors.neonPink,
- borderStyle: "dashed",
- },
- userInfo: {
- flex: 1,
- },
- nicknameRow: {
- flexDirection: "row",
- alignItems: "center",
- justifyContent: "space-between",
- marginBottom: 8,
- },
- nickname: {
- color: "#fff",
- fontSize: 18,
- fontWeight: "bold",
- },
- editBtn: {
- paddingHorizontal: 10,
- paddingVertical: 4,
- backgroundColor: Colors.neonBlue,
- borderRadius: 4,
- },
- editBtnText: {
- color: "#000",
- fontSize: 10,
- fontWeight: "bold",
- },
- idRow: {
- alignItems: "flex-start",
- },
- idItem: {
- flexDirection: "row",
- alignItems: "center",
- marginBottom: 4,
- },
- idText: {
- color: Colors.textSecondary,
- fontSize: 12,
- marginRight: 8,
- },
- copyBadge: {
- backgroundColor: "rgba(255, 255, 255, 0.1)",
- paddingHorizontal: 4,
- borderRadius: 2,
- },
- copyText: {
- color: "#fff",
- fontSize: 8,
- },
- phoneText: {
- color: Colors.textTertiary,
- fontSize: 12,
- },
- loginTip: {
- color: Colors.neonPink,
- fontSize: 14,
- textDecorationLine: "underline",
- },
- techDecoTR: {
- position: "absolute",
- top: 0,
- right: 0,
- width: 20,
- height: 20,
- borderTopWidth: 2,
- borderRightWidth: 2,
- borderColor: Colors.neonBlue,
- },
- techDecoBL: {
- position: "absolute",
- bottom: 0,
- left: 0,
- width: 20,
- height: 20,
- borderBottomWidth: 2,
- borderLeftWidth: 2,
- borderColor: Colors.neonBlue,
- },
- // Stats
- statsContainer: {
- flexDirection: "row",
- justifyContent: "space-between",
- marginHorizontal: 15,
- marginBottom: 20,
- backgroundColor: Colors.darkCard,
- borderRadius: 8,
- padding: 15,
- borderWidth: 1,
- borderColor: "rgba(255, 255, 255, 0.1)",
- },
- dataItem: {
- alignItems: "center",
- flex: 1,
- },
- dataNum: {
- color: Colors.neonBlue,
- fontSize: 18,
- fontWeight: "bold",
- textShadowColor: Colors.neonBlue,
- textShadowRadius: 5,
- },
- dataLabel: {
- color: Colors.textSecondary,
- fontSize: 12,
- marginTop: 4,
- },
- dataLine: {
- width: 20,
- height: 2,
- backgroundColor: "rgba(255, 255, 255, 0.1)",
- marginTop: 8,
- },
- // Shortcuts
- shortcutsContainer: {
- marginHorizontal: 15,
- marginBottom: 20,
- },
- shortcutsHeader: {
- borderLeftWidth: 3,
- borderLeftColor: Colors.neonPink,
- paddingLeft: 10,
- marginBottom: 10,
- },
- shortcutsTitle: {
- color: "#fff",
- fontSize: 14,
- fontWeight: "bold",
- letterSpacing: 2,
- },
- shortcutsGrid: {
- flexDirection: "row",
- backgroundColor: Colors.darkCard,
- borderRadius: 8,
- padding: 15,
- },
- shortcutItem: {
- flex: 1,
- alignItems: "center",
- },
- shortcutIconBox: {
- width: 48,
- height: 48,
- borderRadius: 24,
- backgroundColor: "rgba(255, 255, 255, 0.05)",
- justifyContent: "center",
- alignItems: "center",
- marginBottom: 8,
- borderWidth: 1,
- borderColor: "rgba(255, 255, 255, 0.1)",
- },
- shortcutIcon: {
- width: 24,
- height: 24,
- tintColor: Colors.neonBlue, // Apply theme color
- },
- shortcutText: {
- color: Colors.textSecondary,
- fontSize: 12,
- },
- // Orders
- orderContainer: {
- marginHorizontal: 15,
- marginBottom: 20,
- },
- orderGrid: {
- flexDirection: "row",
- gap: 15,
- },
- orderBtn: {
- flex: 1,
- height: 60,
- backgroundColor: Colors.darkCard,
- borderRadius: 8,
- justifyContent: "center",
- alignItems: "center",
- borderWidth: 1,
- borderColor: "rgba(255, 255, 255, 0.1)",
- position: "relative",
- overflow: "hidden",
- },
- orderBtnText: {
- color: "#fff",
- fontSize: 14,
- fontWeight: "bold",
- letterSpacing: 2,
- },
- orderBtnLine: {
- position: "absolute",
- bottom: 0,
- left: 0,
- right: 0,
- height: 2,
- backgroundColor: Colors.neonBlue,
- },
- // Menu
- menuSection: {
- marginHorizontal: 15,
- backgroundColor: Colors.darkCard,
- borderRadius: 8,
- paddingVertical: 5,
- borderWidth: 1,
- borderColor: "rgba(255, 255, 255, 0.1)",
- },
- // Footer
- filingBox: {
- alignItems: "center",
- marginTop: 20,
- opacity: 0.5,
- },
- filingText: {
- color: Colors.textTertiary,
- fontSize: 10,
- textAlign: "center",
- },
- });
|