import React, { useState, useCallback, useRef } from 'react'; import { View, Text } from '@tarojs/components'; import Taro, { useDidShow, useReachBottom, usePullDownRefresh } from '@tarojs/taro'; import { listMyTransactions } from '../../../services/points'; import type { PointsTransaction } from '../../../services/points'; import { usePointsStore } from '../../../stores/points'; import EmptyState from '../../../components/EmptyState'; import Loading from '../../../components/Loading'; import './index.scss'; const TYPE_TABS = [ { key: '', label: '全部' }, { key: 'earn', label: '收入' }, { key: 'spend', label: '支出' }, ]; export default function PointsDetail() { const { account, refresh: refreshPoints } = usePointsStore(); const [transactions, setTransactions] = useState([]); const [activeTab, setActiveTab] = useState(''); const [page, setPage] = useState(1); const [total, setTotal] = useState(0); const [loading, setLoading] = useState(false); const loadingRef = useRef(false); const fetchTransactions = useCallback( async (pageNum: number, type: string, isRefresh = false) => { if (loadingRef.current) return; loadingRef.current = true; setLoading(true); try { const res = await listMyTransactions({ page: pageNum, page_size: 10, }); let list = res.data || []; if (type) { list = list.filter((t) => t.type === type); } if (isRefresh) { setTransactions(list); } else { setTransactions((prev) => [...prev, ...list]); } setTotal(res.total); setPage(pageNum); } catch { Taro.showToast({ title: '加载失败', icon: 'none' }); } finally { loadingRef.current = false; setLoading(false); } }, [], ); const loadAll = useCallback( async (type?: string) => { const t = type !== undefined ? type : activeTab; await Promise.all([refreshPoints(), fetchTransactions(1, t, true)]); }, [refreshPoints, fetchTransactions, activeTab], ); useDidShow(() => { Taro.setNavigationBarTitle({ title: '积分明细' }); loadAll(); }); usePullDownRefresh(() => { loadAll().finally(() => { Taro.stopPullDownRefresh(); }); }); useReachBottom(() => { if (!loading && transactions.length < total) { fetchTransactions(page + 1, activeTab); } }); const handleTabChange = (key: string) => { setActiveTab(key); fetchTransactions(1, key, true); }; const getTypeLabel = (type: string) => { if (type === 'earn') return '收'; if (type === 'spend') return '支'; return '过'; }; const getTypeClass = (type: string) => { if (type === 'earn') return 'earn'; if (type === 'spend') return 'spend'; return 'expired'; }; const formatAmount = (tx: PointsTransaction) => { const amt = tx.amount; if (tx.type === 'earn') return `+${amt.toLocaleString()}`; if (tx.type === 'spend') return `-${amt.toLocaleString()}`; return `-${amt.toLocaleString()}`; }; const formatDate = (dateStr: string) => { if (!dateStr) return ''; const d = new Date(dateStr); return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`; }; const balance = account?.balance ?? 0; return ( {/* 余额卡片 */} 当前积分 {balance.toLocaleString()} {(account?.total_earned ?? 0).toLocaleString()} 累计获得 {(account?.total_spent ?? 0).toLocaleString()} 累计消费 {(account?.total_expired ?? 0).toLocaleString()} 已过期 {/* 类型筛选标签 */} {TYPE_TABS.map((tab) => ( handleTabChange(tab.key)} > {tab.label} ))} {/* 交易列表 */} {transactions.length === 0 && !loading ? ( ) : ( {transactions.map((tx) => { return ( {getTypeLabel(tx.type)} {tx.description || (tx.type === 'earn' ? '积分收入' : tx.type === 'spend' ? '积分消费' : '积分过期')} {formatDate(tx.created_at)} {formatAmount(tx)} 余额 {tx.balance_after.toLocaleString()} ); })} {loading && } {!loading && transactions.length >= total && total > 0 && ( )} )} ); }