首页 / ChatBar


页面路由:/(HomePage)
核心组件:ChatBar.jsx(AI 对话浮栏)



首页加载时


初始化用户信息


GET /api/auth/me

认证:必需(JWT Bearer Token)


后端处理:从 JWT 提取 userId → 查询 users 表 → 头像兜底生成


响应


{
  "user": {
    "id": "string",
    "phone": "string",
    "nickname": "string",
    "email": "string | null",
    "avatar_url": "string",
    "is_guest": 0 | 1,
    "has_onboarded": 0 | 1,
    "role": "user | admin | developer"
  }
}



加载账单列表


GET /api/bills

认证:必需


后端处理:JOIN bills + bill_members + users(owner)→ 筛选当前用户是成员的账单 → 按 updated_at 倒序


响应


{
  "bills": [
    {
      "id": "uuid",
      "name": "账单名",
      "owner_phone": "string",
      "owner_nickname": "string",
      "role": "owner | editor | viewer",
      "custom_prompt": "string | null"
    }
  ]
}



加载最近活跃账单的详情


GET /api/bills/:id

认证:必需


触发条件:自动加载最近一次活跃账单的详情(从 localStorage 读取 lastActiveBillId


后端处理

1. 校验账单存在 + 用户是成员

2. 获取该账单所有成员

3. 获取该账单所有分类


响应


{
  "bill": { /* bills 表全部字段 */ },
  "members": [ /* 成员列表 */ ],
  "categories": [ /* 分类列表 */ ],
  "myRole": "owner | editor | viewer",
  "myPerms": { "can_edit": true, "can_delete": true }
}



加载账单交易记录


GET /api/transactions/:billId

认证:必需


后端处理:查询 transactions.bill_id = :billId → 按 tx_time ASC 排序


响应


{
  "transactions": [
    {
      "id": "string",
      "category": "string(来自 CSV,非 category_id 关联)",
      "tx_type": "支出 | 收入 | ...",
      "amount": "integer(单位:分)",
      "tx_time": "datetime"
    }
  ],
  "uploadMeta": { /* 最近一次 CSV 上传信息 */ }
}



切换账单时


触发条件:用户在下拉框中选择不同账单


调用:同「加载账单详情」GET /api/bills/:id,同时清空 ChatBar 消息历史




ChatBar AI 对话


页面加载 ChatBar 时


#### 加载 AI Keys(自动)


GET /api/apikeys/resolve-all/:billId

认证:必需


后端处理:查询该账单所有可用的 AI Key(个人 + 共享),按 priority 排序


响应


{
  "available": [
    {
      "id": "key_id",
      "provider": "openai",
      "model": "gpt-4o",
      "owner_type": "user",
      "owner_id": "user_id",
      "is_self_owner": true
    }
  ]
}



发送文本消息


触发条件:用户输入文字并点击发送(或按回车)



POST /api/ai/chat

认证:必需(Authorization Bearer Token)


Content-Typeapplication/json


参数

参数类型说明
billIdstring当前账单 ID
providerstringAI 提供商(openai/anthropic/gemini 等)
modelstring模型名(可选,不传则自动选择)
owner_typestringKey 类型(user
owner_idnumberKey 所有者 ID
messagesarray对话历史(最多10条,格式同 OpenAI)

messages 格式


[
  { "role": "system", "content": "你是一个助手..." },
  { "role": "user", "content": "分析我的账单" }
]

响应格式SSE 流Content-Type: text/event-stream



data: {"content": "部分回复内容"}

data: [DONE]

错误响应


data: [ERROR] AI 请求失败,请稍后重试

data: [DONE]

关键前端逻辑




发送语音消息


前置条件:VOICE_INPUT_ENABLED = false(当前语音功能禁用)



POST /api/ai/transcribe

认证:必需


Content-Typemultipart/form-data


参数

参数类型说明
audioFile音频文件(WebM/PCM)

后端处理:调用 Whisper API 转写音频 → 返回文本


响应


{ "text": "转写后的文字" }



更新账单 Custom Prompt


触发条件:用户在 ChatBar 中开启 Prompt 模式并保存



PUT /api/bills/:billId/prompt

认证:必需


参数


{ "prompt": "你是一个专业财务分析师..." }

后端处理:更新 bill_members.custom_prompt 字段




首页数据流全貌



进入首页
    │
    ├── GET /auth/me          → 获取用户信息
    │
    ├── GET /bills            → 获取账单列表
    │
    ├── GET /bills/:id        → 加载最近活跃账单详情
    │                            (含 members、categories)
    │
    ├── GET /transactions/:billId  → 加载交易记录
    │
    └── GET /apikeys/resolve-all/:billId  → 加载可用 AI Keys
                                                   │
                                                   ▼
                                          ChatBar 渲染就绪
                                                   │
                      ┌────────────────────────────┼────────────────────────────┐
                      ▼                            ▼                            ▼
               发送文本消息                  发送语音消息                  更新 Custom Prompt
              POST /ai/chat              POST /ai/transcribe           PUT /bills/:id/prompt
              (SSE 流式响应)             (Whisper 转写)                (保存 Prompt)



已知行为