"use client" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Input } from "@/components/ui/input" import { Separator } from "@/components/ui/separator" import { requestWithAuth } from "@/lib/api" import { getWalletBalance, listWalletTransactions, topUpWallet, withdrawWallet, } from "@/lib/api/transactions" import { toApiError } from "@/lib/errors" import { notifyInfo, notifySuccess } from "@/lib/toast" import type { WalletTransaction } from "@/lib/types" import { useAuthStore } from "@/store/auth" import { ArrowDownLeft, ArrowUpRight, CreditCard, DollarSign, RefreshCw, Wallet, } from "lucide-react" import { useCallback, useEffect, useMemo, useState } from "react" const typeLabels: Record = { topup: "充值", payment: "支付", income: "收入", withdrawal: "提现", refund: "退款", } const typeIcons: Record = { topup: ArrowDownLeft, payment: ArrowUpRight, income: ArrowDownLeft, withdrawal: ArrowUpRight, refund: ArrowDownLeft, } export default function WalletPage() { const { currentRole } = useAuthStore() const isConsumer = currentRole === "consumer" const [balance, setBalance] = useState(null) const [transactions, setTransactions] = useState([]) const [isLoading, setIsLoading] = useState(false) const [isMutating, setIsMutating] = useState(false) const [loadError, setLoadError] = useState(null) const [selectedAmount, setSelectedAmount] = useState(null) const [customAmount, setCustomAmount] = useState("") const [lastRefreshedAt, setLastRefreshedAt] = useState(null) const filteredTransactions = useMemo(() => { return transactions.filter((tx) => { if (isConsumer) { return ["topup", "payment", "refund"].includes(tx.type) } return ["income", "withdrawal"].includes(tx.type) }) }, [isConsumer, transactions]) const incomeSummary = useMemo(() => { const income = transactions .filter((tx) => tx.type === "income") .reduce((total, tx) => total + Number(tx.amount), 0) const withdrawn = transactions .filter((tx) => tx.type === "withdrawal") .reduce((total, tx) => total + Number(tx.amount), 0) return { income, available: balance ?? 0, withdrawn, } }, [balance, transactions]) const loadWalletData = useCallback( async (options?: { showToast?: boolean; silent?: boolean }) => { if (!options?.silent) { setIsLoading(true) setLoadError(null) } try { const res = await requestWithAuth(async () => { const [b, items] = await Promise.all([ getWalletBalance(), listWalletTransactions({ offset: 0, limit: 1000 }), ]) return { balance: b, transactions: items } }) if (!res) { setLoadError("请先登录") return } setBalance(res.balance) setTransactions(res.transactions) if (options?.showToast) notifySuccess("交易记录已刷新") } catch (error) { setLoadError(toApiError(error).msg) } finally { setIsLoading(false) } }, [], ) useEffect(() => { let cancelled = false void (async () => { try { const res = await requestWithAuth(async () => { const [b, items] = await Promise.all([ getWalletBalance(), listWalletTransactions({ offset: 0, limit: 100 }), ]) return { balance: b, transactions: items } }) if (cancelled) return if (!res) { setLoadError("请先登录") return } setBalance(res.balance) setTransactions(res.transactions) } catch (error) { if (cancelled) return setLoadError(toApiError(error).msg) } })() return () => { cancelled = true } }, []) const handleTopUp = async (rawAmount?: number) => { const amount = rawAmount ?? Number(customAmount) if (!Number.isFinite(amount) || amount <= 0) { notifyInfo("请输入有效金额") return } setIsMutating(true) try { const res = await requestWithAuth(async () => { await topUpWallet({ amount }) await loadWalletData({ silent: true }) return true }) if (!res) return notifySuccess("充值成功") setCustomAmount("") setSelectedAmount(null) } catch (error) { notifyInfo(toApiError(error).msg) } finally { setIsMutating(false) } } const handleWithdraw = async () => { const amount = Number(customAmount) if (!Number.isFinite(amount) || amount <= 0) { notifyInfo("请输入有效金额") return } setIsMutating(true) try { const res = await requestWithAuth(async () => { await withdrawWallet({ amount }) await loadWalletData({ silent: true }) return true }) if (!res) return notifySuccess("提现成功") setCustomAmount("") } catch (error) { notifyInfo(toApiError(error).msg) } finally { setIsMutating(false) } } return (

钱包

{isConsumer ? "账户余额" : "收入余额"}

{balance === null ? ( -- ) : ( <>¥{balance.toFixed(2)} )}

{loadError &&

{loadError}

}
{isConsumer ? ( ) : ( )}
{isConsumer ? ( 快捷充值
{[50, 100, 200, 500, 1000, 2000].map((amount) => ( ))}
{ setCustomAmount(event.target.value) setSelectedAmount(null) }} />
) : ( 收入概览

累计收入

¥{incomeSummary.income.toFixed(2)}

可提现

¥{incomeSummary.available.toFixed(2)}

已提现

¥{incomeSummary.withdrawn.toFixed(2)}

setCustomAmount(event.target.value)} />
)} 交易记录 {lastRefreshedAt && (

最近刷新:{lastRefreshedAt}

)} {isLoading ? (
加载中...
) : filteredTransactions.length > 0 ? ( filteredTransactions.map((tx) => { const Icon = typeIcons[tx.type] const isIncome = tx.type === "topup" || tx.type === "income" || tx.type === "refund" return (
{Icon ? : }

{tx.description}

{new Date(tx.createdAt).toLocaleString("zh-CN")}

{isIncome ? "+" : ""}¥{Math.abs(Number(tx.amount)).toFixed(2)}

{typeLabels[tx.type]}
) }) ) : (
暂无交易记录
)}
) }