first commit

This commit is contained in:
2026-09-21 17:37:53 +08:00
commit 67d4dd5b7c
141 changed files with 8558 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
import 'json_util.dart';
/// 账户信息(对应后端 AccountResponse)
///
/// 语义说明(重要):
/// - [balance] 是后端计算出来的:`initialBalance + totalIncome - totalExpense`
/// - [initialBalance] 才是可写入数据库的字段(后端 PUT /accounts/balance 改的是它)
/// - [totalIncome] / [totalExpense] 是**全部账单**的汇总,只读
class AccountInfo {
final int? id;
final String name;
final double initialBalance;
final double balance;
final double totalIncome;
final double totalExpense;
const AccountInfo({
this.id,
this.name = '默认账户',
required this.initialBalance,
required this.balance,
required this.totalIncome,
required this.totalExpense,
});
factory AccountInfo.fromJson(Map<String, dynamic> json) {
final initial = asDouble(json['initialBalance']);
final income = asDouble(json['totalIncome']);
final expense = asDouble(json['totalExpense']);
return AccountInfo(
id: json['id'] == null ? null : asInt(json['id']),
name: asNonEmpty(json['name'], '默认账户'),
initialBalance: initial,
// 后端没给 balance 时本地按同一公式兜底
balance: json['balance'] == null
? initial + income - expense
: asDouble(json['balance']),
totalIncome: income,
totalExpense: expense,
);
}
static const empty = AccountInfo(
initialBalance: 0,
balance: 0,
totalIncome: 0,
totalExpense: 0,
);
}
/// 把"用户想要的目标余额"反算成后端可写入的期初余额。
///
/// 因为 balance = initialBalance + totalIncome - totalExpense,
/// 所以要让余额显示为 target,期初余额必须设为:
/// `target - totalIncome + totalExpense`
double initialBalanceFor({
required double targetBalance,
required double totalIncome,
required double totalExpense,
}) {
if (!targetBalance.isFinite) return 0;
return targetBalance - totalIncome + totalExpense;
}