import { useState, useEffect, useMemo, Table, Button, Input, Select, DatePicker, message, Card, Row, Col, Tag, Space, Modal, Drawer, Descriptions, Typography, Alert, Statistic, Tooltip, SearchOutlined, FilterOutlined, ExportOutlined, DownloadOutlined, EyeOutlined, CheckCircleOutlined, CloseCircleOutlined, SyncOutlined, DollarOutlined, ArrowUpOutlined, ArrowDownOutlined, ReloadOutlined, LineChart, Line, Bar, RechartsPie, ResponsiveContainer, Legend, XAxis, YAxis, CartesianGrid, Cell, useNavigate, Option, RangePicker, Search, Title, Text, FC, } from '@/imports'; import moment from 'moment'; import { financeDataSource } from '@/services/financeDataSource'; import type { Transaction } from '@/services/financeDataSource'; const Transactions: FC = () => { const navigate = useNavigate(); const [transactions, setTransactions] = useState([]); const [loading, setLoading] = useState(false); const [selectedRows, setSelectedRows] = useState([]); const [detailDrawerVisible, setDetailDrawerVisible] = useState(false); const [currentTransaction, setCurrentTransaction] = useState(null); const [filters, setFilters] = useState({ type: '', category: '', status: '', search: '', dateRange: null as any, minAmount: null as number | null, maxAmount: null as number | null, }); const fetchTransactions = async (filterParams?: any) => { setLoading(true); try { // 转换过滤参数以匹配 financeDataSource 期望的格式 const params = { type: filterParams?.type || filters.type, startDate: filterParams?.dateRange?.[0]?.format('YYYY-MM-DD'), endDate: filterParams?.dateRange?.[1]?.format('YYYY-MM-DD'), }; const data = await financeDataSource.fetchTransactions(params); setTransactions(data); } catch (error) { message.error('Failed to load transactions'); } finally { setLoading(false); } }; useEffect(() => { fetchTransactions(); }, []); // 只在组件挂载时执行一次 const handleExport = () => { message.success('交易记录已导出'); }; const handleBatchExport = () => { if (selectedRows.length === 0) { message.warning('请先选择要导出的交易'); return; } message.success(`成功导出 ${selectedRows.length} 条交易记录`); }; const handleViewDetail = (record: Transaction) => { setCurrentTransaction(record); setDetailDrawerVisible(true); }; const handleRefresh = () => { fetchTransactions(); message.success('数据已刷新'); }; const stats = useMemo(() => { const income = transactions.filter(t => t.type === 'income').reduce((sum, t) => sum + t.amount, 0); const expense = transactions.filter(t => t.type === 'expense').reduce((sum, t) => sum + t.amount, 0); const pending = transactions.filter(t => t.status === 'pending').reduce((sum, t) => sum + t.amount, 0); return { income, expense, profit: income - expense, pending, total: transactions.length, }; }, [transactions]); const trendData = useMemo(() => { const trendData = Array.from({ length: 7 }, (_, i) => { const date = moment().subtract(i, 'days').format('YYYY-MM-DD'); const dayTransactions = transactions.filter(t => moment(t.createdAt).format('YYYY-MM-DD') === date); return { date, income: dayTransactions.filter(t => t.type === 'income').reduce((sum, t) => sum + t.amount, 0), expense: dayTransactions.filter(t => t.type === 'expense').reduce((sum, t) => sum + t.amount, 0), }; }).reverse(); return trendData; }, [transactions]); const categoryData = useMemo(() => { const categoryMap: Record = {}; transactions.filter(t => t.type === 'expense').forEach(t => { categoryMap[t.category] = (categoryMap[t.category] || 0) + t.amount; }); return Object.entries(categoryMap).map(([name, value]) => ({ name, value })); }, [transactions]); const columns = [ { title: '交易ID', dataIndex: 'transactionId', key: 'transactionId', render: (text: string) => {text}, }, { title: '金额', dataIndex: 'amount', key: 'amount', sorter: (a: Transaction, b: Transaction) => a.amount - b.amount, render: (amount: number, record: Transaction) => ( {record.type === 'income' ? '+' : '-'}${(amount || 0).toFixed(2)} ), }, { title: '类型', dataIndex: 'type', key: 'type', filters: [ { text: '收入', value: 'income' }, { text: '支出', value: 'expense' }, { text: '退款', value: 'refund' }, { text: '费用', value: 'fee' }, ], render: (type: string) => { const typeConfig = { income: { text: '收入', color: 'success' }, expense: { text: '支出', color: 'error' }, refund: { text: '退款', color: 'warning' }, fee: { text: '费用', color: 'processing' }, }; const config = typeConfig[type as keyof typeof typeConfig] || { text: type, color: 'default' }; return {config.text}; }, }, { title: '分类', dataIndex: 'category', key: 'category', filters: [ { text: '销售', value: 'Sales' }, { text: '供应商', value: 'Suppliers' }, { text: '营销', value: 'Marketing' }, { text: '物流', value: 'Shipping' }, { text: '平台费用', value: 'Platform' }, { text: '退款', value: 'Refund' }, ], }, { title: '描述', dataIndex: 'description', key: 'description', ellipsis: true, }, { title: '日期', dataIndex: 'date', key: 'date', sorter: (a: Transaction, b: Transaction) => moment(a.createdAt).unix() - moment(b.createdAt).unix(), render: (date: string) => moment(date).format('YYYY-MM-DD HH:mm'), }, { title: '状态', dataIndex: 'status', key: 'status', filters: [ { text: '已完成', value: 'completed' }, { text: '待处理', value: 'pending' }, { text: '失败', value: 'failed' }, ], render: (status: string) => { const statusConfig = { completed: { text: '已完成', color: 'success', icon: }, pending: { text: '待处理', color: 'warning', icon: }, failed: { text: '失败', color: 'error', icon: }, }; const config = statusConfig[status as keyof typeof statusConfig]; return {config.text}; }, }, { title: '操作', key: 'action', render: (_: any, record: Transaction) => ( ), }, ]; return (
交易记录 查看和管理所有财务交易 } valueStyle={{ color: '#52c41a' }} suffix="USD" /> } valueStyle={{ color: '#ff4d4f' }} suffix="USD" /> } valueStyle={{ color: stats.profit >= 0 ? '#52c41a' : '#ff4d4f' }} suffix="USD" /> } valueStyle={{ color: '#faad14' }} suffix="USD" /> `${name}: ${((percent || 0) * 100).toFixed(0)}%`} > {categoryData.map((entry, index) => ( ))} {selectedRows.length > 0 && ( } style={{ marginBottom: 16 }} /> )}
setFilters({ ...filters, search: value })} allowClear /> setFilters({ ...filters, dateRange: dates })} />
r.id), onChange: (selectedRowKeys: React.Key[], selectedRows: Transaction[]) => { setSelectedRows(selectedRows); }, }} pagination={{ pageSize: 20, showSizeChanger: true, showQuickJumper: true, showTotal: (total) => `共 ${total} 条`, pageSizeOptions: ['10', '20', '50', '100'], }} scroll={{ x: 1200 }} /> setDetailDrawerVisible(false)} open={detailDrawerVisible} width={600} > {currentTransaction && ( {currentTransaction.id} {currentTransaction.type === 'income' ? '+' : '-'}${currentTransaction.amount.toFixed(2)} {currentTransaction.type === 'income' ? '收入' : '支出'} {currentTransaction.category} {currentTransaction.description} {moment(currentTransaction.createdAt).format('YYYY-MM-DD HH:mm:ss')} {currentTransaction.status === 'completed' ? '已完成' : currentTransaction.status === 'pending' ? '待处理' : '失败'} )} ); }; export default Transactions;