💰 账单页(BillPage)
账单的详细管理页面,包括交易流水、CSV 导入、分类管理、成员邀请、预算设置等核心功能。数据来自 DataContext。
页面结构
- 侧边栏:账单列表 + 添加账单(复用 HomePage 侧边栏)
- Tab 栏:交易 / 分类 / 成员 / 预算 / 定期 / 设置
- 交易 Tab:筛选栏 + 交易列表 + 分页 + 汇总统计
- 分类 Tab:分类列表(图标+名称+类型+颜色+操作)
- 成员 Tab:成员列表 + 邀请功能
- 预算 Tab:月度预算设置(按分类)
- 定期 Tab:定期账单管理(新建/激活/暂停/删除)
- 设置 Tab:账单名称修改 + 删除账单
数据流
BillPage 通过 DataContext 获取:bills, transactions, categories, budgets, selectedBillId, selectedBill
DataContext 的 mutate(key) 规则:变更 bills → 重新 GET /api/bills;变更 transactions → 重新 GET /api/transactions/:billId;etc.
DataContext 的 mutate(key) 规则:变更 bills → 重新 GET /api/bills;变更 transactions → 重新 GET /api/transactions/:billId;etc.
触发时机详解
交易 Tab — 核心操作
1. Tab 切换到「交易」→ 显示流水列表(来自 DataContext)
触发条件:点击"交易" Tab → setActiveTab("transactions") → 显示交易列表(数据来自 DataContext.transactions,无需额外请求)
2. 筛选条件变化 → 过滤显示(纯前端)
触发条件:修改日期范围 / 类型筛选 / 分类筛选 → setFilters() → 本地 filteredTransactions 过滤(不回发请求)
3. 点击「添加交易」→ Modal → POST /api/transactions
触发条件:点击"添加交易"按钮 → 弹出添加交易 Modal → 填写信息 → 点击确认
POST
/api/transactions
✅ 点击"添加交易"确认按钮触发
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
bill_id | string | 必填 | 所属账单ID(当前 selectedBillId) |
amount | number | 必填 | 金额(正数,内部根据 type 转为正负) |
type | string | 必填 | income | expense |
category_id | string | 必填 | 分类ID |
date | string | 必填 | 日期(YYYY-MM-DD) |
description | string | 选填 | 备注描述 |
shared_with | string[] | 选填 | 分摊成员用户ID数组(AA 分摊场景) |
副作用:成功后 mutate("transactions") → DataContext 重新 GET /api/transactions/:billId
4. 点击「编辑」交易 → Modal → PUT /api/transactions/:id
触发条件:点击交易行的"编辑"按钮 → 弹出编辑 Modal → 修改信息 → 点击确认
PUT
/api/transactions/:id
✅ 点击确认按钮触发
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
amount | number | 必填 | 新金额 |
type | string | 必填 | income | expense |
category_id | string | 必填 | 分类ID |
date | string | 必填 | 日期(YYYY-MM-DD) |
description | string | 选填 | 备注描述 |
副作用:成功后 mutate("transactions")
5. 点击「删除」交易 → DELETE /api/transactions/:id
触发条件:点击交易行的"删除"按钮 → confirm() 确认 → 发送 DELETE 请求
DELETE
/api/transactions/:id
✅ confirm 确认后触发
副作用:成功后 mutate("transactions")
6. 批量选择 + 删除 → 批量 DELETE
触发条件:勾选多条 → 点击"删除选中(N)" → 遍历每个选中 ID → Promise.all 并发 DELETE
7. CSV 导入
触发条件:点击"导入 CSV" → 文件选择框触发 → 选文件 → 上传处理
POST
/api/csvimports/parse
✅ 选择 CSV 文件后立即上传解析(无确认按钮)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
file | File | 必填 | CSV 文件(FormData 方式上传) |
bill_id | string | 必填 | 目标账单ID |
响应: {"rows": 10, "columns": ["date","amount","type","category","description"], "preview": [...]}
POST
/api/csvimports
✅ 确认导入按钮触发(在预览 Modal 中点击确认)
说明:body 包含 column_mapping(字段映射)和已解析的 transactions 数组
副作用:成功后 mutate("transactions")
分类 Tab
8. 切换到「分类」Tab
触发条件:点击"分类" Tab → setActiveTab("categories") → 显示分类列表(来自 DataContext.categories)
9. 点击「添加分类」→ Modal → POST /api/categories
触发条件:点击添加分类按钮 → 弹出 Modal → 填写名称/图标/颜色/类型 → 确认
POST
/api/categories
✅ 点击确认按钮触发
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
bill_id | string | 必填 | 所属账单ID |
name | string | 必填 | 分类名称 |
type | string | 必填 | income | expense |
icon | string | 选填 | emoji 图标(默认 📁) |
color | string | 选填 | 颜色(默认 #6366f1) |
parent_id | string | 选填 | 父分类ID(二级分类支持) |
副作用:成功后 mutate("categories")
10. 编辑 / 删除分类 → PUT / DELETE /api/categories/:id
触发条件:点击编辑/删除按钮 → 弹出确认 Modal → 确认 → 发送 PUT 或 DELETE
副作用:操作成功后 mutate("categories")
成员 Tab
11. 切换到「成员」Tab → GET /api/bills/:id(更新成员信息)
触发条件:点击"成员" Tab → 重新 GET /api/bills/:id(确保成员列表最新)
12. 邀请成员 → POST /api/bills/:id/members
触发条件:点击邀请按钮 → 弹出 Modal → 输入用户手机号或邮箱 → 确认
POST
/api/bills/:id/members
✅ 点击确认邀请按钮触发
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
phone | string | 选填 | 被邀请人手机号 |
email | string | 选填 | 被邀请人邮箱 |
副作用:成功后重新 GET /api/bills/:id 更新成员列表
预算 Tab
13. 切换到「预算」Tab
触发条件:点击"预算" Tab → 显示预算列表(来自 DataContext.budgets)
14. 添加 / 编辑预算 → POST / PUT /api/budgets
触发条件:点击"添加预算"或编辑按钮 → 弹出 Modal → 填写月预算金额 → 确认
POST
/api/budgets
✅ 点击确认按钮触发
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
bill_id | string | 必填 | 所属账单ID |
category_id | string | 必填 | 关联分类ID(null = 总预算) |
amount | number | 必填 | 月度预算金额 |
副作用:成功后 mutate("budgets")
定期 Tab
15. 切换到「定期」Tab → GET /api/recurring
触发条件:点击"定期" Tab → 获取当前账单的定期账单列表
GET
/api/recurring?bill_id=:billId
✅ 切换到定期 Tab 时触发
16. 创建 / 更新定期账单 → POST / PUT /api/recurring
触发条件:点击"新建定期"或编辑 → 弹出 Modal → 填写信息 → 确认
POST
/api/recurring
✅ 点击确认按钮触发
参数:bill_id, category_id, amount, type, description, start_date, end_date, recurrence_pattern
副作用:成功后重新 GET /api/recurring
设置 Tab
17. 切换到「设置」Tab
触发条件:点击"设置" Tab → setActiveTab("settings")(纯前端状态切换,无额外请求)
18. 修改账单名称 → PUT /api/bills/:id
触发条件:修改账单名称输入框 → 失去焦点时自动 PUT(onBlur)
PUT
/api/bills/:id
✅ onBlur 时自动触发(无需确认按钮)
参数:{"name": "新名称"}
副作用:成功后 mutate("bills") + mutate("selectedBill")
19. 删除账单 → DELETE /api/bills/:id
触发条件:点击"删除账单"按钮 → confirm() 确认 → 发送 DELETE → Navigate to /home
DELETE
/api/bills/:id
✅ confirm 确认后触发
副作用:成功后 mutate("bills") + Navigate to /home