项目总览:从代码看 asset-light

技术栈与依赖(以当前代码为准)

  • UI:Dioxus Desktop(Rust 声明式 UI)
  • 本地数据库:SQLite(rusqlite,嵌入式,无需服务端)
  • 序列化serde
  • 时间chrono
  • IDuuid
  • 金额/比例rust_decimal(避免浮点误差)

依赖定义见:Cargo.toml

运行入口

  • 应用入口:src/main.rs
    • 初始化数据库:db::init_database()
    • 启动 UI:dioxus::launch(app::App)
  • 根组件:src/app.rs
    • 提供全局状态:provide_app_state()
    • 路由渲染:Router::<Route> {}

目录结构(核心)

  • src/main.rs:进程入口,初始化依赖(数据库)后启动 UI
  • src/app.rs:根组件,注入全局状态并挂载路由
  • src/router.rs:路由枚举(页面入口 + layout 包裹)
  • src/error.rs:统一错误类型 AppErrorAppResult<T>
  • src/pages/*:页面(Home / Assets / History / Plans / Analysis)
  • src/components/*:页面内部 UI 组件(按业务域拆分)
  • src/models/*:领域模型(资产分类体系、资产/快照/方案等)
  • src/db/*:数据库访问层(连接、迁移、Repository,返回 AppResult<T>
  • src/state/*:全局状态(Dioxus Signal Context)
  • src/services/*:业务计算/服务(例如分析计算)
  • src/utils/*:格式化等工具函数

分层与职责(建议的理解方式)

  • UI 层(components/pages/router/app)
    负责渲染与交互,不直接拼 SQL;从 Repository 拉取数据或触发写入;在需要时更新 AppState
  • 数据访问层(db/ + repositories)*
    负责 SQL、类型转换与持久化规则(例如字符串到 Decimal / Uuid / chrono 的解析)。
  • 领域模型(models/*)
    负责“数据结构 + 稳定编码”,例如资产大类 Category、口径 AssetScope、工具类型 VehicleType、子资产类别编码等。
  • 业务服务层(services/*,可选)
    负责跨模块的计算逻辑,避免把复杂计算堆进 UI。

数据库位置与环境变量

数据库文件路径由 dirs::data_local_dir() 决定(macOS 通常在用户目录下的 Application Support)。
项目支持通过环境变量指定 DB 路径(便于测试/调试):

  • ASSET_LIGHT_DB_PATH:指向一个 sqlite 文件路径

对应实现见:src/db/connection.rsDatabase::db_path()

迁移策略(重要)

当前迁移逻辑内置于 src/db/connection.rsDatabase::run_migrations()
会维护 schema_meta 表中的 schema_version,并在版本升级时进行表结构处理。

注意:当 schema_version < 2 时,迁移会执行 DROP TABLE(会清空历史数据)。
这适用于早期迭代阶段“允许破坏性升级”的策略,若要进入长期使用阶段,需要改为真正的“非破坏性迁移”。

扩展一个新功能的建议切入点

以“新增一个页面/功能”为例,推荐按顺序改动:

  1. models:先定义稳定的数据结构与编码(必要时为 DB 做准备)
  2. db:增加/扩展 Repository 方法(读写与类型转换)
  3. pages/components:增加 UI 与交互
  4. state/services:补全全局状态同步或业务计算(需要时)