- 新增App主组件,实现聊天、账本、统计三大功能模块切换 - 支持语音及文本输入,自动解析记账信息并生成交易记录 - 交易记录支持编辑、删除、提醒等操作,数据本地持久化 - 管家性格预设和自定义设定,包含头像上传和语气调整 - 会话展示支持关联交易显示,样式区分收入与支出 - 账本页添加日期分组交易列表及饼图统计展示 - 消息列表实现渐变背景和交互动画,提升用户体验 - 支持图片上传并同步发送给AI进行解析记账 - 底部导航实现三标签切换并同步显示对应内容 - 全局事务编辑弹窗支持直接调用和删除操作 - 增加环境变量示例和.gitignore规则,完善工程配置
114 lines
4.0 KiB
TypeScript
114 lines
4.0 KiB
TypeScript
import React, { useMemo } from 'react';
|
||
import { Transaction, TransactionType, ExpenseCategory } from '../types';
|
||
import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip, Legend, BarChart, Bar, XAxis, YAxis, CartesianGrid } from 'recharts';
|
||
|
||
interface DashboardProps {
|
||
expenses: Transaction[]; // Kept prop name as expenses for compatibility but type is 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 Dashboard: React.FC<DashboardProps> = ({ expenses }) => {
|
||
const today = new Date().toISOString().split('T')[0];
|
||
|
||
// Filter only expenses for the dashboard visuals
|
||
const expenseTransactions = useMemo(() => expenses.filter(e => e.type === TransactionType.EXPENSE), [expenses]);
|
||
|
||
const todaysExpenses = useMemo(() => {
|
||
return expenseTransactions.filter(e => e.date === today);
|
||
}, [expenseTransactions, today]);
|
||
|
||
const totalToday = useMemo(() => {
|
||
return todaysExpenses.reduce((sum, e) => sum + e.amount, 0);
|
||
}, [todaysExpenses]);
|
||
|
||
const categoryData = useMemo(() => {
|
||
const map = new Map<string, number>();
|
||
todaysExpenses.forEach(e => {
|
||
map.set(e.category, (map.get(e.category) || 0) + e.amount);
|
||
});
|
||
|
||
return Array.from(map.entries()).map(([name, value], index) => ({
|
||
name,
|
||
value,
|
||
fill: COLORS[index % COLORS.length]
|
||
}));
|
||
}, [todaysExpenses]);
|
||
|
||
const weeklyData = useMemo(() => {
|
||
const data: { date: string; total: number }[] = [];
|
||
for (let i = 6; i >= 0; i--) {
|
||
const d = new Date();
|
||
d.setDate(d.getDate() - i);
|
||
const dateStr = d.toISOString().split('T')[0];
|
||
const dailySum = expenseTransactions
|
||
.filter(e => e.date === dateStr)
|
||
.reduce((sum, e) => sum + e.amount, 0);
|
||
data.push({ date: dateStr.slice(5), total: dailySum });
|
||
}
|
||
return data;
|
||
}, [expenseTransactions]);
|
||
|
||
return (
|
||
<div className="flex flex-col h-full bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||
<div className="p-6 bg-gradient-to-r from-indigo-500 to-purple-600 text-white">
|
||
<h2 className="text-xl font-bold mb-1">今日消费统计</h2>
|
||
<div className="flex items-end gap-2">
|
||
<span className="text-4xl font-extrabold tracking-tight">¥{totalToday.toFixed(2)}</span>
|
||
<span className="text-indigo-100 mb-1 text-sm">{today}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="flex-1 overflow-y-auto p-4 space-y-6 no-scrollbar">
|
||
<div className="bg-gray-50 p-4 rounded-xl">
|
||
<h3 className="text-gray-700 font-semibold mb-4 text-sm uppercase tracking-wider">今日分类占比</h3>
|
||
{categoryData.length > 0 ? (
|
||
<div className="h-64 w-full">
|
||
<ResponsiveContainer width="100%" height="100%">
|
||
<PieChart>
|
||
<Pie
|
||
data={categoryData}
|
||
cx="50%"
|
||
cy="50%"
|
||
innerRadius={60}
|
||
outerRadius={80}
|
||
paddingAngle={5}
|
||
dataKey="value"
|
||
>
|
||
{categoryData.map((entry, index) => (
|
||
<Cell key={`cell-${index}`} fill={entry.fill} />
|
||
))}
|
||
</Pie>
|
||
<Tooltip formatter={(value: number) => `¥${value.toFixed(2)}`} />
|
||
<Legend />
|
||
</PieChart>
|
||
</ResponsiveContainer>
|
||
</div>
|
||
) : (
|
||
<div className="h-32 flex items-center justify-center text-gray-400 text-sm">
|
||
今天还没有消费哦,小王表现不错!
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default Dashboard; |