# 开源简账
**Repository Path**: run_wind/OpenSourceSimpleAccount
## Basic Information
- **Project Name**: 开源简账
- **Description**: 基于 Flutter 的跨平台个人记账应用。支持多账本、归属人管理、类型分类、账单记录与统计报表,含加密备份恢复与 WebDAV 同步。
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 0
- **Created**: 2025-12-31
- **Last Updated**: 2026-09-01
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 开源简账 — 个人记账 App
基于 Flutter 的跨平台个人记账应用,支持多账本、归属管理、收支归类配置、定额储备(独立储蓄模块)、资产概览、账单记录、统计看板、CSV 导入导出、数据加密备份、WebDAV 远程备份与恢复、数据库清除。应用启动时自动检测新版本,左侧抽屉提示下载。
### 截图效果
## 功能特性
### 账单管理(核心)
| 功能 | 说明 |
|------|------|
| **账单列表** | 按月分组展示,每月头部显示支出/收入汇总。按月 SQL 分批加载(6 个月/批),滚动到底自动加载更多,长年使用不卡顿 |
| **账单表单** | 七行布局:所属账本 / 归属人+金额 / 日期+时间 / 类型+分类(级联) / 计入统计开关 / 固定支出+必要支出(仅支出) / 描述。红(支出) 绿(收入) 颜色区分 |
| **账单筛选** | 右侧抽屉式筛选面板,支持账本多选、归属人多选、类型(支出/收入)多选、分类多选、时间范围选择、描述关键词模糊搜索。筛选激活时右上角图标显示红色圆点 |
| **账单复制** | 列表项长按菜单 → 复制为未保存的草稿表单,改个金额即可提交(适合水电费、房租等重复账单) |
| **账单删除** | 软删除,列表项长按菜单 → 确认弹窗 → 逻辑删除 |
### 配置管理
| 功能 | 说明 |
|------|------|
| **账本目录** | 创建 / 编辑 / 封账(停用后不在账单表单出现) / 删除 / 排序。支持多账本(日常、旅行、投资等) |
| **归属管理** | 创建 / 编辑 / 停用 / 删除 / 排序。可用于家庭成员或合伙人分摊 |
| **收支归类** | 两层结构:支出 / 收入。每个类型下可自定义分类,支持排序。分类可禁用(隐藏,不在表单中出现) |
### 资产概览
| 功能 | 说明 |
|------|------|
| **资产概览** | 独立页面集中展示全生命周期累计资产状态:累计收入 / 累计支出 / 在管储蓄 / 流动资金 |
| **全量累计口径** | 数据为全部账单与储蓄汇总,不随统计看板的日期/筛选变化,代表"当前资产状态" |
| **流动资金** | 流动资金 = 累计收入 - 累计支出 - 在管储蓄 |
| **明细入口** | 资产页内置"定额储备""统计看板"跳转入口,串联储备与分析功能 |
### 定额储备
| 功能 | 说明 |
|------|------|
| **定额储备** | 独立于收支账本的储蓄模块,记录定期存单、现金封装等长期储蓄 |
| **储蓄归类** | 自定义储蓄类型名称,在定额储备表单中选择使用 |
### 小金库
| 功能 | 说明 |
|------|------|
| **小金库** | 完全独立于主流水账本的私密资金模块,不参与收支统计、不支持 Excel 导入导出 |
| **隐藏入口** | 左侧抽屉长按 Logo 进入,日常使用不暴露入口 |
| **独立统计** | 模块顶部显示总金额和笔数,支持按日期记录和备注 |
### 统计看板
**年度统计(选定年份,8 区块):**
| 区块 | 内容 |
|------|------|
| 年度概览 | 年收入 / 年支出 / 支出比 / 月均收入 / 月均支出 |
| 每月收支双柱图 | X 轴固定 1-12 月,每轴点并列收入(绿)+支出(红)双柱,触摸显示数值 |
| 历年对比 | 以选定年为最右,向前 5 年,每轴点 2 柱(收入/支出),不足 5 年左侧留空 |
| 支出分类分析 | 横向条形图,各分类支出降序排列 |
| 归属人分析 | 横向条形图,各归属人支出降序排列 |
| 堆叠进度条(固定支出) | 仅固定支出(品牌色) + 灵活支出(红色) 斜切分割线,按比例占满 100% |
| 堆叠进度条(刚性支出) | 固定+必要支出(品牌色) + 灵活支出(红色) 斜切分割线,按比例占满 100% |
| 大额支出 Top3 | 排名圆圈 + 分类名 + 归属人 + 金额 + 日期 |
| 月报列表 | 顶部汇总行(月均收入/支出)+ 倒序 12 个月每行明细 |
**月度统计(选定年月,7 区块):**
| 区块 | 内容 |
|------|------|
| 月度概览 | 月收入 / 月支出 / 支出比 / 日均收入 / 日均支出 |
| 支出分类分析 | 横向条形图 |
| 归属人分析 | 横向条形图 |
| 堆叠进度条(固定支出) | 仅固定支出 vs 灵活支出斜切分割 |
| 堆叠进度条(刚性支出) | 固定+必要支出 vs 灵活支出斜切分割 |
| 大额支出 Top3 | 排名列表 |
| 日历日报 | 周一~周日网格日历,每格显示日期 + 收/支 两行数字,格子背景按当天最高值颜色半透明 |
**筛选:** 账本多选 + 归属人多选,右侧抽屉式面板 + 完成批量应用
### 数据迁移
| 功能 | 说明 |
|------|------|
| **CSV 导入** | 两遍扫描:收集缺失配置 → 确认创建 → 逐行校验 → 去重 → 批量插入。自动识别 UTF-8 / GBK 编码,自动识别逗号/分号分隔符。⚠️ 增量导入,不会覆盖已有数据;小金库数据不支持导入;导入前建议先加密备份当前数据 |
| **CSV 导出** | UTF-8 BOM + 逗号分隔(Excel/WPS 双击直接打开)。有数据按真实账单导出,无数据自动生成 7 条示例模板。弹出目录选择器保存到指定位置。⚠️ 仅导出「账单流水」和「储蓄记录」,不含小金库、备注等明细;建议仅用于数据迁移或账本合并等特殊场景 |
### 远程备份
| 功能 | 说明 |
|------|------|
| **WebDAV 配置** | 配置服务器地址、用户名、密码与远端路径,支持测试连接 |
| **上传到远端** | 将本地加密备份上传到远程服务器 |
| **从远端恢复** | 从远程服务器下载最新备份并恢复数据库 |
| **自动同步** | 可配置检测间隔(每次打开 / 10 分钟 ~ 72 小时),打开应用后在后台检测远端是否有更新备份,发现新版本时询问是否恢复;已恢复的远端备份会去重避免重复提示 |
### 数据管理
| 功能 | 说明 |
|------|------|
| **加密备份** | SQLite 数据库加密打包为 ZIP(支持自定义密码)→ 弹出目录选择器保存到指定位置 |
| **加密恢复** | 从 ZIP 文件恢复数据库(覆盖当前数据,重启应用) |
| **数据库清除** | 一键清除所有数据(账本、归属人、分类、账单等),操作前弹出确认弹框,不可撤销 |
### 其他
| 功能 | 说明 |
|------|------|
| **主题切换** | 跟随系统 / 亮色 / 深色 三选一,持久化到本地存储,下次启动自动恢复 |
| **左侧导航抽屉** | 统一入口:账单管理(账单流水/账本目录/归属管理/收支归类)、储备管理(资产概览/定额储备/储蓄归类)、财务分析(统计看板),分组展示 |
| **自动更新检测** | 启动时检测 Gitee 新版本,根据当前平台自动匹配安装包(Windows → .exe,Android → .apk,macOS → .dmg,Linux → .AppImage),左侧抽屉提示下载,点击跳转浏览器 |
## 截图
| 账单列表 | 统计报表 | 设置 |
|---------|---------|------|
| (待添加) | (待添加) | (待添加) |
## 技术栈
| 层面 | 技术 | 用途 |
|------|------|------|
| 框架 | Flutter 3.10+ | 跨平台(Windows / Android / iOS / macOS / Linux) |
| 状态管理 | GetX 4.7 | 响应式状态 + 依赖注入 + 路由 |
| 本地数据库 | sqflite 2.3 | SQLite 数据库 |
| 轻量持久化 | GetStorage 2.1 | 主题模式、当前账本 ID、备份密码等偏好 |
| 数据模型 | Freezed 3.2 + JsonSerializable | 不可变数据类生成 |
| 图表 | fl_chart 1.2 | 统计图:柱状图、双柱图、横向条形图、触摸 tooltip |
| CSV | csv 8.0 | CSV 编解码(逗号分隔) |
| GBK | gbk_codec 0.4 | GBK 编码解码(兼容 WPS/Excel 导出的 CSV) |
| 备份 | archive 4.0 | ZIP 压缩/解压 + 加密支持 |
| 文件选择 | file_picker 11.0 | 选择 CSV 导入文件、备份文件、选择保存目录 |
| 国际化 | flutter_localizations (intl) | 日期/时间选择器中文 |
| 版本信息 | package_info_plus 9.0 | 运行时获取应用版本号 |
| HTTP 请求 | dio 5.9 | 检测新版本(Gitee API) |
| 打开外部链接 | url_launcher 6.3 | 打开浏览器下载安装包 |
## 项目结构
```
lib/
├── main.dart # 应用入口 — 路由、主题、本地化
├── app/
│ ├── routes/app_routes.dart # 路由名称常量(集中维护)
│ ├── themes/app_theme.dart # 亮/暗主题 + 字体/间距/圆角常量
│ └── bindings/app_binding.dart # GetX 依赖注入
├── core/
│ ├── database/database_helper.dart # SQLite 单例 + 建表 + 通用 CRUD + 迁移
│ ├── services/
│ │ ├── backup_service.dart # 加密 ZIP 备份与恢复
│ │ ├── excel_service.dart # CSV 导入导出(校验/去重/自动创建配置)
│ │ └── update_service.dart # 版本更新检测(Gitee API)
│ ├── utils/
│ │ ├── toast_utils.dart # 吐司提示(成功/错误/信息)
│ │ └── validators.dart # 表单校验
│ └── widgets/
│ ├── app_drawer.dart # 左侧导航抽屉(统一入口 + 更新提示)
│ ├── confirm_dialog.dart # 确认弹窗
│ ├── update_dialog.dart # 版本更新弹窗
│ ├── empty_state.dart # 空状态占位
│ ├── list_item_card.dart # 通用列表项卡片(标题+副标题+状态+操作)
│ ├── edit_delete_menu.dart # 编辑/删除三点菜单
│ ├── loading_indicator.dart # 加载指示器
│ └── selection_picker.dart # 底部弹窗选择器(账本/归属人/类型/分类)
├── modules/ # 业务模块(按功能拆分)
│ ├── assets/ # 资产概览模块(全量累计资产状态)
│ │ ├── controllers/ # 加载累计收支 + 储蓄总额
│ │ └── views/ # 资产页面 + 概览主卡片
│ ├── bill/ # 账单模块(核心)
│ │ ├── models/bill.dart # Freezed 数据模型
│ │ ├── controllers/ # GetX 控制器(SQL 分批加载 + 筛选)
│ │ ├── views/ # 列表页 + 表单页
│ │ └── widgets/ # 列表项、筛选抽屉等
│ ├── ledger/ # 账本目录模块(CRUD + 排序 + 封账)
│ ├── person/ # 归属管理模块(CRUD + 停用 + 排序)
│ ├── category/ # 收支归类模块(CRUD + 停用 + 排序)
│ ├── savings/ # 定额储备模块(独立储蓄管理)
│ │ ├── models/savings.dart # Freezed 数据模型
│ │ ├── controllers/ # CRUD + CSV 导入导出
│ │ └── views/ # 列表页 + 表单页
│ ├── savings_type/ # 储蓄归类模块(CRUD + 停用 + 排序)
│ │ ├── models/savings_type.dart # Freezed 数据模型
│ │ ├── controllers/ # CRUD + 默认初始化
│ │ └── views/ # 列表页 + 表单页
│ ├── settings/ # 设置模块(主题/备份/WebDAV/CSV/关于/更新)
│ │ ├── controllers/
│ │ │ ├── update_controller.dart # 版本更新检测控制器(启动时自动检测)
│ │ └── services/
│ └── statistics/ # 统计模块(年度/月度图表 + 日历日报)
└── shared/
├── constants/enums.dart # 业务枚举(账本状态/类型/默认分类)
├── controllers/theme_controller.dart # 主题控制器(持久化到 GetStorage)
├── extensions/ # Dart 扩展方法
└── helpers/type_helpers.dart # 类型颜色映射(红/绿)
```
## 数据表
所有表之间不设物理外键约束,关联通过应用层维护,便于备份恢复和跨设备数据迁移。软删除标记 `is_deleted` 统一控制逻辑删除。
表名在 `DatabaseHelper` 中以 `static const String` 常量的形式定义(如 `tableBill`、`tableLedger`),业务代码中统一引用这些常量,避免硬编码字符串。
### 核心表:`bill`(账单)
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| `id` | INTEGER | PK AUTOINCREMENT | 自增主键 |
| `amount` | REAL | NOT NULL | 金额(正数) |
| `bill_time` | INTEGER | NOT NULL | 账单时间(毫秒时间戳) |
| `ledger_id` | INTEGER | NOT NULL | 账本 ID |
| `person_id` | INTEGER | NOT NULL | 归属人 ID |
| `type_category_id` | INTEGER | NOT NULL | 分类 ID(关联 bill_type_category) |
| `include_in_stats` | INTEGER | NOT NULL DEFAULT 1 | 是否计入统计 |
| `is_fixed_expense` | INTEGER | NOT NULL DEFAULT 0 | 是否固定支出 |
| `is_necessary` | INTEGER | NOT NULL DEFAULT 0 | 是否必要支出 |
| `description` | TEXT | | 描述/备注 |
| `create_time` | INTEGER | NOT NULL | 创建时间 |
| `update_time` | INTEGER | NOT NULL | 更新时间 |
| `is_deleted` | INTEGER | DEFAULT 0 | 软删除标记 |
### 配置表:`ledger`(账本)
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| `id` | INTEGER | PK AUTOINCREMENT | 自增主键 |
| `name` | TEXT | NOT NULL | 账本名称 |
| `description` | TEXT | | 账本描述 |
| `status` | TEXT | NOT NULL DEFAULT '启用' | 状态:启用 / 封账 |
| `sort_order` | INTEGER | DEFAULT 0 | 排序权重 |
| `create_time` | INTEGER | NOT NULL | 创建时间 |
| `update_time` | INTEGER | NOT NULL | 更新时间 |
| `is_deleted` | INTEGER | DEFAULT 0 | 软删除标记 |
### 配置表:`person`(归属人)
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| `id` | INTEGER | PK AUTOINCREMENT | 自增主键 |
| `name` | TEXT | NOT NULL UNIQUE | 归属人姓名 |
| `remark` | TEXT | | 备注 |
| `sort_order` | INTEGER | DEFAULT 0 | 排序权重 |
| `is_disabled` | INTEGER | DEFAULT 0 | 是否停用 |
| `create_time` | INTEGER | NOT NULL | 创建时间 |
| `update_time` | INTEGER | NOT NULL | 更新时间 |
| `is_deleted` | INTEGER | DEFAULT 0 | 软删除标记 |
### 配置表:`bill_type_category`(类型分类)
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| `id` | INTEGER | PK AUTOINCREMENT | 自增主键 |
| `type` | TEXT | NOT NULL | 类型:支出 / 收入 |
| `category` | TEXT | NOT NULL | 分类名称 |
| `sort_order` | INTEGER | DEFAULT 0 | 排序权重 |
| `description` | TEXT | | 分类描述 |
| `is_disabled` | INTEGER | DEFAULT 0 | 是否停用 |
| `create_time` | INTEGER | NOT NULL | 创建时间 |
| `update_time` | INTEGER | NOT NULL | 更新时间 |
| `is_deleted` | INTEGER | DEFAULT 0 | 软删除标记 |
| | | **UNIQUE(type, category)** | 同一类型下分类名唯一 |
### 储蓄表:`savings`(定额储备)
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| `id` | INTEGER | PK AUTOINCREMENT | 自增主键 |
| `type` | TEXT | NOT NULL | 储蓄类型名称 |
| `amount` | REAL | NOT NULL | 金额(正数) |
| `deposit_date` | INTEGER | NOT NULL | 存入时间(毫秒时间戳) |
| `term_months` | INTEGER | NOT NULL DEFAULT 0 | 期限(月),0=不定期 |
| `interest_rate` | REAL | NOT NULL DEFAULT 0 | 年利率(%) |
| `institution` | TEXT | | 存入机构 |
| `note` | TEXT | | 备注 |
| `create_time` | INTEGER | NOT NULL | 创建时间 |
| `update_time` | INTEGER | NOT NULL | 更新时间 |
| `is_deleted` | INTEGER | DEFAULT 0 | 软删除标记 |
### 配置表:`savings_type`(储蓄归类)
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| `id` | INTEGER | PK AUTOINCREMENT | 自增主键 |
| `name` | TEXT | NOT NULL UNIQUE | 类型名称 |
| `remark` | TEXT | | 备注说明 |
| `sort_order` | INTEGER | DEFAULT 0 | 排序权重 |
| `is_disabled` | INTEGER | DEFAULT 0 | 是否停用 |
| `create_time` | INTEGER | NOT NULL | 创建时间 |
| `update_time` | INTEGER | NOT NULL | 更新时间 |
| `is_deleted` | INTEGER | DEFAULT 0 | 软删除标记 |
### 设计约定
- **无物理外键** — 所有关联通过应用层维护,备份恢复和跨设备迁移无需重建约束
- **软删除** — `is_deleted = 1` 标记删除,永远不执行 `DELETE FROM`,数据可恢复
- **时间戳** — 毫秒级 Unix 时间戳(`DateTime.millisecondsSinceEpoch`),兼容 SQLite 整数运算
- **金额精度** — REAL 类型存储,UI 显示 `toStringAsFixed(2)`,统计用 SQL SUM 聚合
## 数据库迁移指南
### 迁移机制
`DatabaseHelper` 使用 SQLite 内置版本号机制(`dbVersion` 常量 + `onUpgrade` 回调)处理架构变更:
```dart
static const int dbVersion = 2; // 改表结构时 +1
Future _onUpgrade(Database db, int oldVersion, int newVersion) async {
if (oldVersion < 2) { /* v1→v2 的变更 */ }
if (oldVersion < 3) { /* v2→v3 的变更 */ }
}
```
每次升级用 `if (oldVersion < N)` 判断,保证从任意旧版本都能连续升级到最新。
### 常见操作
| 操作 | 方法 | 复杂度 |
|------|------|--------|
| 新增字段 | `ALTER TABLE ... ADD COLUMN` | ⭐ |
| 新增表 | `CREATE TABLE IF NOT EXISTS` | ⭐ |
| 减少字段 | 重建表 + DROP + RENAME | ⭐⭐⭐ |
| 改字段类型 | 重建表 + DROP + RENAME | ⭐⭐⭐ |
| 重命名字段 | `RENAME COLUMN`(SQLite 3.25+)或重建表 | ⭐⭐ |
### 注意事项
1. `onUpgrade` 中不要访问 `DatabaseHelper` 单例(数据库未完全就绪)
2. 始终使用 `dbVersion` 常量,不要硬编码版本号
3. 复杂迁移写在事务中:`await db.transaction((txn) async { ... })`
4. 发布前验证:从上一个版本升到当前版本,确认数据完整
5. 旧版本兼容:用 `if (oldVersion < N)` 保证增量升级链完整
## 编译运行
```bash
# 1. 安装依赖
flutter pub get
# 2. 生成 Freezed 代码(修改模型后需要)
flutter pub run build_runner build --delete-conflicting-outputs
# 3. 运行
flutter run
# 4. 代码分析
flutter analyze
```
### 平台说明
- **Windows / Linux / macOS** — 使用 `sqflite_common_ffi` 替代原生 sqflite
- **Android / iOS** — 原生 sqflite,无需额外配置
### IDE 配置
- **VS Code** — `lib/` 文件夹直接打开,推荐安装 Flutter / Dart 扩展
- **Android Studio / IntelliJ** — 直接打开项目根目录,自动识别
## 设计语言
### 色彩体系
| 元素 | 规格 |
|------|------|
| 品牌色 | 靛蓝 `#5C6BC0` |
| 支出色 | 红 `#D32F2F` |
| 收入色 | 绿 `#2E7D32` |
| 必要色 | 橙 `#F57C00` | 必要支出标签色 |
| 页面背景(亮色) | `#F5F7FA` |
| 卡片背景 | `#FFFFFF` |
| 输入框填充 | `#F0F1F5` |
### 圆角体系(`AppRadius`)
| 常量 | 值 | 用途 |
|------|-----|------|
| `tag` | 4 | 标签/标记 |
| `small` | 6 | 摘要 Chip |
| `chip` | 8 | Chip |
| `icon` | 10 | 图标容器 |
| `input` | 12 | 输入框/按钮 |
| `card` | 16 | 卡片 |
| `dialog` | 16 | 对话框 |
| `sheet` | 20 | 底部弹窗 |
### 字体体系(`AppFont`)
所有字体大小使用 `AppFont` 常量,禁止魔法值。
| 常量 | 值 | 用途 |
|------|-----|------|
| `xs` | 10 | 极小标签 |
| `sm` | 11 | Chip 文字 |
| `caption` | 12 | 辅助说明 |
| `body` | 13 | 描述文本 |
| `md` | 14 | 正文 |
| `lg` | 15 | 强调正文 |
| `xl` | 16 | 主标题 |
| `title` | 18 | 页面标题 |
| `headline` | 20 | 大标题 |
### 间距体系(`AppSpacing`)
4px 基准。所有 `SizedBox`、`EdgeInsets` 使用 `AppSpacing` 常量,禁止魔法值。
| 常量 | 值 | 用途 |
|------|-----|------|
| `xx` | 2 | 极小间隙 |
| `xs` | 4 | 标签/按钮内边距 |
| `sm` | 8 | 表单元素间距 |
| `md` | 12 | 行内间距 |
| `lg` | 16 | 外边距/卡片边距 |
| `xl` | 20 | 大间距 |
| `xxl` | 24 | 区块间距 |
| `huge` | 32 | 表单底部 |
| `fab` | 80 | 列表底部 FAB 安全间距 |
快捷 EdgeInsets:`zero`、`allXs`~`allHuge`、`hSm`~`hXl`、`vSm`~`vLg`、`symSm`~`symLg`、`tSm`、`tMd`、`bFab`。
## 第三方依赖
| 名称 | 版本 | 用途 | 许可证 |
|------|------|------|--------|
| [get](https://github.com/jonataslaw/getx) | 4.7.3 | 状态管理 / 路由 / 依赖注入 | MIT |
| [get_storage](https://github.com/jonataslaw/get_storage) | 2.1.1 | 轻量持久化 | MIT |
| [sqflite](https://github.com/tekartik/sqflite) | 2.3.0 | SQLite 数据库 | BSD-2 |
| [sqflite_common_ffi](https://github.com/tekartik/sqflite) | 2.4.2 | 桌面平台 SQLite | BSD-2 |
| [fl_chart](https://github.com/imaNNeo/fl_chart) | 1.2.0 | 统计图表 | MIT |
| [csv](https://github.com/polevpn/csv) | 8.0.0 | CSV 编解码 | MIT |
| [gbk_codec](https://pub.dev/packages/gbk_codec) | 0.4.0 | GBK 编码解码 | MIT |
| [file_picker](https://github.com/miguelpruivo/flutter_file_picker) | 11.0.2 | 文件选择 + 目录选择 | MIT |
| [archive](https://github.com/brendan-duncan/archive) | 4.0.0 | ZIP 压缩/解压 + 加密 | MIT |
| [freezed_annotation](https://github.com/rrousselGit/freezed) | 3.1.0 | 不可变模型 | MIT |
| [json_annotation](https://github.com/google/json_serializable.dart) | 4.9.0 | JSON 序列化 | BSD-3 |
| [intl](https://github.com/dart-lang/i18n) | 0.20.2 | 日期格式化 | BSD-3 |
| [webdav_client](https://pub.dev/packages/webdav_client) | 1.2.2 | WebDAV 同步 | MIT |
| [package_info_plus](https://github.com/fluttercommunity/plus_plugins) | 9.0.1 | 运行时版本信息 | BSD-3 |
| [dio](https://pub.dev/packages/dio) | 5.9.2 | HTTP 请求(Gitee API 版本检测) | MIT |
| [url_launcher](https://pub.dev/packages/url_launcher) | 6.3.0 | 打开外部链接(浏览器/下载) | BSD-3 |
| [path_provider](https://github.com/flutter/packages) | 2.1.0 | 文件路径获取 | BSD-3 |
| [flutter_launcher_icons](https://github.com/fluttercommunity/flutter_launcher_icons) | 0.14.4 | 应用图标生成 | MIT |
| [flutter_native_splash](https://github.com/jonbhanson/flutter_native_splash) | 2.4.7 | 启动页 | MIT |
## 版本管理
### 应用版本号
`pubspec.yaml` 顶部 `version` 字段(格式 `x.y.z+n`):
```yaml
version: 1.0.12+13 # ← 改这里即可,所有位置自动生效
```
修改后自动生效的位置:
- 设置页 → 关于 → 版本号
- 备份 ZIP 注释中的 `appVersion` 字段
### 数据库版本号
`lib/core/database/database_helper.dart`:
```dart
static const int dbVersion = 4; // ← 改表结构时 +1,同时添加 onUpgrade 逻辑
```
## 开发规范
- **注释** — 文件头部说明用途,公开方法写 `///` 文档注释,复杂逻辑行内注释
- **封装** — 避免过度设计,单个文件 ≤ 300 行(如超过考虑拆分)
- **色彩** — 不使用硬编码颜色值,统一使用 `AppTheme` 品牌色和主题色常量
- **字体** — 不使用魔法数字,统一使用 `AppFont.*` 常量
- **间距** — 不使用魔法数字,统一使用 `AppSpacing.*` 常量和快捷 EdgeInsets
- **状态** — 使用 GetX(`Obx` + `Rx` 系列),避免 `setState` 在父子组件间传播
- **模型** — 使用 Freezed 生成不可变类,手动编写 `fromMap`/`toMap` 用于 SQLite 序列化
- **错误处理** — 不空吞异常,至少 `debugPrint` 日志或 Toast 提示用户
- **命名** — 望文生义原则:看到名字知道用途,布尔变量用 `is`/`has`/`can` 前缀
- **性能** — 列表渲染设置合理的 `key`,循环内避免频繁创建对象、操作数据库
- **刷新策略** — 子页面(统计/归属人/分类)通过路由 binding 进入时自动 reload;首页(账单列表)通过 `needsRefresh` 标志位联动刷新
- **依赖** — 不加不必要的抽象层和设计模式,保持代码一眼能看懂
## 构建与发布
### 发布前配置
1. **更新版本号** — 修改 `pubspec.yaml` 中的 `version`(如 `1.0.12+13`,`+` 前为版本名,后为构建号)
2. **检查 Gitee 仓库配置** — `lib/core/services/update_service.dart` 中的 `GiteeConfig` 确保指向你的仓库
3. **更新应用图标**(可选)— 修改 `assets/icon/` 下的图片,执行 `flutter pub run flutter_launcher_icons`
4. **更新启动屏**(可选)— 修改 `flutter_native_splash.yaml`,执行 `flutter pub run flutter_native_splash:create`
### 版本发布流程(Gitee)
用户打开 App → 设置 → 关于 → 点击「检测更新」→ 自动比对版本号 → 有更新时弹窗提示 → 点击「前往下载」→ 浏览器打开下载链接。同时,每次应用启动时自动检测新版本,在左侧抽屉底部显示提示卡片。
发布新版本步骤:
1. **构建并打包** — 为各平台打包(见下方命令)
2. **创建 Gitee Release**:
- 打开仓库 →「发行版」→「创建发行版」
- **标签版本**:输入 `v1.0.1`(推荐格式 `v*.*.*`,如 `v1.0.1`、`v2.0.0`)
- **发行标题**:如 `v1.0.1`
- **发行说明**:填写更新内容(用户将在此看到)
- **上传附件**:把各平台安装包上传
- 点击「创建」
### 构建命令与输出路径
```bash
# ======================== Android ========================
# (需要 Android SDK + 签名配置,ABI 拆分多架构)
flutter build apk --release
# 输出:build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk
# build/app/outputs/flutter-apk/app-arm64-v8a-release.apk
# build/app/outputs/flutter-apk/app-x86_64-release.apk
开源简账_v1.0.12_android.apk
# ======================== Windows ========================
# (需要 Visual Studio 构建工具)
flutter build windows --release
# 输出:build\windows\runner\Release\magicoct_app.exe + 一系列 .dll 文件
# Windows 需要制作为可执行文件(.exe)再分发
# 更新检测会优先匹配 .exe 文件
# 使用 Enigma Virtual Box 打包:
开源简账_v1.0.12_windows.exe
# ======================== macOS ========================
# (需要 macOS + Xcode)
flutter build macos --release
# 输出:build/macos/Build/Products/Release/magicoct_app.app
# 通常打包为 .dmg 分发
# 重命名示例:
hdiutil create -volname OpenSourceSimpleAccount -srcfolder build/macos/Build/Products/Release/magicoct_app.app OpenSourceSimpleAccount_v1.0.1_macos.dmg
# ======================== Linux ========================
flutter build linux --release
# 输出:build/linux/x64/release/bundle/
# 通常打包为 .AppImage 或 .deb 分发
# ======================== iOS ========================
# (需要 macOS + Xcode + Apple Developer 账号)
flutter build ios --release --no-codesign
# 输出:build/ios/iphoneos/Runner.app
# 用 Xcode 打包为 .ipa
# ======================== Web ========================
flutter build web --release
# 输出:build/web/
```
### 签名与商店发布
- **Android**:`android/app/build.gradle.kts` 中已配置 `signingConfigs.release`,签名文件在 `keystore/key`
- **Windows**:使用 Visual Studio 对生成的 `.exe` 或 `.msix` 进行数字签名
- **iOS/macOS**:在 Xcode 中配置签名证书和 Provisioning Profile
## License
MIT