소스 검색

钱包模块

zbb 3 달 전
부모
커밋
584200c8b2
6개의 변경된 파일768개의 추가작업 그리고 0개의 파일을 삭제
  1. 4 0
      app/cardInfo/index.tsx
  2. 296 0
      app/wallet/index.tsx
  3. 180 0
      app/wallet/recharge.tsx
  4. 4 0
      app/wallet/recharge_record.tsx
  5. 280 0
      app/wallet/withdraw.tsx
  6. 4 0
      app/wallet/withdraw_record.tsx

+ 4 - 0
app/cardInfo/index.tsx

@@ -0,0 +1,4 @@
+import { Text, View } from 'react-native';
+export default function CardInfo() {
+  return <View><Text>银行卡信息 (Pending)</Text></View>;
+}

+ 296 - 0
app/wallet/index.tsx

@@ -0,0 +1,296 @@
+import { Stack, useRouter } from 'expo-router';
+import React, { useEffect, useState } from 'react';
+import { FlatList, ImageBackground, RefreshControl, SafeAreaView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
+import services from '../../services/api';
+
+const TABS = [
+  { title: '全部', value: '' },
+  { title: '收入', value: 'IN' },
+  { title: '支出', value: 'OUT' },
+];
+
+// Define types
+interface TransactionItem {
+  itemId: string;
+  itemDesc: string;
+  createTime: string;
+  type: string;
+  money: number;
+}
+
+export default function WalletScreen() {
+  const router = useRouter();
+  const [balance, setBalance] = useState('0.00');
+  const [activeTab, setActiveTab] = useState(TABS[0]);
+  const [transactions, setTransactions] = useState<TransactionItem[]>([]);
+  const [loading, setLoading] = useState(false);
+  const [refreshing, setRefreshing] = useState(false);
+  const [page, setPage] = useState(1);
+  const [hasMore, setHasMore] = useState(true);
+
+  const fetchWalletInfo = async () => {
+    try {
+      const res = await services.wallet.info('CASH');
+      if (res && res.balance) {
+        setBalance(res.balance);
+      }
+    } catch (error) {
+      console.error('Failed to fetch wallet info', error);
+    }
+  };
+
+  const fetchTransactions = async (pageNum = 1, isRefresh = false) => {
+    if (loading) return;
+    setLoading(true);
+    try {
+      const res = await services.wallet.bill(pageNum, 20, 'CASH', activeTab.value);
+      if (res && res.records) {
+        if (isRefresh) {
+            setTransactions(res.records);
+        } else {
+            setTransactions(prev => [...prev, ...res.records]);
+        }
+        setHasMore(res.records.length >= 20);
+        setPage(pageNum);
+      } else {
+        if (isRefresh) setTransactions([]);
+        setHasMore(false);
+      }
+    } catch (error) {
+      console.error('Failed to fetch transactions', error);
+    } finally {
+      setLoading(false);
+      setRefreshing(false);
+    }
+  };
+  useEffect(() => {
+    fetchWalletInfo();
+    fetchTransactions(1, true);
+  }, [activeTab]);
+
+  const onRefresh = () => {
+    setRefreshing(true);
+    fetchWalletInfo();
+    fetchTransactions(1, true);
+  };
+
+  const loadMore = () => {
+    if (hasMore && !loading) {
+      fetchTransactions(page + 1);
+    }
+  };
+  const renderItem = ({ item }: { item: TransactionItem }) => (
+    <View style={styles.cell}>
+      <View>
+        <Text style={styles.itemDesc}>{item.itemDesc}</Text>
+        <Text style={styles.itemTime}>{item.createTime}</Text>
+      </View>
+      <Text style={[styles.itemAmount, item.type === 'IN' ? styles.amountIn : styles.amountOut]}>
+        {item.type === 'IN' ? '+' : '-'}{item.money}
+      </Text>
+    </View>
+  );
+
+  return (
+    <ImageBackground 
+      source={{ uri: 'https://cdn.acetoys.cn/kai_xin_ma_te/supermart/mine/kaixinMineBg.png' }} 
+      style={styles.container}
+      resizeMode="cover"
+    >
+      <Stack.Screen options={{ 
+        title: '钱包',
+        headerTitleStyle: { color: '#fff' },
+        headerStyle: { backgroundColor: 'transparent' }, 
+        headerTransparent: true,
+        headerTintColor: '#fff', 
+      }} />
+
+      <SafeAreaView style={{ flex: 1, marginTop: 100 }}>
+      {/* Info Card */}
+      <View style={styles.infoCard}>
+        <View style={styles.balanceContainer}>
+            <Text style={styles.balanceAmount}>{balance}</Text>
+            <Text style={styles.balanceLabel}>余额</Text>
+        </View>
+        
+        <View style={styles.actionButtons}>
+          <TouchableOpacity 
+            style={styles.btnWithdraw} 
+            onPress={() => router.push('/wallet/withdraw')}
+          >
+            <Text style={styles.btnWithdrawText}>我要提现</Text>
+          </TouchableOpacity>
+          
+          <TouchableOpacity 
+            style={styles.btnRecharge} 
+            onPress={() => router.push('/wallet/recharge')}
+          >
+            <Text style={styles.btnRechargeText}>充值</Text>
+          </TouchableOpacity>
+        </View>
+      </View>
+
+      {/* Tabs */}
+      <View style={styles.tabsContainer}>
+        {TABS.map((tab, index) => (
+          <TouchableOpacity 
+            key={index} 
+            style={styles.tabItem}
+            onPress={() => setActiveTab(tab)}
+          >
+            <Text style={[styles.tabText, activeTab.value === tab.value && styles.activeTabText]}>
+              {tab.title}
+            </Text>
+          </TouchableOpacity>
+        ))}
+      </View>
+
+      {/* Transaction List */}
+      <View style={styles.listContainer}>
+        <FlatList
+            data={transactions}
+            renderItem={renderItem}
+            keyExtractor={(item) => item.itemId || Math.random().toString()}
+            contentContainerStyle={styles.listContent}
+            refreshControl={
+            <RefreshControl refreshing={refreshing} onRefresh={onRefresh} tintColor="#333" />
+            }
+            onEndReached={loadMore}
+            onEndReachedThreshold={0.5}
+            // ListFooterComponent={loading && !refreshing ? <ActivityIndicator style={{marginTop: 10}} /> : null}
+            ListEmptyComponent={!loading ? <View style={styles.emptyContainer}><Text style={styles.emptyText}>暂无记录</Text></View> : null}
+        />
+      </View>
+      </SafeAreaView>
+    </ImageBackground>
+  );
+}
+
+const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+    backgroundColor: '#f5f5f5',
+  },
+  infoCard: {
+    marginHorizontal: 14,
+    marginTop: 12,
+    marginBottom: 15,
+    borderRadius: 10,
+    height: 139,
+    backgroundColor: '#3d3f41',
+    alignItems: 'center',
+    justifyContent: 'center',
+  },
+  balanceContainer: {
+    alignItems: 'center',
+    marginTop: 10,
+  },
+  balanceAmount: {
+    fontSize: 30,
+    fontWeight: 'bold',
+    color: '#fff',
+  },
+  balanceLabel: {
+    fontSize: 12,
+    color: 'rgba(255,255,255,0.8)',
+    marginTop: 2,
+    marginBottom: 15,
+  },
+  actionButtons: {
+    flexDirection: 'row',
+    justifyContent: 'space-around',
+    width: '75%',
+  },
+  btnWithdraw: {
+    width: 90,
+    height: 32,
+    borderRadius: 16,
+    borderWidth: 1,
+    borderColor: '#fff',
+    justifyContent: 'center',
+    alignItems: 'center',
+  },
+  btnWithdrawText: {
+    color: '#fff',
+    fontSize: 14,
+  },
+  btnRecharge: {
+    width: 90,
+    height: 32,
+    borderRadius: 16,
+    backgroundColor: '#fff',
+    justifyContent: 'center',
+    alignItems: 'center',
+  },
+  btnRechargeText: {
+    color: '#3d3f41',
+    fontSize: 14,
+  },
+  tabsContainer: {
+    flexDirection: 'row',
+    justifyContent: 'flex-start',
+    paddingHorizontal: 15,
+    marginBottom: 10,
+  },
+  tabItem: {
+    width: '32%',
+    paddingVertical: 10,
+    alignItems: 'center',
+    justifyContent: 'center',
+  },
+  tabText: {
+    color: '#3d3f41',
+    fontSize: 14,
+  },
+  activeTabText: {
+    fontWeight: 'bold',
+    fontSize: 15,
+    // Add underline or color change if needed, logic in Uniapp was mostly bold
+  },
+  listContainer: {
+    flex: 1,
+    marginHorizontal: 14,
+    marginBottom: 14,
+    borderRadius: 10,
+    backgroundColor: '#fff',
+    overflow: 'hidden',
+  },
+  listContent: {
+    paddingBottom: 20,
+  },
+  cell: {
+    flexDirection: 'row',
+    justifyContent: 'space-between',
+    alignItems: 'center',
+    paddingVertical: 18,
+    paddingHorizontal: 15,
+    borderBottomWidth: 1,
+    borderBottomColor: '#eee',
+  },
+  itemDesc: {
+    fontSize: 14,
+    fontWeight: 'bold',
+    color: '#666666',
+  },
+  itemTime: {
+    fontSize: 10,
+    color: '#999',
+    marginTop: 4,
+  },
+  itemAmount: {
+    fontSize: 16,
+  },
+  amountIn: {
+    color: '#ff9600', // Uniapp color-theme
+  },
+  amountOut: {
+    color: '#666666', // Uniapp color-1
+  },
+  emptyContainer: {
+    padding: 60,
+    alignItems: 'center',
+  },
+  emptyText: {
+    color: '#999',
+  },
+});

+ 180 - 0
app/wallet/recharge.tsx

@@ -0,0 +1,180 @@
+import { Stack, useRouter } from 'expo-router';
+import React, { useState } from 'react';
+import { ActivityIndicator, Alert, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
+import services from '../../services/api';
+
+const MAX_AMOUNT = 100000;
+
+export default function RechargeScreen() {
+    const router = useRouter();
+    const [money, setMoney] = useState('');
+    const [loading, setLoading] = useState(false);
+
+    const validateInput = (text: string) => {
+        let value = text.replace(/[^\d.]/g, '')
+            .replace(/^\./g, '')
+            .replace(/\.{2,}/g, '.');
+        
+        value = value.replace(/^(-)*(\d+)\.(\d\d).*$/, '$1$2.$3');
+
+        if (parseFloat(value) > MAX_AMOUNT) {
+            Alert.alert('提示', `最大充值金额为${MAX_AMOUNT}元`);
+            value = MAX_AMOUNT.toString();
+        }
+        setMoney(value);
+    };
+
+    const handleRecharge = async () => {
+        const amount = parseFloat(money);
+        if (!amount || amount <= 0) {
+            Alert.alert('提示', '请输入有效的充值金额');
+            return;
+        }
+
+        setLoading(true);
+        try {
+            // Uniapp logic: generatePaymentLink -> tradeNo
+            const res = await services.wallet.generatePaymentLink(amount, 'ALIPAY_H5', 'CASH');
+            
+            if (res && res.data && res.data.tradeNo) {
+                 const tradeNo = res.data.tradeNo;
+                 Alert.alert(
+                    '提示', 
+                    '已生成充值订单,请完成支付',
+                    [
+                        { 
+                            text: '已支付', 
+                            onPress: async () => {
+                                const checkRes = await services.wallet.checkPaymentStatus({ tradeNo: tradeNo }); 
+                                if (checkRes && checkRes.code === 0 && checkRes.data.paySuccess) {
+                                    Alert.alert('提示', '支付成功');
+                                    router.replace('/wallet/recharge_record');
+                                } else {
+                                    Alert.alert('提示', checkRes.msg || '支付未完成或查询失败');
+                                }
+                            } 
+                        },
+                        { text: '稍后支付' }
+                    ]
+                 );
+            } else {
+                 Alert.alert('失败', '生成充值订单失败');
+            }
+
+        } catch (error) {
+            console.error('Recharge failed', error);
+            Alert.alert('错误', '充值失败,请重试');
+        } finally {
+            setLoading(false);
+        }
+    };
+
+    return (
+        <View style={styles.container}>
+            <Stack.Screen options={{ title: '充值', headerStyle: { backgroundColor: '#fff' }, headerShadowVisible: false }} />
+            
+            <View style={styles.content}>
+                <View style={styles.inputWrapper}>
+                    <Text style={styles.label}>充值金额:</Text>
+                    <TextInput
+                        style={styles.input}
+                        value={money}
+                        onChangeText={validateInput}
+                        placeholder="请输入金额"
+                        keyboardType="decimal-pad"
+                    />
+                </View>
+
+                <Text style={styles.tip}>充值金额可以用于购买手办,奖池</Text>
+                <Text style={styles.tipSub}>
+                    充值金额不可提现,<Text style={styles.highlight}>线下充值额外返10%</Text>
+                </Text>
+
+                <TouchableOpacity 
+                    style={[styles.btn, loading && styles.disabledBtn]} 
+                    onPress={handleRecharge}
+                    disabled={loading}
+                >
+                     {loading ? <ActivityIndicator color="#fff" /> : <Text style={styles.btnText}>充值</Text>}
+                </TouchableOpacity>
+
+                <TouchableOpacity style={styles.recordLink} onPress={() => router.push('/wallet/recharge_record')}>
+                    <Text style={styles.recordLinkText}>充值记录 {'>'}{'>'}</Text>
+                </TouchableOpacity>
+            </View>
+        </View>
+    );
+}
+
+const styles = StyleSheet.create({
+    container: {
+        flex: 1,
+        backgroundColor: '#fff',
+    },
+    content: {
+        paddingHorizontal: 24,
+        paddingTop: 32,
+    },
+    inputWrapper: {
+        flexDirection: 'row',
+        alignItems: 'center',
+        borderWidth: 1,
+        borderColor: '#ddd',
+        borderRadius: 8,
+        paddingHorizontal: 16,
+        height: 52, // 104rpx
+        marginTop: 15,
+    },
+    label: {
+        fontSize: 16, // font5
+        color: '#333',
+        marginRight: 10,
+    },
+    input: {
+        flex: 1,
+        fontSize: 16, // font5
+        height: '100%',
+    },
+    tip: {
+        textAlign: 'center',
+        color: '#666', // color-2
+        fontSize: 14,
+        marginTop: 36,
+    },
+    tipSub: {
+        textAlign: 'center',
+        color: '#666', // color-2
+        fontSize: 14,
+        marginTop: 5,
+        marginBottom: 20,
+    },
+    highlight: {
+        color: '#07C160',
+        textDecorationLine: 'underline',
+    },
+    btn: {
+        backgroundColor: '#0081ff', // bg-blue
+        height: 44,
+        borderRadius: 4,
+        justifyContent: 'center',
+        alignItems: 'center',
+        width: '70%',
+        alignSelf: 'center',
+    },
+    disabledBtn: {
+        opacity: 0.7,
+    },
+    btnText: {
+        color: '#fff',
+        fontSize: 14,
+        fontWeight: 'bold',
+    },
+    recordLink: {
+        marginTop: 20,
+        alignItems: 'center',
+    },
+    recordLinkText: {
+        color: '#8b3dff', // color-theme
+        fontSize: 14,
+    },
+});

+ 4 - 0
app/wallet/recharge_record.tsx

@@ -0,0 +1,4 @@
+import { Text, View } from 'react-native';
+export default function RechargeRecord() {
+  return <View><Text>充值记录 (Pending)</Text></View>;
+}

+ 280 - 0
app/wallet/withdraw.tsx

@@ -0,0 +1,280 @@
+import { Ionicons } from '@expo/vector-icons';
+import { Stack, useLocalSearchParams, useRouter } from 'expo-router';
+import React, { useEffect, useState } from 'react';
+import { ActivityIndicator, Alert, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
+import services from '../../services/api';
+
+export default function WithdrawScreen() {
+    const router = useRouter();
+    const params = useLocalSearchParams();
+    const [balance, setBalance] = useState('0.00');
+    const [money, setMoney] = useState('');
+    const [bankInfo, setBankInfo] = useState<any>(null);
+    const [rate, setRate] = useState(0);
+    const [agree, setAgree] = useState(false);
+    const [loading, setLoading] = useState(false);
+    
+    // Uniapp had type='ALIPAY' default
+    const type = (params.type as string) || 'ALIPAY';
+
+    useEffect(() => {
+        fetchData();
+        fetchRate();
+        fetchWithdrawInfo();
+    }, []);
+
+    const fetchData = async () => {
+        try {
+            const res = await services.wallet.withdrawPre(type, 'MAGIC_PROMOTION');
+            if (res && res.avaliableWithdraw) {
+                setBalance(res.avaliableWithdraw.amount);
+            }
+        } catch (error) {
+            console.error('Fetch withdraw pre failed', error);
+        }
+    };
+
+    const fetchRate = async () => {
+        try {
+            await services.user.getParamConfig('wallet_withdraw_rate').then((res: any) => {
+                 setRate(res.data ? Number(res.data) : 0);
+            });
+        } catch (error) {
+            console.error('Fetch rate failed', error);
+        }
+    };
+
+    const fetchWithdrawInfo = async () => {
+        try {
+            const res = await services.wallet.getWithdraw();
+            setBankInfo(res);
+        } catch (error) {
+            console.error('Fetch bank info failed', error);
+        }
+    };
+
+    const handleWithdraw = async () => {
+        if (!agree) {
+            Alert.alert('提示', '请您先阅读并同意提现协议');
+            return;
+        }
+        if (!bankInfo || !bankInfo.bankNum) {
+            Alert.alert('提示', '请新增银行卡信息');
+            return;
+        }
+        const amount = parseFloat(money);
+        if (!money || isNaN(amount) || amount <= 0 || amount > parseFloat(balance)) {
+             Alert.alert('提示', '请输入正确的金额');
+             return;
+        }
+
+        setLoading(true);
+        try {
+            const success = await services.wallet.withdraw({
+                money,
+                ...bankInfo,
+                walletType: 'MAGIC_PROMOTION',
+                accountType: '3'
+            });
+            if (success) {
+                Alert.alert('成功', '提现申请已提交', [
+                    { text: '确定', onPress: () => router.push('/wallet/withdraw_record') }
+                ]);
+                setMoney('');
+            }
+        } catch (error) {
+            console.error('Withdraw failed', error);
+        } finally {
+            setLoading(false);
+        }
+    };
+
+    const realMoney = money ? (parseFloat(money) * (1 - rate)).toFixed(2) : '0.00';
+
+    return (
+        <ScrollView style={styles.container}>
+            <Stack.Screen options={{ title: '提现', headerStyle: { backgroundColor: '#fff' }, headerShadowVisible: false }} />
+            
+            <View style={styles.groupContainer}>
+                {/* Bank Card Section */}
+                <TouchableOpacity style={styles.formGroup} onPress={() => router.push('/cardInfo')}>
+                    <Text style={styles.label}>提现至</Text>
+                    <View style={styles.rightContent}>
+                        <Text style={styles.valueText}>
+                            {bankInfo && bankInfo.bankName 
+                                ? `${bankInfo.bankName}尾号(${bankInfo.bankNum.slice(-4)})` 
+                                : '暂无银行卡信息'}
+                        </Text>
+                        <Ionicons name="chevron-forward" size={16} color="#8799a3" />
+                    </View>
+                </TouchableOpacity>
+            </View>
+
+            <View style={styles.groupContainer}>
+                <View style={styles.formGroup}>
+                    <Text style={styles.label}>可提现金额:{balance}元</Text>
+                    <TouchableOpacity style={styles.ruleBtn}>
+                        <Ionicons name="help-circle" size={16} color="#5b5b5b" />
+                        <Text style={styles.ruleText}>提现规则</Text>
+                    </TouchableOpacity>
+                </View>
+                
+                <View style={styles.formGroupInput}>
+                    <Text style={styles.currencySymbol}>¥</Text>
+                    <TextInput
+                        style={styles.input}
+                        value={money}
+                        onChangeText={setMoney}
+                        keyboardType="decimal-pad"
+                        placeholder="请输入提现金额"
+                    />
+                    <TouchableOpacity onPress={() => setMoney(balance)}>
+                        <Text style={styles.withdrawAll}>全部提现</Text>
+                    </TouchableOpacity>
+                </View>
+
+                <View style={[styles.formGroup, { backgroundColor: '#f8f8f8' }]}>
+                    <Text style={styles.label}>税率:</Text>
+                    <Text style={styles.valueText}>{(rate * 100).toFixed(0)}%</Text>
+                </View>
+                <View style={[styles.formGroup, { backgroundColor: '#f8f8f8' }]}>
+                    <Text style={styles.label}>实际到账金额:</Text>
+                    <Text style={styles.valueText}>{realMoney}</Text>
+                </View>
+            </View>
+
+            <TouchableOpacity style={styles.recordLink} onPress={() => router.push('/wallet/withdraw_record')}>
+                <Text style={styles.recordLinkText}>提现记录</Text>
+            </TouchableOpacity>
+
+            <TouchableOpacity style={styles.agreement} onPress={() => setAgree(!agree)}>
+                <Ionicons 
+                    name={agree ? "radio-button-on" : "radio-button-off"} 
+                    size={20} 
+                    color={agree ? "#8b3dff" : "#8799a3"} 
+                />
+                <Text style={styles.agreementText}>
+                    我已阅读并同意 <Text style={styles.linkText}>《提现协议》</Text>
+                </Text>
+            </TouchableOpacity>
+
+            <View style={styles.footer}>
+                <TouchableOpacity 
+                    style={[styles.confirmBtn, loading && styles.disabledBtn]} 
+                    onPress={handleWithdraw}
+                    disabled={loading}
+                >
+                    {loading ? <ActivityIndicator color="#fff" /> : <Text style={styles.confirmBtnText}>确认提现</Text>}
+                </TouchableOpacity>
+            </View>
+        </ScrollView>
+    );
+}
+
+const styles = StyleSheet.create({
+    container: {
+        flex: 1,
+        backgroundColor: '#fff',
+    },
+    groupContainer: {
+        paddingHorizontal: 12,
+        paddingTop: 18,
+    },
+    formGroup: {
+        flexDirection: 'row',
+        justifyContent: 'space-between',
+        alignItems: 'center',
+        paddingVertical: 15,
+        backgroundColor: '#fff',
+        // borderBottomWidth: 1,
+        // borderBottomColor: '#eee',
+    },
+    formGroupInput: {
+        flexDirection: 'row',
+        alignItems: 'center',
+        paddingVertical: 15,
+        borderBottomWidth: 1,
+        borderBottomColor: '#eee',
+    },
+    label: {
+        fontSize: 15,
+        color: '#333',
+    },
+    rightContent: {
+        flexDirection: 'row',
+        alignItems: 'center',
+    },
+    valueText: {
+        fontSize: 15,
+        color: '#666',
+        marginRight: 5,
+    },
+    ruleBtn: {
+        flexDirection: 'row',
+        alignItems: 'center',
+    },
+    ruleText: {
+        fontSize: 14,
+        color: '#5b5b5b',
+        marginLeft: 4,
+    },
+    currencySymbol: {
+        fontSize: 24,
+        fontWeight: 'bold',
+        color: '#333',
+        width: 30,
+    },
+    input: {
+        flex: 1,
+        fontSize: 20,
+        paddingHorizontal: 10,
+    },
+    withdrawAll: {
+        color: '#ff9600',
+        fontSize: 14,
+    },
+    recordLink: {
+        alignItems: 'center',
+        marginTop: 18,
+    },
+    recordLinkText: {
+        fontSize: 12,
+        color: '#999',
+    },
+    agreement: {
+        flexDirection: 'row',
+        justifyContent: 'center',
+        alignItems: 'center',
+        marginTop: 20,
+    },
+    agreementText: {
+        fontSize: 12,
+        color: '#333',
+        marginLeft: 4,
+    },
+    linkText: {
+        color: '#8b3dff',
+    },
+    footer: {
+        paddingHorizontal: 26,
+        paddingTop: 6,
+        marginTop: 20,
+        backgroundColor: '#f6f6f6', // Optional visual separation if needed, or transparent
+        paddingBottom: 40,
+    },
+    confirmBtn: {
+        backgroundColor: '#8b3dff', // Theme color
+        height: 50,
+        borderRadius: 25,
+        justifyContent: 'center',
+        alignItems: 'center',
+    },
+    disabledBtn: {
+        opacity: 0.7,
+    },
+    confirmBtnText: {
+        color: '#fff',
+        fontSize: 16,
+        fontWeight: 'bold',
+    },
+});

+ 4 - 0
app/wallet/withdraw_record.tsx

@@ -0,0 +1,4 @@
+import { Text, View } from 'react-native';
+export default function WithdrawRecord() {
+  return <View><Text>提现记录 (Pending)</Text></View>;
+}