fix: 修复账单删除功能并支持分析页面删除操作
Some checks failed
Deploy BillAI / Deploy to Production (push) Has been cancelled

- 将删除接口从 DELETE /api/bills/:id 改为 POST /api/bills/:id/delete 以兼容 SvelteKit 代理
- 分析页面组件 (TopExpenses/BillRecordsTable/DailyTrendChart) 支持删除并同步更新统计数据
- Review 接口改为直接查询 MongoDB 而非读取文件
- 软删除时记录 updated_at 时间戳
- 添加 .dockerignore 文件优化构建
- 完善 AGENTS.md 文档
This commit is contained in:
clz
2026-02-16 22:28:49 +08:00
parent a5f1a370c7
commit 642ea2d3ef
13 changed files with 277 additions and 151 deletions

View File

@@ -16,6 +16,7 @@
pageSize?: number;
categories?: string[];
onUpdate?: (updated: UIBill, original: UIBill) => void;
onDelete?: (deleted: UIBill) => void;
}
let {
@@ -24,7 +25,8 @@
showDescription = true,
pageSize = 10,
categories = [],
onUpdate
onUpdate,
onDelete
}: Props = $props();
// 排序状态
@@ -112,6 +114,24 @@
onUpdate?.(updated, original);
}
function handleRecordDeleted(deleted: UIBill) {
const idx = records.findIndex(r => r === deleted);
const finalIdx = idx !== -1
? idx
: records.findIndex(r =>
r.time === deleted.time &&
r.merchant === deleted.merchant &&
r.amount === deleted.amount
);
if (finalIdx !== -1) {
records.splice(finalIdx, 1);
records = [...records];
}
onDelete?.(deleted);
}
// 重置分页(当记录变化时)
$effect(() => {
records;
@@ -280,4 +300,6 @@
viewDescription="查看这笔支出的详细信息"
editDescription="修改这笔支出的信息"
onUpdate={handleRecordUpdated}
onDelete={handleRecordDeleted}
allowDelete={true}
/>

View File

@@ -18,9 +18,10 @@
records: UIBill[];
categories?: string[];
onUpdate?: (updated: UIBill, original: UIBill) => void;
onDelete?: (deleted: UIBill) => void;
}
let { records = $bindable(), categories = [], onUpdate }: Props = $props();
let { records = $bindable(), categories = [], onUpdate, onDelete }: Props = $props();
function handleRecordUpdated(updated: UIBill, original: UIBill) {
// 更新 records 数组
@@ -46,6 +47,28 @@
// 传播到父组件
onUpdate?.(updated, original);
}
function handleRecordDeleted(deleted: UIBill) {
const idx = records.findIndex(r =>
r === deleted ||
(r.time === deleted.time && r.merchant === deleted.merchant && r.amount === deleted.amount)
);
if (idx !== -1) {
records.splice(idx, 1);
records = [...records];
}
const dateIdx = selectedDateRecords.findIndex(r =>
r === deleted ||
(r.time === deleted.time && r.merchant === deleted.merchant && r.amount === deleted.amount)
);
if (dateIdx !== -1) {
selectedDateRecords.splice(dateIdx, 1);
selectedDateRecords = [...selectedDateRecords];
}
onDelete?.(deleted);
}
// Dialog 状态
let dialogOpen = $state(false);
@@ -923,6 +946,7 @@
pageSize={8}
{categories}
onUpdate={handleRecordUpdated}
onDelete={handleRecordDeleted}
/>
</div>
{:else}

View File

@@ -8,9 +8,10 @@
records: UIBill[];
categories: string[]; // 可用的分类列表
onUpdate?: (record: UIBill) => void;
onDelete?: (record: UIBill) => void;
}
let { records, categories, onUpdate }: Props = $props();
let { records, categories, onUpdate, onDelete }: Props = $props();
let dialogOpen = $state(false);
let selectedRecord = $state<UIBill | null>(null);
@@ -32,6 +33,26 @@
selectedRecord = updated;
onUpdate?.(updated);
}
function handleRecordDeleted(deleted: UIBill) {
const idx = records.findIndex(r => r === deleted);
const finalIdx = idx !== -1
? idx
: records.findIndex(r =>
r.time === deleted.time &&
r.merchant === deleted.merchant &&
r.amount === deleted.amount
);
if (finalIdx !== -1) {
records.splice(finalIdx, 1);
records = [...records];
}
selectedRecord = null;
selectedRank = 0;
onDelete?.(deleted);
}
</script>
<Card.Root class="transition-all duration-200 hover:shadow-lg hover:-translate-y-1">
@@ -80,6 +101,8 @@
viewDescription="查看这笔支出的完整信息"
editDescription="修改这笔支出的信息"
onUpdate={handleRecordUpdated}
onDelete={handleRecordDeleted}
allowDelete={true}
>
{#snippet titleExtra({ isEditing })}
{#if selectedRank <= 3 && !isEditing}