# liangqi-app **Repository Path**: PharaohMan/liangqi-app ## Basic Information - **Project Name**: liangqi-app - **Description**: 两讫 · 本地优先的通用记账 Web App,支持赊账、负债、还款、共享账本与 PWA。GPL-3.0-or-later。 - **Primary Language**: Unknown - **License**: AGPL-3.0 - **Default Branch**: master - **Homepage**: https://arksc.cn:8002/workbook/ - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-11-01 - **Last Updated**: 2026-11-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 两讫 · Liangqi > 银货两讫,账目两清。 **语言:** **简体中文** · [繁體中文](README.zh-TW.md) · [English](README.en.md) · [日本語](README.ja.md) · [한국어](README.ko.md) · [Español](README.es.md) · [Français](README.fr.md) · [Deutsch](README.de.md) · [Português](README.pt.md) · [Русский](README.ru.md) **在线使用:** https://arksc.cn:8002/workbook/ **源码仓库:** [Gitee](https://gitee.com/PharaohMan/liangqi-app) · [GitHub](https://github.com/yejunhui/liangqi-app) **开源协议:** AGPL-3.0-or-later · **AI / 开发上下文:** [AGENTS.md](AGENTS.md) 两讫是一个**本地优先、可连接远程仓库**的记账 Web App,专门把两类支出分开: - **现金支出**:现在就从存款里扣。 - **赊账支出**:现在不动存款,只增加负债,之后还款。 默认情况下数据只保存在本机,可以放多个账本;连接 GitHub、Gitee 或 WebDAV 后,一个仓库保存一本共享账,多个成员共用同一个仓库。连接远程时优先使用远程数据,离线自动回退本地。 ![两讫首页](docs/screenshots/dashboard.png) ## 它解决什么问题 大多数记账 App 只记录「花了多少」,但现实里经常是: > 这顿饭是刷信用卡的,钱还没从银行卡扣,但支出已经发生了。 两讫把这件事拆成三笔逻辑: | 操作 | 资产 / 存款 | 负债 | 支出 | | --- | ---: | ---: | ---: | | 现金消费 | −100 | 0 | +100 | | 赊账消费 | 0 | +100 | 0 | | 还款 | −100 | −100 | +100 | | 借款到账 | +100 | +100 | 0 | 关键点: - 赊账消费只增加负债、不动存款,**消费当时不计支出**;还款时再按还款金额计入支出。 - 还款是「资产 → 负债」的转移,同时确认还款当期的支出。 - 净资产 = 资产合计 − 负债合计。赊账消费会增加负债,所以净资产在消费时已经下降;还款不会改变净资产。 ## 功能 - **多账本**:本地书库可以放家庭账、旅行账、生意账等多个账本,随时切换。 - **资产 / 负债账户**:现金、银行卡、信用卡、花呗、借款等,支持期初余额;资产账户可标记是否计入「可支配资产」。 - **资产概览**:总资产、总负债、可支配、净资产。 - **两种支出方式**:现在扣存款,或先记负债生成待还账单。 - **账单管理**:账单名称、分类、到期日、部分还款、已还清状态。 - **还款**:从资产账户还款,自动减少负债和存款,并在还款时计入支出。 - **账户转账**:现金、银行卡等资产账户之间互转,只改变余额,不计入收支和预算。 - **成员归属**:每个账单和流水可以归属到家庭成员,账单卡片和流水里都会显示成员。 - **标签与标签组**:内置「生活场景 / 费用用途 / 关联对象」日常标签,跨分类标记流水和账单;标签组支持单选或多选,也可以随时添加自己的标签。 - **两级分类**:支出 / 收入分类都可以设置父分类,例如「餐饮 / 午餐」,统计和预算会包含子分类。 - **预算**:按月度或年度设置分类、标签、成员预算,首页显示进度,超支提醒;支持根据最近 3 个月支出生成智能预算建议。 - **周期记账**:房租、工资、订阅等按天 / 周 / 月 / 年自动生成流水,支持暂停和立即补记。 - **CSV 导入**:微信、支付宝、银行 CSV,自动识别列、预览并导入;支持按分类名称匹配。 - **多币种记账**:记账时可选外币,自动获取实时汇率,也可以手动修改;按本位币保存余额和统计,同时保留原始金额。 - **附件**:流水和账单可以添加小票、发票、截图;文件保存在本机 IndexedDB,并可在同步时上传到远程仓库,其他设备打开时按需下载,最大 10 MB。 - **智能记账**:输入或说一句「昨天午饭 35 现金」,自动识别金额、分类、账户、日期;语音使用浏览器 Web Speech。可以在设置里连接 OpenAI 兼容接口,用 AI 解析更复杂的一句话。 - **AI 助手**:连接到 OpenAI 兼容接口后,可以基于当前账本的本月收支、12 个月趋势、分类、标签、成员、预算和待还账单进行对话分析、预算建议和年度总结。 - **位置与地图**:流水可以记录当前位置,并在「分析 → 消费足迹」用 OpenStreetMap 查看地点分布。 - **批量修改**:在流水页进入批量模式,多选后统一修改分类、成员或标签,适合整理导入的账单。 - **本地密码**:可设置本地密码锁,PBKDF2 哈希保存在本机,打开应用时需要解锁。 - **统计**:净资产、本月支出、本月收入、待还总额、逾期金额、分类占比、7 天走势、预算进度;独立「分析」页提供 6 个月趋势、标签 / 成员分布、大额支出、多维筛选和可保存的自定义分析视图。 - **报表导出**:分析页可以导出当前筛选结果的 CSV(Excel 可直接打开),也可以生成并打印 PDF 月报。 - **分类管理**:支出 / 收入分类,支持自定义名称、Emoji、颜色和父分类。 - **PWA**:可安装到桌面 / 手机主屏幕,Service Worker 缓存应用外壳,离线可打开。 - **远程数据源**:GitHub、Gitee、WebDAV;**一个仓库对应一本共享账**,不同用户连接同一个仓库就会进入同一本账。 - **多用户与作者权限**:多个人可以共用同一个 GitHub / Gitee 私钥(Token)连接同一个仓库;连接后在登录页选择成员并输入密码。共享账本强制成员密码,成员密码的 PBKDF2 哈希会随成员信息写入仓库 `meta.json`。登录后必须通过「切换用户 / 锁定」退出,再回到成员列表重新登录;流水和账单记录该成员为作者,其他人只能查看,不能修改或删除他人的记账。成员列表会同步到仓库。 - **增量合并**:同步时按流水 / 账单 id 合并双方新增内容,同一记录按字段更新时间做字段级合并;删除使用墓碑记录,避免多人同步时把对方新增的账覆盖掉。 - **快捷指令 / 个性化**:支持 `#/quick?text=...` URL 快速记账、剪贴板粘贴、自定义 CSS、N 记一笔 / Q 一句话记账快捷键。 - **本地优先 + 远程优先读取**:本地立即写入;连接远程后打开账本优先拉远程,离线自动用本地。首页右上角的云图标显示当前同步状态:本地账本、待同步、同步中、已同步、离线或同步失败;点击可进入数据源页查看详情。 - **增量同步**:先读 manifest 判断远程是否有变化,没有变化时跳过 meta 和全部分片;拉取时按分片哈希复用本机缓存,上传只写哈希变化的分片。 - **冲突备份**:远程覆盖本地时,被覆盖版本保存在本机,可下载 JSON。 - **备份**:单账本 JSON、整个书库 JSON;GitHub / Gitee 仓库本身保留提交历史。 - **多语言**:界面支持简体中文、繁體中文、English、日本語、한국어、Español、Français、Deutsch、Português、Русский;首次打开按浏览器语言选择,也可以在「设置 → 界面语言」切换。语言只保存在本机,不写入共享账本;金额、日期和报表会跟随语言格式化。 - **深色模式**:浅色、深色、跟随系统。 - **响应式**:桌面端侧边栏,手机端底部导航和底部弹层。 | 账单 | 流水 | | --- | --- | | ![账单页](docs/screenshots/bills.png) | ![流水页](docs/screenshots/entries.png) | | 账户 | 手机端 | | --- | --- | | ![账户页](docs/screenshots/accounts.png) | 手机端首页 | | 数据源 | | | --- | --- | | ![数据源页](docs/screenshots/data-source.png) | 本地 / GitHub / Gitee / WebDAV 四种模式 | ## 远程仓库结构 一个仓库只保存一本共享账: ```text repo/ └── liangqi/ ├── meta.json # 账户、分类、标签、预算、周期规则、成员、设置、账本信息、删除墓碑 ├── manifest.json # 分片清单、哈希、条数 ├── entries-0.json # 第 0–999 条流水 ├── entries-1000.json # 第 1000–1999 条流水 ├── bills-0.json # 账单分片 └── attachments/ # 附件文件(base64 JSON,按需下载) ``` 每个分片默认 1000 条。`manifest.json` 记录每个分片的起始位置、条数和内容哈希。 旧版多账本布局(`liangqi/index.json` + `liangqi/books//`)仍然可以读取;第一次同步后会写入新的单账本根布局。旧版单文件 `books/.json` 也保留读取兼容。旧版仓库如果包含多本账,只迁移当前绑定的那一本,其他账本仍留在仓库里但不会出现在新的共享账列表中。 多个人可以共用同一个私钥连接同一个仓库。连接后,每个用户在登录页选择自己的成员并输入密码;新流水和账单会把该成员写成作者。成员列表和成员密码哈希保存在账本的 `meta.json` 中,会随远程同步,所有设备可见。共享账本的成员必须有密码。登录后不能直接点选其他成员;必须点「当前记账成员 → 切换用户 / 锁定」,退出到登录页。锁定和切换用户都会回到成员列表;上次登录的成员排在第一位,也可以选择其他成员,再输入密码登录。新建流水、账单和周期记账时,成员归属默认使用当前登录成员。 ## 同步规则 - **本地立即写**:每次修改先写浏览器 IndexedDB,界面立刻更新;localStorage 作为兜底镜像。 - **增量拉取**:先读 `manifest.json` 判断远程是否有变化,没有变化时跳过 meta 和全部分片;拉取时按分片哈希复用本机缓存。 - **自动推送**:本地修改后延迟约 1.8 秒推送到远程;失败不阻塞记账。 - **分片上传**:只上传内容哈希发生变化的分片;GitHub 通过 Git Data API 把多个分片合并成一次 commit,Gitee / WebDAV 按文件写入。 - **逐条合并**:同步时把远程和本地的流水、账单按 id 合并,双方新增都会保留;同一 id 的标题、备注、分类、成员、标签、附件等字段按 `fieldUpdatedAt` 逐字段取舍。 - **删除墓碑**:删除流水 / 账单时写入 `deletedEntries` / `deletedBills` 墓碑,删除账户 / 分类 / 标签 / 成员 / 预算 / 周期规则 / 附件时写入 `deletedConfig`,其他设备同步后一起删除,不会因为对方还持有旧副本而复活。 - **作者保护**:流水、账单、周期规则和附件记录作者 id。非作者只能查看,不能修改或删除;还款、新增流水不受影响。 - **共享配置**:账户、分类、标签、成员、预算、周期规则、附件等是账本级共享配置,按 id 合并;账户、分类、标签等重复 id 以远程版本为准,成员按 `updatedAt` / `fieldUpdatedAt` 逐字段合并,避免旧副本覆盖新密码。并应用共享配置墓碑。 - **冲突备份**:实际写入前如果发现本地和远程都有修改,会先保存一份本地版本到「数据源 → 冲突备份」,最多 10 份。 - **离线回退**:远程不可用时继续使用本地,恢复后自动合并并补推。 ## 部署形态 完整、面向普通用户的部署步骤见 **[docs/deployment.md](docs/deployment.md)**,包括: - 直接使用在线地址和安装 PWA - Netlify Drop / Cloudflare Pages / Gitee Pages - Nginx + HTTPS 自建部署 - 共享账连接、成员登录和备份 - 常见问题排查 简要说明: - **纯静态前端**:`pnpm build` 产出 `dist/`,可部署到 Cloudflare Pages、GitHub Pages、Netlify 等;没有数据库、没有 API 服务。 - **完全无后端**:连接 GitHub / Gitee 只需要「仓库名 + 私钥」,或使用 WebDAV;不需要 OAuth 服务。 - **OAuth Worker(可选,当前界面未启用)**:`server/oauth-worker` 代码仍保留,但当前连接界面只使用私钥。 - **WebDAV 注意**:浏览器直连要求服务器允许 CORS;不支持 CORS 的 WebDAV 需要额外代理,那种情况下才需要后端。 ### 部署到子路径 ```bash # 生成 /workbook/ 前缀的静态文件 pnpm build:workbook ``` Nginx 示例: ```nginx location = /workbook { return 301 /workbook/; } location /workbook/ { root /var/www; try_files $uri $uri/ /workbook/index.html; index index.html; } ``` 也可以使用 `scripts/deploy-workbook.sh`,通过 `DEPLOY_HOST` / `DEPLOY_USER` / `DEPLOY_PATH` 部署并在远端 reload nginx。SSH 需要预先配置好密钥或 ssh-agent。 ## 登录方式 ### 仓库名 + 私钥 GitHub / Gitee 只需要两个字段: - **仓库名**:可以写 `family-ledger`,也可以写 `your-name/family-ledger` - **私钥 / Access Token**:GitHub 需要 `repo` 权限,Gitee 需要 `projects` 权限 如果仓库名只写了 repo,应用会用私钥读取账号并补全 owner。分支自动使用仓库默认分支,不需要填写。 私钥只保存在本机 `localStorage`,不会经过两讫的服务器。多个人可以共用同一个私钥;连接后在登录页选择自己的成员并输入密码。 ### OAuth Worker(当前界面未启用) `server/oauth-worker` 是 GitHub / Gitee OAuth code exchange 的参考实现;当前版本的连接界面只使用私钥,OAuth 代码保留但未接入按钮。 ### WebDAV 支持 Nextcloud、Alist、群晖等标准 WebDAV。填写地址、用户名、密码即可。WebDAV 服务器需要允许浏览器跨域访问(CORS),否则连接会失败。 ## 快速开始 要求 Node.js 22+ 和 pnpm。 ```bash pnpm install pnpm dev ``` 打开终端输出的地址(默认 `http://localhost:5173`)。 其他命令: ```bash pnpm test # 账务、备份、远程适配器测试 pnpm typecheck # TypeScript 类型检查 pnpm lint # oxlint pnpm build # 生产构建 pnpm preview # 预览构建结果 ``` ## 使用方式 1. 第一次打开会先进入「连接共享账本」:填写仓库名和私钥,或使用 WebDAV。连接成功后自动打开共享账,并进入成员登录页。连接信息保存在本机,下次打开直接选择成员登录;也可以选择「暂不连接,仅使用本地账本」。 2. 登录成员:选择自己的成员并输入密码。首次登录的成员会先设置密码;密码以 PBKDF2 哈希保存在共享仓库。 3. 打开首页后,点击左上角「当前账本」可以切换账本,点击「当前记账成员」可以查看当前成员、锁定或切换用户。 4. 到「账户」页设置资产账户的期初余额(例如银行卡里现在有多少钱)。 5. 记一笔支出时选择: - **现在扣存款**:从现金 / 银行卡支出。 - **先记负债**:记到信用卡 / 花呗,生成待还账单。 6. 到「账单」页查看待还金额和到期日,点「还款」从存款账户还款。 7. 到「数据源」页填写仓库名和私钥连接,打开共享账本,或把当前账本上传到空仓库。 8. 在「设置 → 数据管理」导出单账本或整个书库备份。 ### 标签、分类与预算 - 到「分类」页可以给支出 / 收入分类设置父分类,例如「餐饮 / 午餐」;选择父分类做预算时会自动包含子分类。 - 到「标签」页创建标签组和标签,记账、编辑账单、设置预算时都可以选择。新账本会自动带一组日常标签;旧账本第一次打开时也会补上,空标签页可以点「添加日常标签」。 - 到「预算」页按月度或年度设置金额,并圈定分类、标签或成员;首页会显示进度和超支提醒。 ### 分析 「分析」页可以按月查看收入、支出、结余和储蓄率,以及近 6 个月趋势、合并二级分类后的分类占比、标签支出、成员支出和大额支出。可以按分类、标签、账户、成员和关键词组合筛选,并把筛选保存成本机的分析视图。统计口径:现金支出立即计入,赊账只记负债,还款时计入支出;转账不计收支。页面底部还有「消费足迹」,按地点汇总带位置的支出,并嵌入 OpenStreetMap 地图。 ### 报表与快捷指令 分析页右上角可以导出当前筛选结果的 CSV(Excel 直接打开),也可以生成打印版月报,用浏览器「打印 → 保存为 PDF」得到 PDF。 iOS 快捷指令或自动化可以打开: ```text https://arksc.cn:8002/workbook/#/quick?text= ``` 打开后会直接进入「一句话记账」并预填内容。桌面端支持 N 记一笔、Q 一句话记账,可在设置中关闭;同时支持自定义 CSS。 ### 智能预算建议 到「预算」页点「智能建议」,应用会根据最近 3 个完整月份的分类平均支出,生成月度预算草案。可以勾选分类、修改金额,再一次性创建预算。 ### 批量修改 在「流水」页点「批量」,勾选多笔流水后可以统一修改分类、成员或标签。分类要求所选流水的类型一致;转账和还款不能修改分类。这个功能适合 CSV 导入后集中整理分类。 ### 周期记账 到「周期」页添加规则,选择支出 / 收入、账户、分类和频率(天 / 周 / 月 / 年)。启用的规则会在打开应用或同步后自动补记到期流水;也可以点「立即入账」手动补记。暂停后不会继续生成,删除规则会保留已经生成的流水。 ### CSV 导入 到「导入」页选择微信、支付宝或银行导出的 CSV。应用会自动寻找表头并猜测「交易时间 / 金额 / 收 / 支 / 分类 / 备注」列;确认预览后再导入。分类按名称匹配,匹配不到时使用你选择的默认分类;「不计收支 / 转账 / 还款」会跳过。 ### 多币种与附件 记账时可以切换币种,应用会先读取本机缓存,再向公开汇率源请求最新汇率;保存时会按当时的实时汇率换算成本位币。汇率源不可用或你手动改过汇率时,会使用当前显示的手动汇率。流水会同时保留外币原始金额和换算后的本位币金额,余额和统计统一使用本位币。流水和账单可以添加附件;附件文件保存在本机 IndexedDB,同步时会上传到仓库的 `attachments/` 目录,其他设备打开时按需下载。 ### 智能记账与位置 首页、侧边栏或手机顶部的麦克风按钮可以打开「一句话记账」,输入或说「昨天午饭 35 现金」。应用会在本机解析金额、分类、账户和日期,再打开表单让你确认。到「设置 → AI 助手」填写 OpenAI 兼容的 `/chat/completions` 地址、模型和 API Key 后,还可以点「AI 识别」处理更复杂的表达。记账表单里可以获取当前位置,位置会出现在「分析 → 消费足迹」。 ### AI 助手 配置好 AI 接口后,从侧边栏或「设置 → AI 助手」打开 AI 助手页。它会读取当前账本的聚合快照(资产、本月 / 上月 / 今年收支、近 12 个月趋势、分类、标签、成员、预算、待还账单和最近 25 条流水摘要),可以回答「这个月花在哪」「给我下个月预算建议」「总结今年」等问题。对话按账本保存在本机,可以随时清空。附件文件、精确位置、token 和密码不会发送给 AI。 ### 安装为 PWA 使用 HTTPS 打开应用后,浏览器会提示安装到桌面或主屏幕;也可以在浏览器菜单中选择「安装应用 / 添加到主屏幕」。安装后可以离线打开应用外壳,账本数据仍然保存在本机。iOS / Android 安装步骤和可选的 Capacitor 原生壳见 [docs/mobile.md](docs/mobile.md)。 ### 本地密码 到「设置 → 本地密码」设置至少 6 位密码。密码使用 PBKDF2-SHA256 哈希后保存在本机,打开应用或刷新新标签页时需要解锁;同一标签页刷新会保持解锁。 注意:**本地密码只保护界面访问,不加密 IndexedDB / localStorage 里的账本数据**。能打开浏览器开发者工具的人仍然可以读到本地数据;如果忘记密码,只能清除浏览器数据。 ### 成员 到「成员」页添加家庭成员。记账时在金额下方选择成员;赊账生成的账单会继承该成员,账单和流水列表都会显示成员标签。成员只影响归属和展示,不影响金额、余额和统计。 ### 可支配资产 首页资产卡显示四个数字: - **总资产**:所有资产账户余额之和。 - **总负债**:所有负债账户余额之和。 - **可支配**:流动资产之和,不扣减负债。现金、银行卡等默认计入流动资产;房产、投资等可以在账户编辑里关闭「计入可支配资产」。 - **净资产**:总资产 − 总负债。 可支配只反映手头可动用的钱;负债和净资产在另外两项中单独显示。期初余额只在创建账户时填写,之后不能修改;如果需要调整,请通过新增流水或还款处理。这是为了避免历史账目被悄悄改掉。 ## 数据与隐私 - 本地书库优先保存在浏览器 **IndexedDB**(`keyval-store` / `liangqi-library-v2`),同时保留 `localStorage` 镜像作为兜底。 - 旧版单账本 `liangqi-ledger-v1` / `zhaibu-ledger-v1` 会在首次启动时迁移到书库,旧键保留,方便回滚。 - 旧的 `zhaibu` 单账本备份仍可导入;新导出使用 `liangqi` 标识。 - 远程模式下,账本数据保存在你自己的 GitHub / Gitee 仓库或 WebDAV 服务器;两讫没有自己的数据服务器。 - 多用户共享账本时,流水 / 账单会记录公开的记账人 id 和显示名;token 不会写入远程账本。成员密码只写 PBKDF2 哈希、盐和迭代次数,不写明文。 - 当前每本账登录的成员保存在本机 `localStorage`(`liangqi-active-members-v1`),不会同步到远程;成员名称、颜色等资料保存在账本 `meta.json` 中。 - 成员密码只保存 PBKDF2 哈希、盐和迭代次数,不保存明文;成员密码哈希会随 `meta.json` 写入远程仓库,并在成员合并时按字段更新时间保留较新的密码。共享账本的成员必须有密码,解锁状态只保存在当前标签页的 `sessionStorage`(`liangqi-unlocked-members-v1`)。锁定或新会话打开后需要重新输入。 - 作者权限在应用内校验:其他协作者在界面上只能查看你的记账,不能修改或删除。拥有仓库写权限的人仍然可以通过 Git 工具直接改文件,因此这里的权限是应用层而不是服务端强制。 - OAuth Worker 只做 code exchange,不存储账本数据。 - **Token / 密码保存在本机 `localStorage`**,以便刷新后保持连接;请使用细粒度、单仓库权限的 token。 - **AI API Key 保存在本机 `localStorage`(`liangqi-ai-v1`)**,AI 请求由浏览器直接发往你配置的接口,不经过两讫服务器;不使用 AI 时不会发起任何外部请求。地图使用 OpenStreetMap 嵌入页面,加载时会访问 openstreetmap.org。 - AI 对话记录按账本保存在本机 `localStorage`(`liangqi-ai-chat-v1:`),不会同步到远程;可以在 AI 助手页清空。每次 AI 请求会发送账本聚合摘要和最近 25 条流水摘要,不发送附件文件、精确位置、token 或密码。 - 切换外币时,浏览器会向你网络可达的公开汇率源请求汇率(默认依次尝试 currency-api / open.er-api.com),请求只包含币种代码,不包含账本内容;汇率缓存保存在本机 `liangqi-fx-rates-v1`。 - **清除浏览器数据会丢失本地书库**。请定期导出备份;已连接远程的数据可以从远程重新拉取。 - 本地密码哈希保存在 `liangqi-auth-v1`;解锁状态只保存在当前标签页的 `sessionStorage`。 - 本地密码不加密账本数据,不能替代磁盘加密或浏览器账户保护。 - 书库备份默认**不包含 token / 密码**,导入后需要重新填写远程凭据。 - 冲突备份保存在 `liangqi-conflicts-v1`,可在数据源页下载或清空。 - 远程分片缓存保存在 IndexedDB `liangqi-remote-chunks`,按内容哈希复用未变化的分片,避免重复下载。 - 附件文件保存在 IndexedDB 的 `liangqi-attachments`,同步后还会上传到远程仓库的 `liangqi/attachments/`;最大 10 MB。其他设备打开时会按需从远程下载。支持批量适配器的设备删除附件时会顺带清理远程文件;WebDAV / Gitee 可能留下孤儿文件。 - PWA Service Worker 只缓存应用外壳和静态资源,不会缓存或上传账本数据。 ## 技术栈 - React 19 + TypeScript - Vite 8 - Tailwind CSS 4 - Zustand(书库 + 当前账本状态) - IndexedDB(`idb-keyval`,本地主存储) - React Router 7(HashRouter,静态托管无需服务端重写) - Web Speech API(浏览器语音识别,可选) - OpenAI 兼容接口(可选 AI 解析) - OpenStreetMap 嵌入地图(可选) - Vitest(账务、备份、远程适配器测试) - Lucide React(界面图标,ISC 许可) - Cloudflare Worker(可选 OAuth 服务,`server/oauth-worker`) 金额全部以**整数分**存储,计算过程中不使用浮点数,避免 `0.1 + 0.2` 类问题。 ## 项目结构 ```text src/ ├── domain/ │ ├── ledger.ts # 账户余额、账单状态、统计等纯函数 │ ├── budgets.ts # 预算范围与进度 │ ├── recurring.ts # 周期日期推进与到期计算 │ ├── csv.ts # CSV 解析、列识别和交易标准化 │ ├── quick-entry.ts # 一句话记账的自然语言解析 │ ├── ai.ts # OpenAI 兼容请求与 AI 快速记账 │ ├── ai-context.ts # 给 AI 的账本聚合快照 │ ├── exchange-rates.ts # 实时汇率、缓存与手动兜底 │ ├── filters.ts # 多维流水筛选 │ ├── member-pin.ts # 成员密码哈希与验证 │ ├── merge.ts # 多人账本的逐条合并、墓碑和作者认领 │ ├── reports.ts # CSV / PDF 月报 │ ├── budget-suggestions.ts # 最近 3 个月预算建议 │ ├── member-session.ts # 当前登录成员与每本书的本地身份 │ ├── analysis-views.ts # 本机保存的自定义分析视图 │ ├── attachments.ts # 附件元数据与 IndexedDB 文件存储 │ ├── money.ts # 金额解析与格式化 │ ├── backup.ts # 单账本 / 书库备份与校验 │ └── seed.ts # 默认账户、分类和账本 ├── remote/ │ ├── chunks.ts # 分片、哈希、manifest │ ├── chunk-cache.ts # 按哈希缓存远程分片 │ ├── attachments.ts # 附件 base64 远程上传 / 下载 │ ├── git-contents.ts # GitHub / Gitee;GitHub 使用 Git Data API 批量提交 │ ├── webdav.ts # WebDAV GET / PUT / MKCOL │ ├── repository.ts # 单账本 meta.json + manifest + 分片 │ ├── sync.ts # 拉取、合并、推送、冲突处理 │ └── oauth.ts # OAuth 弹窗 ├── store/ │ ├── library.ts # 书库、账本列表、连接配置 │ ├── ledger.ts # 当前账本 + 账务 / 成员 actions │ ├── auth.ts # 本地密码 │ ├── book-actions.ts # 切换 / 新建 / 删除账本 │ └── ui.ts # 全局弹层状态 ├── pages/ # 首页、流水、账单、账户、分类、标签、预算、分析、AI 助手、周期、导入、成员、数据源、设置 ├── components/ # 布局、账本切换、弹层、卡片、图表等 ├── i18n/ │ ├── index.ts # 语言检测、切换、t() 与占位符 │ ├── en.ts # 英文翻译(中文源文案作为 key) │ ├── ja.ts / ko.ts / es.ts / fr.ts │ ├── de.ts / pt.ts / ru.ts │ └── zh-TW.ts # 繁體中文 ├── hooks/ ├── utils/ └── types.ts # 数据模型 server/ └── oauth-worker/ # 可选 GitHub / Gitee OAuth Worker ``` ### 多语言 - 界面语言保存在本机 `localStorage`(`liangqi-language-v1`),不会写入共享账本。 - 首次打开按浏览器语言选择,也可以在「设置 → 界面语言」切换。 - UI 文案使用 `t("中文源文案", [参数])`,占位符写作 `{0}`、`{1}`;翻译包在 `src/i18n/<语言>.ts`,key 是中文源文案。缺少目标语言翻译时回退英文,再回退中文。 - 语言包按需动态加载,不会让首屏加载所有翻译。 - 日期、金额、报表和语音识别语言会跟随当前语言格式化。 - README 提供 10 种语言版本,可从文档顶部的语言选择器切换。 核心数据模型在 `src/types.ts`: - `Library`:多个 `Book` + 当前账本 + 远程连接配置。 - `Book`:账户、分类、标签组、标签、预算、周期规则、附件、删除墓碑、成员、账单、流水、币种、远程绑定。 - `Account`:`asset` 或 `liability`,带期初余额;资产可标记 `liquid` 是否计入可支配资产。 - `Member`:账单和流水的归属成员,也是共享账里的登录身份和记账作者。 - `Category`:支出 / 收入分类,可通过 `parent` 组成两级分类。 - `TagGroup` / `Tag`:标签组定义单选或多选,标签可跨分类标记流水和账单。 - `Budget`:月度 / 年度预算,可按分类(含子分类)、标签、成员筛选支出。 - `RecurringRule`:周期记账规则,保存频率、下次日期、账户和分类。 - `Attachment`:附件元数据;文件二进制保存在本机 IndexedDB。 - `Bill`:一张待还账单,记录本金、到期日、成员、标签、附件、作者;还款金额由流水推导。 - `Entry`:`expense` / `income` / `repayment` / `transfer`,支出和还款通过 `billId` 关联账单,转账通过 `toAccountId` 关联转入账户,可关联成员、标签、附件、位置、外币原始金额和作者。 - `Tombstone`:删除墓碑,记录被删除流水 / 账单 id、时间和作者,用于多端合并。 余额、账单剩余金额和统计结果都是**推导值**,不单独存一份余额,避免数据不同步。 ## 路线图 - [ ] S3 兼容存储 - [ ] SQLite 备份快照 - [ ] 操作日志 / 墓碑压缩 / 断点续传 - [ ] 分期还款计划 - [ ] 真实 GitHub / Gitee / WebDAV 双用户联调 - [ ] 账户级多币种与历史汇率重估 - [ ] 原生 iOS / Android 壳(可选,Capacitor) - [ ] 更完整的组件测试与端到端测试 ## 扫码使用 手机扫码打开在线版: 扫码使用两讫 ## 支持项目 如果两讫对你有帮助,欢迎使用支付宝或微信扫码支持后续开发。 | 支付宝 | 微信 | | --- | --- | | 支付宝赞赏码 | 微信赞赏码 | ## 许可证 本项目以 **GNU Affero General Public License v3.0 or later(AGPL-3.0-or-later)** 发布,完整文本见 [LICENSE](LICENSE)。 - 你可以自由使用、修改和分发本程序。 - 分发修改版时,必须向接收者提供对应源码和许可证文本。 - 如果你修改本程序并通过网络向用户提供服务,必须按 AGPL 第 13 条向这些用户提供对应源码。 - 更早的版本曾以 GPL-3.0-or-later 发布;已经发布的授权无法撤回,从当前版本起使用 AGPL-3.0-or-later。 ### 品牌与素材 「两讫 / LIANGQI」名称和双栏 Logo 为本项目原创。原创代码、文档和图片按 AGPL-3.0-or-later 授权;名称和 Logo 是商标,AGPL 不授予商标权。界面图标使用 Lucide(ISC 许可)和系统 Emoji,不包含第三方应用的图标、文案或截图素材。 名称与 Logo 尚未做正式的商标注册检索;如果计划商业发行,请在目标国家 / 类目自行做商标查询。本项目不声称拥有任何注册商标。 第三方依赖与图标的许可证见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。 ## License Liangqi is released under the **GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later)**. See [LICENSE](LICENSE) for the full text. If you modify Liangqi and make it available to users over a network, section 13 of the AGPL requires you to offer those users the Corresponding Source of your modified version. Earlier releases were published under GPL-3.0-or-later. Those grants remain valid; this version and later releases use AGPL-3.0-or-later. ## 免责声明 本项目是记账工具,不构成财务、税务或投资建议。使用前请先导出备份;作者不对因数据丢失、计算错误或使用本软件造成的损失负责。 ## 更多建议请给我们发邮件吧 junhuiye@foxmail.com 1589082159@qq.com