import React, { useMemo, useState, useEffect } from 'react'; import { Transaction, TransactionType, ExpenseCategory } from '../types'; import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Cell, LineChart, Line, CartesianGrid, ReferenceLine } from 'recharts'; interface StatisticsPageProps { transactions: Transaction[]; } const COLORS = [ '#6366f1', // Indigo '#ec4899', // Pink '#10b981', // Emerald '#f59e0b', // Amber '#8b5cf6', // Violet '#ef4444', // Red '#3b82f6', // Blue '#14b8a6', // Teal '#f97316', // Orange '#84cc16', // Lime '#06b6d4', // Cyan '#d946ef', // Fuchsia '#64748b', // Slate '#a855f7', // Purple '#fbbf24' // Yellow ]; const StatisticsPage: React.FC = ({ transactions }) => { const [selectedMonth, setSelectedMonth] = useState(new Date().toISOString().slice(0, 7)); const [trendCategory, setTrendCategory] = useState(ExpenseCategory.FOOD); const monthlyTransactions = useMemo(() => { return transactions.filter(t => t.date.startsWith(selectedMonth)); }, [transactions, selectedMonth]); const totalIncome = useMemo(() => monthlyTransactions.filter(t => t.type === TransactionType.INCOME).reduce((sum, t) => sum + t.amount, 0), [monthlyTransactions]); const totalExpense = useMemo(() => monthlyTransactions.filter(t => t.type === TransactionType.EXPENSE).reduce((sum, t) => sum + t.amount, 0), [monthlyTransactions]); const monthlyBalance = useMemo(() => totalIncome - totalExpense, [totalIncome, totalExpense]); // Extract month number for display const monthLabel = useMemo(() => { const month = parseInt(selectedMonth.split('-')[1]); return `${month}月`; }, [selectedMonth]); const barData = [ { name: '收入', amount: totalIncome, fill: '#10b981' }, { name: '支出', amount: totalExpense, fill: '#ec4899' }, { name: '结余', amount: monthlyBalance, fill: '#6366f1' } ]; // Category Stats (Used for Ranking and Detail) const categoryStats = useMemo(() => { const map = new Map(); monthlyTransactions .filter(t => t.type === TransactionType.EXPENSE) .forEach(t => { const existing = map.get(t.category) || { count: 0, amount: 0 }; existing.count += 1; existing.amount += t.amount; map.set(t.category, existing); }); return Array.from(map.entries()) .map(([name, stat], index) => ({ name, ...stat, color: COLORS[index % COLORS.length] })) .sort((a, b) => b.amount - a.amount); }, [monthlyTransactions]); // Set default trend category to top expense of current month if available useEffect(() => { if (categoryStats.length > 0) { setTrendCategory(categoryStats[0].name); } }, [categoryStats.length > 0 ? categoryStats[0].name : null]); // Top 5 Ranking (Now based on Categories) const rankingData = useMemo(() => { return categoryStats.slice(0, 5); }, [categoryStats]); // Calculate 6-month trend for the selected category const trendData = useMemo(() => { const data = []; const today = new Date(); // Look back 6 months for (let i = 5; i >= 0; i--) { const d = new Date(today.getFullYear(), today.getMonth() - i, 1); const monthStr = d.toISOString().slice(0, 7); // YYYY-MM const displayMonth = `${d.getMonth() + 1}月`; const total = transactions .filter(t => t.type === TransactionType.EXPENSE && t.category === trendCategory && t.date.startsWith(monthStr) ) .reduce((sum, t) => sum + t.amount, 0); data.push({ name: displayMonth, amount: total, fullDate: monthStr }); } return data; }, [transactions, trendCategory]); return (
{/* Header */}

收支统计

setSelectedMonth(e.target.value)} className="bg-gray-100 rounded-lg px-3 py-1 text-xs font-bold text-gray-500 outline-none border-none shadow-sm focus:ring-1 focus:ring-indigo-300 transition-all" />
{/* Monthly Overview Card */}

{monthLabel}收支总览

总收入
+¥{totalIncome.toFixed(0)}
总支出
-¥{totalExpense.toFixed(0)}
本月结余
= 0 ? 'text-indigo-600' : 'text-orange-500'}`}> {monthlyBalance < 0 ? '-' : ''}¥{Math.abs(monthlyBalance).toFixed(0)}
`¥${val.toFixed(2)}`} cursor={{fill: 'transparent'}} contentStyle={{borderRadius: '8px'}} /> {barData.map((entry, index) => ( ))}
{/* Top Expenses Ranking (By Category) */}

{monthLabel}分类消费排行榜 (Top 5)

{rankingData.length > 0 ? rankingData.map((cat, idx) => (
{idx + 1}
{cat.name}
¥{cat.amount.toFixed(0)} {cat.count}笔
)) : (
暂无支出
)}
{/* Category Breakdown Details */}

{monthLabel}分类统计详情

{categoryStats.length > 0 ? categoryStats.map((cat) => (
{cat.name} {cat.count}笔
¥{cat.amount.toFixed(0)}
)) : (
暂无数据
)}
{/* Trend Analysis Chart */}

分类趋势 (近6个月)

); }; export default StatisticsPage;