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
+50
View File
@@ -0,0 +1,50 @@
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../core/network/api_exception.dart';
import '../core/network/dio_client.dart';
import '../models/budget.dart';
final budgetApiProvider = Provider<BudgetApi>((ref) => BudgetApi(ref.watch(dioProvider)));
/// 预算接口(后端只提供当月预算)
class BudgetApi {
final Dio _dio;
BudgetApi(this._dio);
/// 获取当月预算。
///
/// 未设置预算时后端可能返回 204 / 空 body,此时返回 [BudgetInfo.empty]
/// 而不是抛错——否则首页会因为"没设预算"而进入错误态。
Future<BudgetInfo> getBudget() async {
try {
final res = await _dio.get('/budgets');
return _parse(res.data);
} on DioException catch (e) {
final err = e.error;
throw err is ApiException ? err : ApiException(-1, '预算加载失败');
}
}
/// 设置/修改当月预算(每月生效,可随时修改)。
/// 后端自动填充年月,amount 必须 >= 0。
Future<BudgetInfo> setCurrentBudget(double amount) async {
try {
final res = await _dio.put('/budgets/current', data: {'amount': amount});
return _parse(res.data);
} on DioException catch (e) {
final err = e.error;
throw err is ApiException ? err : ApiException(-1, '预算保存失败');
}
}
BudgetInfo _parse(Object? data) {
if (data == null) return BudgetInfo.empty;
if (data is Map<String, dynamic>) return BudgetInfo.fromJson(data);
if (data is Map && data['data'] is Map) {
return BudgetInfo.fromJson(Map<String, dynamic>.from(data['data'] as Map));
}
return BudgetInfo.empty;
}
}