feat: 在首页新增每日洞察卡,集成AI服务提供个性化财务分析。

This commit is contained in:
2026-01-29 00:11:14 +08:00
parent f116998226
commit c80f64346e
4 changed files with 213 additions and 17 deletions

View File

@@ -13,6 +13,14 @@ interface DailyInsightCardProps {
maxTransaction?: { note?: string; amount: number };
lastWeekSpend?: number;
streakDays?: number;
// 新增字段
budgetRemaining?: number;
daysRemaining?: number;
weeklyTotal?: number;
avgDailySpend?: number;
top3Categories?: { name: string; amount: number }[];
todayTransactionCount?: number;
last7DaysSpend?: number[]; // 最近7天每日支出
}
export const DailyInsightCard: React.FC<DailyInsightCardProps> = ({
@@ -23,9 +31,16 @@ export const DailyInsightCard: React.FC<DailyInsightCardProps> = ({
topCategory,
maxTransaction,
lastWeekSpend,
streakDays
streakDays,
budgetRemaining,
daysRemaining,
weeklyTotal,
avgDailySpend,
top3Categories,
todayTransactionCount,
last7DaysSpend,
}) => {
const [aiData, setAiData] = useState<{ spending: string; budget: string } | null>(null);
const [aiData, setAiData] = useState<{ spending: string; budget: string; emoji?: string; tip?: string } | null>(null);
const [isAiLoading, setIsAiLoading] = useState(false);
useEffect(() => {
@@ -50,7 +65,15 @@ export const DailyInsightCard: React.FC<DailyInsightCardProps> = ({
amount: maxTransaction.amount
} : undefined,
lastWeekSpend,
streakDays
streakDays,
// 新增数据
budgetRemaining,
daysRemaining: daysRemaining ?? (daysInMonth - today),
weeklyTotal,
avgDailySpend,
top3Categories,
todayTransactionCount,
last7DaysSpend,
});
setAiData(result);
} catch (e) {
@@ -62,7 +85,7 @@ export const DailyInsightCard: React.FC<DailyInsightCardProps> = ({
const timer = setTimeout(fetchAI, 500);
return () => clearTimeout(timer);
}, [todaySpend, yesterdaySpend, monthlyBudget, monthlySpent, topCategory, maxTransaction, lastWeekSpend, streakDays]);
}, [todaySpend, yesterdaySpend, monthlyBudget, monthlySpent, topCategory, maxTransaction, lastWeekSpend, streakDays, budgetRemaining, daysRemaining, weeklyTotal, avgDailySpend, top3Categories, todayTransactionCount, last7DaysSpend]);
const getSpendingInsight = (today: number, yesterday: number) => {
if (aiData) return { text: <span>{aiData.spending}</span>, type: 'ai' };
@@ -114,6 +137,7 @@ export const DailyInsightCard: React.FC<DailyInsightCardProps> = ({
<div className="daily-insight__header">
<Icon icon={aiData ? "solar:magic-stick-3-bold-duotone" : "solar:stars-minimalistic-bold-duotone"} width="20" />
<span>{aiData ? 'AI 每日简报' : '每日简报'}</span>
{aiData?.emoji && <span className="daily-insight__emoji">{aiData.emoji}</span>}
{isAiLoading && !aiData && <span className="daily-insight__loading-badge">AI ...</span>}
</div>
@@ -130,12 +154,46 @@ export const DailyInsightCard: React.FC<DailyInsightCardProps> = ({
<p className="daily-insight__text animate-fade-in">{spendingInsight.text}</p>
</div>
{/* 7-Day Trend Chart */}
{last7DaysSpend && last7DaysSpend.length > 0 && (
<div className="daily-insight__section">
<span className="daily-insight__title">7</span>
<div className="trend-chart">
{last7DaysSpend.map((amount, index) => {
const maxVal = Math.max(...last7DaysSpend, 1);
const heightPercent = Math.max((amount / maxVal) * 100, 10); // Min 10% height
const isToday = index === last7DaysSpend.length - 1;
const isMax = amount === maxVal && amount > 0;
return (
<div key={index} className="trend-bar-wrapper" title={`Day ${index - 6}: ¥${amount}`}>
<div
className={`trend-bar ${isToday ? 'trend-bar--today' : ''} ${isMax ? 'trend-bar--max' : ''}`}
style={{ height: `${heightPercent}%` }}
/>
</div>
);
})}
</div>
</div>
)}
<div className="daily-insight__divider" />
<div className="daily-insight__section">
<span className="daily-insight__title"></span>
<p className="daily-insight__text animate-fade-in">{budgetInsight.text}</p>
</div>
{aiData?.tip && (
<>
<div className="daily-insight__divider" />
<div className="daily-insight__tip">
<Icon icon="solar:lightbulb-bolt-bold-duotone" width="16" />
<span>{aiData.tip}</span>
</div>
</>
)}
</div>
</div>
);