docs: 同步汇账最新功能,新增智能查数、账单关系等文档

对照 ledgerly 自文档上次更新以来的全部改动,补充新功能文档、修正品牌与版本残留,并新增下载与安装页;配图已重新截取并上传 OSS,本地截图目录不纳入版本管理。

变更内容:
- 新增「智能查数」「账单关系」两个使用文档页,并登记侧边栏与总览
- 设置页扩充为八个面板(账号安全、数据库实时进度、外观、导航等)并改为即时保存
- 收支记录补充关系列、批量操作、AI 搜索浮窗、可配置分页与「账单详情」弹窗
- 统计面板补充饼图/渠道图下钻与筛选双向联动;规则管理补充批量删除
- AI 能力补充智能查数与关系命名;新增下载与安装页
- 开发文档同步:AI 13 类调用、数据模型 24 张表、API、前端偏好、构建部署
- 统一「汇账 Ledgerly」品牌与「设置/日志」菜单文案,版本号对齐 0.1
- 截图脚本新增账单详情等场景并更新登记

说明:
- download.md 的 OSS 下载链接保持待发布产物回填,暂不调整
- 已通过 npm run docs:build 与 npm run typecheck:scripts
This commit is contained in:
2026-09-26 21:57:38 +08:00
parent b979c6e498
commit 923d6db5c0
35 changed files with 841 additions and 216 deletions
+84 -39
View File
@@ -8,7 +8,7 @@
为此项目在 `ledgerly/AGENTS.md` 中约定:
> 多 Tab 或可切换的界面偏好需**持久化记忆**(`localStorage`),下次打开时恢复到上次选择;存储键统一以 `finance.` 前缀命名,读取时对非法值回退默认项,写入时忽略存储异常。
> 多 Tab 或可切换的界面偏好需**持久化记忆**(`localStorage`),下次打开时恢复到上次选择;存储键统一以 `ledgerly.` 前缀命名,读取时对非法值回退默认项,写入时忽略存储异常。
据此形成三条实践原则:
@@ -32,38 +32,45 @@
| 键名 | 偏好内容 | 文件 | 保存时机 | 读取时机 |
|---|---|---|---|---|
| `locale` | 界面语言 `zh-CN`/`en-US`/`ja-JP` | `locales/index.ts:16` | 切换语言 | 模块初始化 |
| `finance.dashboard.prefs` | 统计面板时间范围、粒度与 11 项筛选 | `views/Dashboard.vue:470` | 变量 `watch` 自动 | `onMounted` |
| `finance.transaction.filterPrefs` | 收支列表筛选、分页、排序 | `views/TransactionList.vue:369` | 变量 `watch` 自动 | `onMounted` |
| `finance.transaction.aiScope` | 批量 AI 建议范围 | `views/TransactionList.vue:146` | 变量 `watch` 自动 | ref 初始化 |
| `finance.transaction.aiRecordTab` | AI 记账方式(文字/图片) | `views/TransactionList.vue:206` | 变量 `watch` 自动 | ref 初始化 |
| `finance.transaction.aiQueryHistory` | AI 自然语言查询历史 | `views/TransactionList.vue:195` | 提交查询时 | `onMounted` |
| `finance.transaction.remarkHistory` | 备注关键词历史 | `views/TransactionList.vue:300` | 备注失焦/回车 | `onMounted` |
| `finance.dashboard.aiSearchHistory` | 统计面板 AI 查询历史 | `views/Dashboard.vue:91` | 提交 AI 搜索时 | `onMounted` |
| `finance.billImport.billType` | 上次选择的账单来源类型 | `views/BillImportPanel.vue:25` | 切换类型时 | ref 初始化 |
| `finance.transaction.relationType` | 账单关系类型偏好 | `components/TransactionRelationEditorModal.vue:14` | 创建模式切换类型时 | 弹窗初始化 |
| `emailBill.tab` | 邮箱账单页标签页 | `views/EmailBillManage.vue:43` | Tab 切换时 | 路由重定向 + 组件 |
| `logs.tab` | 系统日志页标签页 | `views/Logs.vue:25` | Tab 切换时 | 路由重定向 + 组件 |
| `ledgerly.locale` | 界面语言 `zh-CN`/`en-US`/`ja-JP` | `locales/index.ts` | 切换语言 | 模块初始化 |
| `ledgerly.dashboard.prefs` | 统计面板时间范围、粒度与多项筛选 | `views/Dashboard.vue` | 变量 `watch` 自动 | `onMounted` |
| `ledgerly.transaction.filterPrefs` | 收支列表筛选、分页、排序 | `views/TransactionList.vue` | 变量 `watch` 自动 | `onMounted` |
| `ledgerly.transaction.aiScope` | 批量 AI 建议范围 | `views/TransactionList.vue` | 变量 `watch` 自动 | ref 初始化 |
| `ledgerly.transaction.aiRecordTab` | AI 记账方式(文字/图片) | `views/TransactionList.vue` | 变量 `watch` 自动 | ref 初始化 |
| `ledgerly.transaction.aiQueryHistory` | AI 自然语言查询历史 | `views/TransactionList.vue` / `components/AiQueryWindow.vue` | 提交查询时 | 浮窗聚焦时 |
| `ledgerly.dashboard.aiSearchHistory` | 统计面板 AI 查询历史 | `views/Dashboard.vue` | 提交 AI 搜索时 | 浮窗聚焦时 |
| `ledgerly.transaction.aiQueryWindow` | 收支记录 AI 查询浮窗位置与尺寸 | `components/FloatingPanel.vue` | 拖拽/缩放结束时 | 浮窗初始化 |
| `ledgerly.dashboard.aiQueryWindow` | 统计面板 AI 搜索浮窗位置与尺寸 | `components/FloatingPanel.vue` | 拖拽/缩放结束时 | 浮窗初始化 |
| `ledgerly.transaction.remarkHistory` | 备注关键词历史 | `views/TransactionList.vue` | 备注失焦/回车 | `onMounted` |
| `ledgerly.billImport.billType` | 上次选择的账单来源类型 | `views/BillImportPanel.vue` | 切换类型时 | ref 初始化 |
| `ledgerly.transaction.relationType` | 账单关系类型偏好 | `components/TransactionRelationEditorModal.vue` | 创建模式切换类型时 | 弹窗初始化 |
| `ledgerly.pagination.tablePageSizes` | 各表格分别记住的每页条数 | `utils/tablePageSizePrefs.ts` | 切换每页条数时 | 表格初始化 |
| `ledgerly.emailBill.tab` | 邮箱账单页标签页 | `views/EmailBillManage.vue` | Tab 切换时 | 路由重定向 + 组件 |
| `ledgerly.logs.tab` | 日志页标签页 | `views/Logs.vue` | Tab 切换时 | 路由重定向 + 组件 |
> `locale`、`emailBill.tab`、`logs.tab` 是较早的实现,未使用 `finance.` 前缀;前两者分别为国际化与路由重定向的既有约定,改动时需保持键名稳定。
> `locale`、`emailBill.tab`、`logs.tab` 是较早的实现,最初未加前缀,现已统一为 `ledgerly.` 前缀:在 `LEGACY_STORAGE_KEYS` 登记旧键、读取前用 `migrateKey` 一次性迁移;品牌改名(`finance.` → `ledgerly.`)的旧键由 `migrateLegacyPrefixedKeys()` 在模块加载时批量迁移,新键已存在时不覆盖。
### sessionStorage 偏好
| 键名 | 偏好内容 | 文件 |
|---|---|---|
| `finance.scroll.<路由路径>` | 各页面内容区滚动位置 | `views/Layout.vue:83` |
| `ledgerly.scroll.<路由路径>` | 各页面内容区滚动位置 | `views/Layout.vue` |
| `ledgerly.sqlQuery.session` | 智能查数当前会话的提问、结果与视图(结果超 500 行时只存提问与视图) | `views/SqlQuery.vue` |
### 后端按用户同步的偏好
| 接口 | 偏好内容 | 前端入口 |
|---|---|---|
| `GET/PUT /api/setting/excluded-display-style` | 「不计入统计」记录展示样式 | `components/DisplayConfigPanel.vue` |
| `GET/PUT /api/setting/show-hidden-data` | 是否显示已隐藏备注的记录 | `components/DisplayConfigPanel.vue` |
| `GET/PUT /api/setting/pagination-prefs` | 表格分页候选与默认每页条数 | `components/DisplayConfigPanel.vue` |
| `GET/PUT /api/setting/nav-menu` | 左侧导航顺序与显隐 | `components/NavMenuConfigPanel.vue` |
| `GET/PUT /api/setting/bill-source-include-in-stats` | 各账单来源「计入统计」默认值 | `components/BillSourceStatsPanel.vue` |
| `GET/PUT /api/ai/config` | AI 启用开关、密钥、模型 | `components/AiConfigPanel.vue` |
## localStorage 偏好详解
### 界面语言 `locale`
### 界面语言 `ledgerly.locale`
- **文件**:`frontend/src/locales/index.ts`
- **取值**:`zh-CN`、`en-US`、`ja-JP`
@@ -72,7 +79,7 @@
- **目的**:记住用户语言选择,应用启动与切换即时生效。
- **入口**:`components/LocaleSwitch.vue`。
### 统计面板偏好 `finance.dashboard.prefs`
### 统计面板偏好 `ledgerly.dashboard.prefs`
- **文件**:`frontend/src/views/Dashboard.vue`(键名第 470 行)
- **数据结构**(JSON 对象,保存见 `savePrefs()` 第 499 行):
@@ -95,7 +102,7 @@
- **跨页写入**:点击趋势图跳转收支列表时,`applyTrendNavigation()`(第 381 行)把统计口径与筛选**合并写入**收支列表的偏好键,并保留分页、排序等既有设置。
- **目的**:下次进入统计面板自动还原时间范围、粒度与全部过滤条件。
### 收支列表筛选偏好 `finance.transaction.filterPrefs`
### 收支列表筛选偏好 `ledgerly.transaction.filterPrefs`
- **文件**:`frontend/src/views/TransactionList.vue`(键名第 369 行)
- **数据结构**(保存见 `saveFilterPrefs()` 第 396 行):
@@ -121,17 +128,17 @@
| 键名 | 取值 | 说明 |
|---|---|---|
| `finance.transaction.aiScope` | `BOTH`/`CATEGORY`/`TAG` | 批量 AI 建议范围,非法值回退 `BOTH`(第 146 行) |
| `finance.transaction.aiRecordTab` | `text`/`image` | AI 记账方式,非法值回退 `text`(第 206 行) |
| `finance.transaction.aiQueryHistory` | 字符串数组(≤10) | AI 自然语言查询历史,最新在前 |
| `finance.transaction.remarkHistory` | 字符串数组(≤10) | 备注关键词历史,失焦/回车记录 |
| `ledgerly.transaction.aiScope` | `BOTH`/`CATEGORY`/`TAG` | 批量 AI 建议范围,非法值回退 `BOTH`(第 146 行) |
| `ledgerly.transaction.aiRecordTab` | `text`/`image` | AI 记账方式,非法值回退 `text`(第 206 行) |
| `ledgerly.transaction.aiQueryHistory` | 字符串数组(≤10) | AI 自然语言查询历史,最新在前 |
| `ledgerly.transaction.remarkHistory` | 字符串数组(≤10) | 备注关键词历史,失焦/回车记录 |
- **`aiRecordTab`** 是 `AGENTS.md` 点名的参考实现:记住用户上次用的记账方式(文字或图片),下次打开 AI 记账弹窗直接落到该 Tab。
- **关键词历史**统一由 `composables/useKeywordHistory.ts` 管理:去重(忽略大小写)、最新在前、上限 10 条,损坏数据自动忽略,下拉末尾提供「清空历史」项。
- 读取:`load()`;记录:`record()`;清空:`clear()`。
- 三处使用:AI 查询历史、备注历史(均在 `TransactionList.vue`)、统计面板 AI 搜索历史(`Dashboard.vue`,键 `finance.dashboard.aiSearchHistory`)。
- 三处使用:AI 查询历史、备注历史(均在 `TransactionList.vue`)、统计面板 AI 搜索历史(`Dashboard.vue`,键 `ledgerly.dashboard.aiSearchHistory`)。
### 账单导入类型 `finance.billImport.billType`
### 账单导入类型 `ledgerly.billImport.billType`
- **文件**:`frontend/src/views/BillImportPanel.vue`(第 25 行)
- **取值**:账单来源编码(`ALIPAY`、`WECHAT`、`CMB` 等)
@@ -139,7 +146,7 @@
- **保存**:`watch(billType)`(第 226 行)在切换类型时写入,同时清空已选文件,避免格式与类型不匹配。
- **目的**:记住上次选择的账单来源。
### 账单关系类型 `finance.transaction.relationType`
### 账单关系类型 `ledgerly.transaction.relationType`
- **文件**:`frontend/src/components/TransactionRelationEditorModal.vue`(第 14 行)
- **取值**:`PARENT_CHILD`(默认)、`SIBLING`
@@ -147,18 +154,32 @@
- **保存**:`watch(editorType)`(第 69 行)**仅在创建模式**(`editingGroupId === null`)写入,编辑既有关系组不覆盖偏好。
- **目的**:新建关系组时默认沿用上次的关系类型。
### 页面标签页 `emailBill.tab` / `logs.tab`
### 页面标签页 `ledgerly.emailBill.tab` / `ledgerly.logs.tab`
- **文件**:`views/EmailBillManage.vue:43`、`views/Logs.vue:25`
- **文件**:`views/EmailBillManage.vue`、`views/Logs.vue`
- **取值**:邮箱页 `configs`/`senderRules`/`messages`;日志页 `http`/`login`/`app`
- **读取**:路由 `/email-bills`、`/logs` 的 `redirect` 读取偏好并拼接子路径(`router/index.ts:69`、第 93 行),带白名单校验,无记录回退默认。
- **读取**:路由 `/email-bills`、`/logs` 的 `redirect` 读取偏好并拼接子路径(`router/index.ts`),带白名单校验,无记录回退默认。
- **保存**:`watch(activeTab, ..., { immediate: true })` 在 Tab 切换时写入。
- **目的**:下次点击「邮箱账单」「系统日志」回到上次标签页。
- **说明**:这两个是 `AGENTS.md` 点名的参考实现,但键名未加 `finance.` 前缀,属早期实现。
- **目的**:下次点击「邮箱账单」「日志」回到上次标签页。
- **说明**:这两个是 `AGENTS.md` 点名的参考实现,早期未加前缀,现已统一为 `ledgerly.` 前缀并做旧键迁移。
### AI 查询浮窗位置 `ledgerly.transaction.aiQueryWindow` / `ledgerly.dashboard.aiQueryWindow`
- **文件**:`components/FloatingPanel.vue`(键经 `storageKey` 传入,由 `AiQueryWindow.vue` 复用)
- **取值**:`{ x, y, width, height }`,非法值回退居中与默认尺寸(默认 560 × 360)。
- **保存**:拖拽或缩放结束时写入;读取在浮窗初始化时。
- **目的**:记住 AI 查询浮窗上次的位置与大小,下次打开保持原样。
### 各表格每页条数 `ledgerly.pagination.tablePageSizes`
- **文件**:`frontend/src/utils/tablePageSizePrefs.ts`、`composables/useTablePageSize.ts`
- **取值**:`Record<tableKey, number>`,按表格键(`transaction`、`categoryExpense`、`rule`、`logsHttp`、`smart-query` 等)分别记录。
- **优先级**:本机记录(且须在当前分页候选中)> 全局默认值(后端 `paginationPrefs`)> 20。
- **保存**:切换某表格每页条数时写入;候选列表与全局默认值在[设置 → 外观设置](/guide/settings#外观设置)中配置(存后端)。
## sessionStorage 偏好:滚动位置
- **文件**:`frontend/src/views/Layout.vue`(前缀第 83 行,键为 `finance.scroll.<路由路径>`)
- **文件**:`frontend/src/views/Layout.vue`(前缀第 83 行,键为 `ledgerly.scroll.<路由路径>`)
- **保存**:内容区 `scroll` 事件经 `requestAnimationFrame` 节流写入;路由切换前保存离开页;`beforeunload` 兜底(第 172 行)。
- **读取**:`restoreScroll()`(第 139 行)在 `onMounted` 与路由切换后恢复;因页面内容异步加载、切换后高度可能不足,用 `rAF` 轮询等待内容高度足够再定位,2 秒超时后按当前可达最大值定位。
- **目的**:刷新或页面切换后恢复阅读位置;仅当前会话有效,关闭浏览器即失效。
@@ -181,9 +202,33 @@
- **前端**:设置页 `components/BillSourceStatsPanel.vue` 编辑保存(可点整行或开关切换)。
- **目的**:按账单来源设置导入时默认是否计入统计,仅影响统计口径,不改变导入结果。
### 显示已隐藏备注的记录
- **接口**:`GET/PUT /api/setting/show-hidden-data`(`api/setting.ts`)
- **数据结构**:`{ show: boolean }`,默认 `false`。
- **存储**:`t_user_preference` 的 `pref_key = showHiddenData`,值以 `"true"`/`"false"` 保存。
- **前端**:设置页 `components/DisplayConfigPanel.vue` 切换即存;收支列表与 Excel 导出据此过滤(关闭时排除 `remark_hidden = true` 的记录),统计备注搜索不受影响。
- **目的**:统一控制「已隐藏备注的记录」是否出现在列表与导出中。
### 表格分页偏好
- **接口**:`GET/PUT /api/setting/pagination-prefs`(`api/setting.ts`)
- **数据结构**:`{ options: number[], defaultSize: number }`,默认候选 `[10, 20, 50, 100]`、默认 20;后端会规范化(去重升序、1–1000、最多 10 项)。
- **存储**:`t_user_preference` 的 `pref_key = paginationPrefs`(JSON)。
- **前端**:设置页 `components/DisplayConfigPanel.vue` 编辑、防抖 500ms 自动保存;`composables/usePageSizeOptions.ts` 提供全局单例,`useTablePageSize(tableKey)` 读取各表记忆值。
- **目的**:统一所有表格的分页候选与默认每页条数。
### 导航顺序与显隐
- **接口**:`GET/PUT /api/setting/nav-menu`(`api/setting.ts`)
- **数据结构**:`{ items: [{ key, visible }] }`,未配置时以前端 `utils/navItems.ts` 的默认顺序与可见性为准。
- **存储**:`t_user_preference` 的 `pref_key = navMenu`(JSON)。
- **前端**:设置页 `components/NavMenuConfigPanel.vue`(`vuedraggable` 拖拽 + 开关,600ms 防抖保存、可恢复默认);`composables/useNavMenu.ts` 与后端合并,`Layout.vue` 据此渲染。隐藏仅移除菜单入口,路由仍可访问。
- **目的**:按账号自定义左侧导航的顺序与显隐,跨设备生效。
### AI 配置
- **接口**:`GET /api/ai/config`、`PUT /api/ai/config`(`api/ai.ts:37`)
- **接口**:`GET /api/ai/config`、`PUT /api/ai/config`(`api/ai.ts`)
- **数据结构**:`{ enabled, apiKey, hasApiKey, baseUrl, model, visionModel }`,`apiKey` 留空表示不修改原值。
- **前端**:设置页 `components/AiConfigPanel.vue` 编辑保存。
- **目的**:用户级 AI 能力配置;其他页面的 AI 元素统一经 `getAiConfig().enabled` 控制显隐。
@@ -195,11 +240,10 @@
以下常见界面偏好当前**没有**持久化实现,改动时无需假设其存在:
- **主题 / 暗色模式**:无主题存储键,界面主题固定。
- **侧边栏折叠 / 展开**:`Layout.vue` 使用固定 `NLayoutSider`,无折叠状态。
- **侧边栏整体折叠 / 展开**:`Layout.vue` 使用固定 `NLayoutSider`,无折叠状态(但菜单项的**顺序与显隐**可配置,见上「导航顺序与显隐」)。
- **表格列显示 / 隐藏 / 顺序**:各页列配置为固定 `computed`。
- **货币 / 金额格式**:无货币偏好。
- **独立日期格式**:仅由语言 `locale` 间接驱动 Naive UI 日期本地化,无单独偏好。
- **全局分页大小**:仅收支列表的 `pageSize` 持久化;日志、规则、邮箱账单等页面分页大小不持久化。
- **IndexedDB / cookie**:未使用。
- **Pinia 持久化插件 / vueuse `useStorage`**:未安装、未使用。
@@ -214,8 +258,9 @@
新增一项用户界面偏好时:
1. 存储键以 `finance.` 前缀命名,按页面/模块分段(如 `finance.transaction.xxx`)。
2. 优先用 `watch` 自动保存,避免要求用户手动点保存。
3. 读取时对取值做白名单校验,非法或损坏数据回退默认项。
4. 写入包 `try/catch`,忽略存储异常。
5. 需要跨设备一致时,改存后端并按当前用户隔离,而非 `localStorage`。
1. 存储键常量集中登记在 `frontend/src/utils/storageKeys.ts` 的 `STORAGE_KEYS`,以 `ledgerly.` 前缀命名、按页面/模块分段(如 `ledgerly.transaction.xxx`);涉及改名时在 `LEGACY_STORAGE_KEYS` 登记旧键并用 `migrateKey` 迁移。
2. 读写统一经 `frontend/src/utils/storage.ts`,**禁止**在业务代码中直接调用 `localStorage`/`sessionStorage`。
3. 优先用 `watch` 自动保存,避免要求用户手动点保存。
4. 读取时对取值做白名单校验,非法或损坏数据回退默认项;写入包 `try/catch`,忽略存储异常。
5. 组件内的字符串型偏好用 `useStringPreference`,关键词历史用 `useKeywordHistory`,浮窗位置尺寸用 `FloatingPanel`(键经 `storageKey` 传入)。
6. 需要跨设备一致时,改存后端并按当前用户隔离,而非 `localStorage`。