Actual Budget 26.4.0 发布详解:同日交易拖拽排序、同心圆环图、Payee 位置实验与 Actual CLI
2026/9/11 23:43:57 网站建设 项目流程

Actual Budget 26.4.0 发布详解:同日交易拖拽排序、同心圆环图、Payee 位置实验与 Actual CLI

【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actual

Actual(actual,一个 local-first 的个人财务管理应用)在 2026 年 4 月发布了 v26.4.0。本次版本延续了 Actual 一贯"高频迭代、体验优先"的节奏,除了大量 Bug 修复与依赖维护外,还带来了一批直接影响日常记账体验的功能:同日交易的拖拽排序、报表模块的同心圆环图(Concentric Donut)、更聪明的支付对象/分类自动补全算法,以及两个重量级实验特性——Payee Locations(按地理位置推荐收款人)Actual CLI(命令行访问预算数据)。本文以发布说明(packages/docs/blog/2026-04-06-release-26-4-0.md)为骨架,结合仓库源码逐项拆解这些能力的实现原理与使用方式,帮助读者快速评估是否升级,并掌握新特性的正确打开方式。

版本信息:Docker Tag26.4.0,Versionv26.4.0,发布于 2026-04-05。

升级前必读:本次版本带来的四个核心变化

类别能力定位
新功能同日交易拖拽排序正式特性
新功能同心圆环图(分类组外环)正式特性
增强支付对象/分类自动补全分层排序算法正式特性
实验特性Payee Locations(按地点推荐支付对象)Experimental
实验特性Actual CLI(命令行预算工具)Experimental,文档入口见 packages/cli/README.md

其中,拖拽排序、同心圆环图与自动补全升级属于"打开即用"的体验改进;两个实验特性则需要用户主动在设置中开启或按文档单独部署,下面分章节深入。

同日交易的拖拽排序:更符合直觉的记账顺序调整

功能背景

在个人记账中,同一天的交易先后顺序往往有实际含义(例如"先消费、后报销")。此前 Actual 调整同一天内交易顺序的方式不够直观;v26.4.0 引入了拖拽排序能力:当多笔交易共享同一天(date)时,可以直接用鼠标拖动调整它们的展示与结算顺序。

源码中的实现证据

该功能由 PR #6653 合入,核心改动位于桌面客户端交易表格相关组件中。从仓库结构看,交易表格的渲染与交互集中在 packages/desktop-client/src/components/transactions 目录,拖拽能力依赖同一日期分组内的行重排,而排序结果最终会写回交易数据,随 Actual 的 CRDT 同步机制传播到其他设备。

使用要点

  • 仅当多笔交易日期完全相同时才可拖拽重排,这是设计上为了避免与跨日排序逻辑冲突;
  • 拖拽排序后请观察排序字段的变化——排序会持久化到该日期分组内;
  • 若配合"显示运行余额(running balance)"使用,重排会实时影响余额计算链路。

同心圆环图:自定义报表中的分类组外环

功能背景

Actual 的报表模块此前以单层环形图(Donut)为主。v26.4.0 引入同心圆环图(Concentric Donut):内环展示分类(category)的占比,外环展示对应分类组(category group)的聚合占比,让用户在一个图里同时看到明细与分组结构,适合预算分析、支出结构复盘等场景。该能力仅用于自定义报表(Custom Reports)

源码实现解析

实现集中在 packages/desktop-client/src/components/reports/graphs/DonutGraph.tsx:

  • 图组件基于 Recharts 的 PieChart 叠加多个环,通过outerRadius(外半径)与chartInnerRadius(内半径)参数控制同心环的层叠关系;
  • 分类组外环通过计算聚合值得到,报表配置层(如 ReportOptions.ts)决定内环与外环的数据维度;
  • 图例与 Tooltip 也随同心结构做了适配,选中内环可联动高亮对应的外环分段。

使用要点

  1. 进入报表 → 新建/编辑自定义报表
  2. 图表类型选择"环形图(Donut)",并开启分类组外环(Concentric)选项;
  3. 内环按分类展示,外环按分类组聚合展示;
  4. 若数值较大导致内环拥挤,可配合本次同步修复的"预算分析报表 padding 优化"(PR #7118)获得更好的排版。

更聪明的自动补全:分层排序的分支补全算法

功能背景

支付对象(payee)与分类(category)下拉框是 Actual 最高频的交互入口。此前补全结果排序相对简单;v26.4.0 引入**分层排序(tiered ranking)**算法(PR #6972),显著提升命中率——输入关键词时,名称本身命中的结果排在"仅组名命中"的结果之前,并且补全时保持大小写不敏感。

源码实现解析

以分类补全为例,排序逻辑位于 packages/desktop-client/src/components/autocomplete/filterCategorySuggestions.ts:

  • 使用fzf模糊匹配库对候选做评分(rankMatches),limit: 100casing: 'case-insensitive'
  • 第一层:按item.name(分类名)直接匹配并排名;
  • 第二层:对未命中第一层的候选,按item.group.name + ' ' + item.name(组名+分类名拼接)再次匹配排名;
  • 最终结果 = 分类名命中 + 组名命中,截取前 100 条,并把特殊的split(拆分交易)入口固定在首位。

同样的算法也应用于支付对象补全(autocomplete 目录下的PayeeAutocompleteCategoryAutocomplete等),配合针对"账户"场景的过滤逻辑共同工作。配套测试见 filterCategorySuggestions.test.ts,其中明确断言"分类名命中应排在仅组名命中的结果之上"。

使用要点

  • 直接输入分类或支付对象关键词即可体验新排序,无需任何配置;
  • 分类名优先、组名兜底的设计,意味着输入"Food"时,名为 Food 的分类会排在"Food & Drink 组"其他分类之前;
  • 本次同步修复了移动端补全"需点两次才能选中"的 Bug(PR #7166),移动端体验一并改善。

实验特性一:Payee Locations——基于地理位置的支付对象推荐

功能背景

这是 v26.4.0 引入的实验特性(MVP):Actual 会记住你在某地使用过的支付对象(payee),此后当你身处附近时,在新增交易时优先推荐附近用过的支付对象。典型场景是线下消费——你在同一商圈反复消费的商户,会被智能地优先提示。该能力同时支持YNAB5 数据导入(PR #6157)。

数据模型与迁移

位置数据由新迁移 1768872504000_add_payee_locations.sql 引入payee_locations表:

CREATE TABLE IF NOT EXISTS payee_locations ( id TEXT PRIMARY KEY, payee_id TEXT, latitude REAL, longitude REAL, created_at INTEGER, tombstone INTEGER DEFAULT 0 );

并配套三个索引:

  • idx_payee_locations_payee_id:按支付对象快速查找;
  • idx_payee_locations_tombstone_payee_created:时间维度查询(按tombstone, payee_id, created_at复合索引);
  • idx_payee_locations_geo_tombstone:地理空间复合索引(tombstone, latitude, longitude),服务于"附近支付对象"查询。

删除采用软删除(tombstone标记),与 Actual 同步模型保持一致。

服务端 API 与距离计算

服务端实现在 packages/loot-core/src/server/payees/app.ts,暴露了 4 个新方法:

方法说明
payee-location-create记录一条位置(payeeId + latitude + longitude
payee-locations-get查询某支付对象的位置(可按payeeId过滤,按created_at倒序)
payee-location-delete软删除一条位置
payees-get-nearby查询附近支付对象

关键设计点:

  • 坐标校验createPayeeLocationgetNearbyPayees都会校验经纬度范围(纬度 -90~90,经度 -180~180),非法坐标直接抛错;
  • 默认半径getNearbyPayees的默认maxDistance来自 packages/loot-core/src/shared/constants.ts 中的DEFAULT_MAX_DISTANCE_METERS = 500,即默认检索 500 米范围内的支付对象;
  • Haversine 距离:附近查询使用 Haversine 公式计算球面距离(单位米),并用 SQL 窗口函数ROW_NUMBER() OVER (PARTITION BY payee_id ORDER BY distance)为每个支付对象只保留最近的一条位置distance_rank = 1),最终按距离升序返回最多 10 条
  • 返回结果同时携带支付对象实体与其最近位置(含distance字段)。

开启与使用

由于是实验特性,需要在 Actual 的"实验功能"设置中开启对应开关(后续版本可能调整入口,以实际界面为准)。启用后:

  1. 系统会在交易发生地自动(或按提示)记录支付对象位置;
  2. 在新交易输入支付对象时,若当前坐标附近存在历史支付对象,候选列表会优先展示它们;
  3. 从 YNAB5 导入的数据若包含位置信息,会一并写入(导入实现在 packages/loot-core/src/server/importers/ynab5.ts)。

注意:位置数据涉及隐私,开启前请确认你接受 Actual 在本地存储经纬度信息;该数据随预算文件同步,仅保存在你自己的服务端。

实验特性二:Actual CLI——用命令行访问你的预算

功能背景

Actual CLI(PR #7208)是 v26.4.0 最受关注的新工具:一个独立的命令行程序,用于查询和修改预算数据——账户、交易、分类、支付对象、规则、日程、标签等。发布说明特别指出它"对 AI Agent 非常有用",因为它允许脚本和 Agent 以结构化方式与预算交互。

安装与快速开始

CLI 以独立 npm 包发布(packages/cli),需要 Node.js >= 22:

npm install -g @actual-app/cli

CLI 连接的是运行中的 Actual sync server(不会直接操作本地预算文件)。快速开始:

# 配置连接信息 export ACTUAL_SERVER_URL=http://localhost:5006 export ACTUAL_PASSWORD=your-password export ACTUAL_SYNC_ID=your-sync-id # 在 设置 → 高级 → Sync ID 中获取 # 列出账户 actual accounts list # 查询余额 actual accounts balance <account-id> # 查看某月预算 actual budgets month 2026-03

配置体系:优先级与环境变量

配置解析优先级从高到低:CLI flags → 环境变量 → 配置文件(cosmiconfig)→ 默认值。核心环境变量如下:

变量说明
ACTUAL_SERVER_URLActual sync server 地址(必填)
ACTUAL_PASSWORD服务端密码(使用 token 时可省略)
ACTUAL_SESSION_TOKEN会话 Token(密码的替代方案)
ACTUAL_SYNC_ID预算 Sync ID(多数命令必填)
ACTUAL_DATA_DIR本地缓存目录
ACTUAL_CACHE_TTL缓存 TTL(秒),默认 60
ACTUAL_LOCK_TIMEOUT预算目录锁等待超时(秒),默认 10
ACTUAL_NO_LOCK设为1时禁用目录锁

配置文件支持.actualrc(JSON/YAML)、.actualrc.json/.yaml/.ymlactual.config.*package.json中的"actual"键,以及全局配置目录(如 Linux 的~/.config/actual/)下的config系列文件。示例 packages/cli/README.md:

{ "serverUrl": "http://localhost:5006", "password": "your-password", "syncId": "1cfdbb80-6274-49bf-b0c2-737235a4c81f", "cacheTtl": 60, "lockTimeout": 10, "noLock": false }

安全提醒:不要在配置文件里存明文密码;优先使用ACTUAL_PASSWORD/ACTUAL_SESSION_TOKEN环境变量或会话 Token,若必须写入文件请设置 600 权限并加入.gitignore

全局 Flags 与常用命令

全局 Flags 与 README 完全对应(--server-url--password--session-token--sync-id--data-dir--cache-ttl--refresh/--no-cache--lock-timeout--no-lock--format(json/table/csv)、--verbose),这些选项在 packages/cli/src/index.ts 中通过 Commander 注册,且支持从ACTUAL_ENCRYPTION_PASSWORD读取端到端加密密码。

支持的命令族(每个命令可用actual <command> --help查看子命令):

命令说明
accounts账户管理
budgets预算与分配管理
categories/category-groups分类 / 分类组管理
transactions交易管理
payees支付对象管理
tags标签管理
rules交易规则管理
schedules日程交易管理
query运行 ActualQL 查询
server服务端工具与 ID 查询
sync刷新/检查本地缓存

实战示例

# 列表输出为表格(默认排除已关闭账户) actual accounts list [--include-closed] --format table # 按名称查实体 ID actual server get-id --type accounts --name "Checking" # 新增一笔交易(金额为整数分:-2500 = -$25.00) actual transactions add --account <id> \ --data '[{"date":"2026-03-14","amount":-2500,"payee_name":"Coffee Shop"}]' # 导出交易为 CSV actual transactions list --account <id> \ --start 2026-01-01 --end 2026-12-31 --format csv > transactions.csv # 设置预算金额($500 = 50000 分) actual budgets set-amount --month 2026-03 --category <id> --amount 50000 # 运行 ActualQL 查询 actual query run --table transactions \ --select "date,amount,payee" --filter '{"amount":{"$lt":0}}' --limit 10

金额约定:输入(flag / JSON)一律使用整数分(5000 = $50.00,-12350 = -$123.50);table/csv输出会自动转为十进制(如1665.00),json输出保持原始分供程序使用。

缓存与并发模型

CLI 会在本地缓存一份预算副本(packages/cli/src/cache.ts):

  • TTL 内(默认 60s)的读命令(listbalancequery run)直接复用缓存,不发起网络请求;
  • 写命令(addupdateset-amount等)写前写后都会与服务端同步;
  • actual sync立即刷新缓存;actual sync --status查看缓存新鲜度;actual sync --clear删除缓存;--refresh/--no-cache单次强制同步。

并发安全:CLI 对每个预算的缓存目录采用"读共享锁 + 写排他锁"(packages/cli/src/lock.ts)。多个并发读安全,写操作串行;若锁被占用,最多等待--lock-timeout(默认 10s)后报错。仅在可信的单进程场景下使用--no-lock

常见坑与建议

  • 拆分交易:统计/求和时过滤"is_parent": false,避免父子都计入导致总额翻倍(父交易持有总金额,子交易持有各部分);
  • 高频脚本:先actual sync一次,再用长--cache-ttl(如 3600)做批量读;
  • 未分类交易category.namenull,过滤/分组时需处理;
  • AQL 无日期子字段date.monthdate.year等不可作为查询字段,需要按月份聚合时请取原始交易并在脚本内自行聚合。

值得关注的增强与修复速览

除上述主线外,v26.4.0 还有一批高价值改动:

功能增强(节选)

  • 拆分交易金额支持公式规则(Formula Rules,PR #6414);
  • 月度预算单元格支持添加备注(PR #6620);
  • 自定义报表 widget 新增"预算额"类型(PR #6903);
  • 报表新增BUDGET_QUERYQUERY_EXTRACT公式函数(PR #7078),用于基于公式的预算分析;
  • 新增新台币(TWD)币种(PR #7095);
  • 文件导入支持交换 payee/memo 字段(PR #7101)、支持"仅导入自某日期之后的交易"(PR #7139)、支持控制已删除/合并交易是否重新导入(PR #6926);
  • 自定义主题:系统主题分离亮/暗选项、支持文本域自定义覆盖、支持自定义字体(PR #7145 / #7236 / #7239 / #7194),并新增 Notion 风格暗色主题(PR #7151);
  • Electron 备份改为 zip +metadata.json,便于直接导入(PR #7069);
  • 修改密码增加管理员与密码认证要求(PR #7207),并修复了对应的提权漏洞(PR #7155);
  • 合并支付对象增加确认弹窗(PR #7188)。

关键修复(节选)

  • 多标签页同步:通过 SharedWorker 共享单一后端,修复多标签同步问题(PR #7172);
  • CSV 导入:修复 Excel 导出金额含尾随空白导致解析错误(PR #7149);
  • 数字格式化:千位分隔符统一规范为 U+2019(右单引号),消除 Node/ICU 版本差异(PR #7179);
  • 移动端运行余额:即将到来的交易按设置显示运行余额(PR #7041);
  • 修复交易日安排跳过周末前进问题(PR #7057)、合并交易丢失日程链接(PR #7177)、银行同步后balance_current未同步给 API 客户端(PR #7243)、OIDC 开启时密码登录失效(PR #7334)等一批影响日常使用的问题。

工程与维护

  • 将 loot-core 发布为@actual-app/core包(PR #7200);
  • 全面转向 TypeScript 项目引用(composite references,PR #7062 / #7180),升级 TypeScript 编译器到 tsgo(PR #7183);
  • 升级 Vite 8(PR #7184);
  • 移除 API 与 loot-core 之间的循环依赖(PR #6809)、YNAB 导入器不再依赖 API 包(PR #7050)。

升级建议与注意事项

  1. 升级路径:自托管用户将 Docker Tag 更新为26.4.0即可,注意本次修复了 Docker 镜像获取迁移文件的 Bug(PR #7146);
  2. 实验特性谨慎开启:Payee Locations 涉及位置数据存储,请评估隐私影响后再启用;Actual CLI 面向自动化场景,建议先在测试预算上验证脚本;
  3. 备份可迁移:Electron 备份格式已变为 zip + metadata.json,旧版本生成的备份仍可导入,新格式则让导入更可靠;
  4. 关注依赖与工具链:本次同步修复了多个依赖的安全漏洞(axios 固定 1.14.0、express-rate-limit、handlebars、node-forge 等升级),自托管用户应尽快升级以获得安全修复。

无论是普通用户看重的记账体验优化,还是面向自动化与 Agent 的 CLI 能力,v26.4.0 都交出了一份扎实的答卷。想深入了解 CLI 的全部子命令,可直接阅读 packages/cli/README.md;想从源码层面理解同心环图、补全算法与附近支付对象查询的实现,可分别查看 DonutGraph.tsx、filterCategorySuggestions.ts 与 payees/app.ts。

【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actual

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询