feat(panel): harcanabilir ve grup harcama grafikleri

- Günlük / Haftalık / Aylık sekmeli iki çizgi grafik (Recharts, ayrı parça olarak yüklenir)
- Kümülatif harcanabilir vs gerçekleşen; 4 grup (+ isteğe bağlı harcanabilir çizgisi)
- Dönem istatistiklerine grup kırılımı (spent_by_group)
- Grafik altında metin özeti, koyu tema uyumlu renkler

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-13 00:14:55 +03:00
parent 64c185ab96
commit 191c3e6db5
20 changed files with 952 additions and 27 deletions
+3
View File
@@ -79,6 +79,8 @@ struct PeriodStatDto {
spendable: i64,
#[ts(type = "number")]
spent: i64,
/// Harcanan, gruplara göre
spent_by_group: GroupAmounts,
/// Kapanmamışsa `null`
#[ts(type = "number | null")]
to_savings: Option<i64>,
@@ -105,6 +107,7 @@ pub async fn periods(
status: x.period.status,
spendable: x.spendable,
spent: x.spent,
spent_by_group: x.spent_by_group.into(),
to_savings: x.period.to_savings,
}
})
+7 -4
View File
@@ -44,6 +44,8 @@ pub struct Summary {
pub budget_total: i64,
/// Dönemde gerçekleşen harcama (silinenler hariç)
pub spent_total: i64,
/// Aynısı gruplara göre (`Group::ALL` sırasıyla)
pub spent_by_group: GroupAmounts,
}
pub struct WeekBudget {
@@ -139,16 +141,16 @@ pub async fn summary(db: &Database, household_id: Uuid, period_id: Uuid) -> AppR
.sum();
let spendable =
income_total - fixed_expense_total - p.savings_goal - carryover_debt + carryover_surplus;
let spent_total = sum_by(
let by_group = sum_by(
db,
col::ENTRIES,
household_id,
doc! { "period_id": period_id },
"$group",
)
.await?
.values()
.sum();
.await?;
let spent_by_group = Group::ALL.map(|g| by_group.get(g.as_str()).copied().unwrap_or(0));
let spent_total = spent_by_group.iter().sum();
Ok(Summary {
income_total,
@@ -159,6 +161,7 @@ pub async fn summary(db: &Database, household_id: Uuid, period_id: Uuid) -> AppR
spendable,
budget_total,
spent_total,
spent_by_group,
})
}
+3 -1
View File
@@ -2,7 +2,7 @@
//!
//! - `daily`: dönemin her günü için 4 grubun harcaması (harcama olmayan gün 0).
//! Günlük/haftalık ve kümülatif seriler istemcide bundan türetilir.
//! - `periods`: son N dönemin harcanabilir/harcanan tutarı (aylık grafik) ve
//! - `periods`: son N dönemin harcanabilir/harcanan tutarı, grup kırılımıyla (aylık grafik) ve
//! **toplam birikim** = kapanışlarda birikime aktarılanların toplamı
//! (varlık değerleri Faz 8'de bunun yerini alacak). Yeniden açılan dönemin son
//! kapanıştaki tutarı, yeniden kapatılana kadar sayılır.
@@ -59,6 +59,7 @@ pub struct PeriodStat {
pub period: Period,
pub spendable: i64,
pub spent: i64,
pub spent_by_group: GroupAmounts,
}
pub struct Stats {
@@ -78,6 +79,7 @@ pub async fn periods(db: &Database, household_id: Uuid, limit: usize) -> AppResu
period: p,
spendable: s.spendable,
spent: s.spent_total,
spent_by_group: s.spent_by_group,
});
}
out.reverse();