diff --git a/web/src/lib/components/analysis/CategoryRanking.svelte b/web/src/lib/components/analysis/CategoryRanking.svelte
index 60a7825..3dda463 100644
--- a/web/src/lib/components/analysis/CategoryRanking.svelte
+++ b/web/src/lib/components/analysis/CategoryRanking.svelte
@@ -16,9 +16,25 @@
totalExpense: number;
records: UIBill[];
categories?: string[];
+ onUpdate?: (updated: UIBill, original: UIBill) => void;
}
- let { categoryStats, pieChartData, totalExpense, records = $bindable(), categories = [] }: Props = $props();
+ let { categoryStats, pieChartData, totalExpense, records = $bindable(), categories = [], onUpdate }: Props = $props();
+
+ function handleRecordUpdated(updated: UIBill, original: UIBill) {
+ // 更新本地 records 数组
+ const idx = records.findIndex(r =>
+ r === original ||
+ (r.time === original.time && r.merchant === original.merchant && r.amount === original.amount)
+ );
+ if (idx !== -1) {
+ records[idx] = updated;
+ records = [...records];
+ }
+
+ // 传播到父组件
+ onUpdate?.(updated, original);
+ }
let mode = $state<'bar' | 'pie'>('bar');
let dialogOpen = $state(false);
@@ -213,7 +229,7 @@
-
+
diff --git a/web/src/lib/components/analysis/DailyTrendChart.svelte b/web/src/lib/components/analysis/DailyTrendChart.svelte
index 7f5be61..db5d95b 100644
--- a/web/src/lib/components/analysis/DailyTrendChart.svelte
+++ b/web/src/lib/components/analysis/DailyTrendChart.svelte
@@ -17,9 +17,35 @@
interface Props {
records: UIBill[];
categories?: string[];
+ onUpdate?: (updated: UIBill, original: UIBill) => void;
}
- let { records = $bindable(), categories = [] }: Props = $props();
+ let { records = $bindable(), categories = [], onUpdate }: Props = $props();
+
+ function handleRecordUpdated(updated: UIBill, original: UIBill) {
+ // 更新 records 数组
+ const idx = records.findIndex(r =>
+ r === original ||
+ (r.time === original.time && r.merchant === original.merchant && r.amount === original.amount)
+ );
+ if (idx !== -1) {
+ records[idx] = updated;
+ records = [...records];
+ }
+
+ // 更新 selectedDateRecords(如果账单在当前选中的日期记录中)
+ const dateIdx = selectedDateRecords.findIndex(r =>
+ r === original ||
+ (r.time === original.time && r.merchant === original.merchant && r.amount === original.amount)
+ );
+ if (dateIdx !== -1) {
+ selectedDateRecords[dateIdx] = updated;
+ selectedDateRecords = [...selectedDateRecords];
+ }
+
+ // 传播到父组件
+ onUpdate?.(updated, original);
+ }
// Dialog 状态
let dialogOpen = $state(false);
@@ -896,6 +922,7 @@
showDescription={false}
pageSize={8}
{categories}
+ onUpdate={handleRecordUpdated}
/>
{:else}
diff --git a/web/src/lib/components/analysis/TopExpenses.svelte b/web/src/lib/components/analysis/TopExpenses.svelte
index d22204c..e31895f 100644
--- a/web/src/lib/components/analysis/TopExpenses.svelte
+++ b/web/src/lib/components/analysis/TopExpenses.svelte
@@ -24,7 +24,11 @@
function handleRecordUpdated(updated: UIBill, original: UIBill) {
const idx = records.findIndex(r => r === original);
- if (idx !== -1) records[idx] = updated;
+ if (idx !== -1) {
+ records[idx] = updated;
+ // 触发响应式更新
+ records = [...records];
+ }
selectedRecord = updated;
onUpdate?.(updated);
}
diff --git a/web/src/routes/analysis/+page.svelte b/web/src/routes/analysis/+page.svelte
index a7a7b3a..da4ca04 100644
--- a/web/src/routes/analysis/+page.svelte
+++ b/web/src/routes/analysis/+page.svelte
@@ -91,6 +91,42 @@
let pieChartData = $derived(calculatePieChartData(categoryStats, totalStats.expense));
let topExpenses = $derived(getTopExpenses(analysisRecords, 10));
+ // 账单更新处理
+ function handleBillUpdated(updated: UIBill) {
+ // 在 records 中查找并更新对应的账单
+ const idx = records.findIndex(r =>
+ r.id === (updated as unknown as { id?: string }).id ||
+ (r.time === updated.time && r.merchant === updated.merchant && r.amount === updated.amount)
+ );
+
+ if (idx !== -1) {
+ // 更新后端格式的记录
+ records[idx] = {
+ ...records[idx],
+ time: updated.time,
+ category: updated.category,
+ merchant: updated.merchant,
+ description: updated.description || '',
+ amount: updated.amount,
+ pay_method: updated.paymentMethod || '',
+ status: updated.status || records[idx].status,
+ remark: updated.remark || records[idx].remark,
+ };
+ // 触发响应式更新
+ records = [...records];
+
+ // 同时更新 allRecords(如果账单在全部数据中)
+ const allIdx = allRecords.findIndex(r =>
+ r.id === (updated as unknown as { id?: string }).id ||
+ (r.time === updated.time && r.merchant === updated.merchant)
+ );
+ if (allIdx !== -1) {
+ allRecords[allIdx] = records[idx];
+ allRecords = [...allRecords];
+ }
+ }
+ }
+
// 分类列表按数据中出现次数排序
let sortedCategories = $derived(() => {
const categoryCounts = new Map();
@@ -253,7 +289,7 @@
-
+
@@ -263,6 +299,7 @@
totalExpense={totalStats.expense}
records={analysisRecords}
categories={sortedCategories()}
+ onUpdate={handleBillUpdated}
/>
@@ -270,7 +307,7 @@
-
+
{:else}