💰 账单页(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.

触发时机详解

交易 Tab — 核心操作

1. Tab 切换到「交易」→ 显示流水列表(来自 DataContext)

触发条件:点击"交易" Tab → setActiveTab("transactions") → 显示交易列表(数据来自 DataContext.transactions,无需额外请求)

2. 筛选条件变化 → 过滤显示(纯前端)

触发条件:修改日期范围 / 类型筛选 / 分类筛选 → setFilters() → 本地 filteredTransactions 过滤(不回发请求)

3. 点击「添加交易」→ Modal → POST /api/transactions

触发条件:点击"添加交易"按钮 → 弹出添加交易 Modal → 填写信息 → 点击确认
POST /api/transactions
✅ 点击"添加交易"确认按钮触发
参数类型必填说明
bill_idstring必填所属账单ID(当前 selectedBillId)
amountnumber必填金额(正数,内部根据 type 转为正负)
typestring必填income | expense
category_idstring必填分类ID
datestring必填日期(YYYY-MM-DD)
descriptionstring选填备注描述
shared_withstring[]选填分摊成员用户ID数组(AA 分摊场景)

副作用:成功后 mutate("transactions") → DataContext 重新 GET /api/transactions/:billId

4. 点击「编辑」交易 → Modal → PUT /api/transactions/:id

触发条件:点击交易行的"编辑"按钮 → 弹出编辑 Modal → 修改信息 → 点击确认
PUT /api/transactions/:id
✅ 点击确认按钮触发
参数类型必填说明
amountnumber必填新金额
typestring必填income | expense
category_idstring必填分类ID
datestring必填日期(YYYY-MM-DD)
descriptionstring选填备注描述

副作用:成功后 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 文件后立即上传解析(无确认按钮)
参数类型必填说明
fileFile必填CSV 文件(FormData 方式上传)
bill_idstring必填目标账单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_idstring必填所属账单ID
namestring必填分类名称
typestring必填income | expense
iconstring选填emoji 图标(默认 📁)
colorstring选填颜色(默认 #6366f1)
parent_idstring选填父分类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
✅ 点击确认邀请按钮触发
参数类型必填说明
phonestring选填被邀请人手机号
emailstring选填被邀请人邮箱

副作用:成功后重新 GET /api/bills/:id 更新成员列表

预算 Tab

13. 切换到「预算」Tab

触发条件:点击"预算" Tab → 显示预算列表(来自 DataContext.budgets)

14. 添加 / 编辑预算 → POST / PUT /api/budgets

触发条件:点击"添加预算"或编辑按钮 → 弹出 Modal → 填写月预算金额 → 确认
POST /api/budgets
✅ 点击确认按钮触发
参数类型必填说明
bill_idstring必填所属账单ID
category_idstring必填关联分类ID(null = 总预算)
amountnumber必填月度预算金额

副作用:成功后 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