Files
monisuo/flutter_monisuo/lib/providers/asset_provider.dart
2026-04-23 00:44:39 +08:00

333 lines
9.3 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:async';
import 'package:flutter/material.dart';
import '../core/network/api_response.dart';
import '../core/event/app_event_bus.dart';
import '../data/models/account_models.dart';
import '../data/models/order_models.dart';
import '../data/services/asset_service.dart';
import '../data/services/fund_service.dart';
import '../data/services/trade_service.dart';
/// 資產狀態管理
class AssetProvider extends ChangeNotifier {
final AssetService _assetService;
final FundService _fundService;
final TradeService _tradeService;
final AppEventBus _eventBus;
AssetOverview? _overview;
AccountFund? _fundAccount;
List<AccountTrade> _tradeAccounts = [];
List<AccountFlow> _flows = [];
List<OrderFund> _fundOrders = [];
List<OrderTrade> _tradeOrders = [];
bool _isLoading = false;
bool _isLoadingFlows = false;
bool _isLoadingOrders = false;
String? _error;
// 加載狀態標記,防止重複加載
bool _overviewLoaded = false;
bool _fundAccountLoaded = false;
bool _tradeAccountLoaded = false;
// 去重:防止并发调用同一 API
Completer<void>? _refreshAllCompleter;
AssetProvider(this._assetService, this._fundService, this._tradeService, this._eventBus);
// Getters
AssetOverview? get overview => _overview;
AccountFund? get fundAccount => _fundAccount;
List<AccountTrade> get tradeAccounts => _tradeAccounts;
List<AccountTrade> get holdings => _tradeAccounts;
List<AccountFlow> get flows => _flows;
List<OrderFund> get fundOrders => _fundOrders;
List<OrderTrade> get tradeOrders => _tradeOrders;
bool get isLoading => _isLoading;
bool get isLoadingFlows => _isLoadingFlows;
bool get isLoadingOrders => _isLoadingOrders;
String? get error => _error;
/// 加載資產總覽
Future<void> loadOverview({bool force = false}) async {
// 如果已經加載過且不是強制刷新,則跳過
if (_overviewLoaded && !force && _overview != null) {
return;
}
_isLoading = true;
_error = null;
notifyListeners();
try {
final response = await _assetService.getOverview();
if (response.success) {
_overview = response.data;
_overviewLoaded = true;
} else {
_error = response.message;
}
} catch (e) {
_error = '加載失敗: $e';
}
_isLoading = false;
notifyListeners();
}
/// 加載資金賬戶
Future<void> loadFundAccount({bool force = false}) async {
// 如果已經加載過且不是強制刷新,則跳過
if (_fundAccountLoaded && !force && _fundAccount != null) {
return;
}
try {
final response = await _assetService.getFundAccount();
if (response.success) {
_fundAccount = response.data;
_fundAccountLoaded = true;
notifyListeners();
}
} catch (_) {
// 忽略錯誤
}
}
/// 加載交易賬戶
Future<void> loadTradeAccount({bool force = false}) async {
// 如果已經加載過且不是強制刷新,則跳過
if (_tradeAccountLoaded && !force && _tradeAccounts.isNotEmpty) {
return;
}
try {
final response = await _assetService.getTradeAccount();
if (response.success) {
_tradeAccounts = response.data ?? [];
_tradeAccountLoaded = true;
notifyListeners();
}
} catch (_) {
// 忽略錯誤
}
}
/// 加載資金流水
Future<void> loadFlows({int? flowType, int pageNum = 1}) async {
_isLoadingFlows = true;
notifyListeners();
try {
final response = await _assetService.getFlow(
flowType: flowType,
pageNum: pageNum,
);
if (response.success && response.data != null) {
final list = response.data!['list'] as List?;
_flows = list?.map((e) => AccountFlow.fromJson(e as Map<String, dynamic>)).toList() ?? [];
}
} catch (_) {
// 忽略錯誤
}
_isLoadingFlows = false;
notifyListeners();
}
/// 劃轉資金
Future<ApiResponse<void>> transfer({
required int direction,
required String amount,
}) async {
try {
final response = await _assetService.transfer(
direction: direction,
amount: amount,
);
if (response.success) {
// 強制刷新數據
await loadOverview(force: true);
await loadFundAccount(force: true);
await loadTradeAccount(force: true);
_eventBus.fire(AppEventType.assetChanged);
}
return response;
} catch (e) {
return ApiResponse.fail('劃轉失敗: $e');
}
}
/// 充值 - 返回訂單詳情包含錢包地址
Future<ApiResponse<Map<String, dynamic>>> deposit({required String amount, String? remark}) async {
try {
final response = await _fundService.deposit(amount: amount, remark: remark);
if (response.success) {
await loadOverview(force: true);
await loadFundAccount(force: true);
_eventBus.fire(AppEventType.orderChanged);
}
return response;
} catch (e) {
return ApiResponse.fail('充值申請失敗: $e');
}
}
/// 確認已打款
Future<ApiResponse<void>> confirmPay(String orderNo) async {
try {
final response = await _fundService.confirmPay(orderNo);
if (response.success) {
await loadFundOrders();
_eventBus.fire(AppEventType.orderChanged);
}
return response;
} catch (e) {
return ApiResponse.fail('確認打款失敗: $e');
}
}
/// 提現
Future<ApiResponse<Map<String, dynamic>>> withdraw({
required String amount,
required String withdrawAddress,
String? network,
String? withdrawContact,
String? remark,
}) async {
try {
final response = await _fundService.withdraw(
amount: amount,
withdrawAddress: withdrawAddress,
network: network,
withdrawContact: withdrawContact,
remark: remark,
);
if (response.success) {
await loadOverview(force: true);
await loadFundAccount(force: true);
_eventBus.fire(AppEventType.assetChanged);
_eventBus.fire(AppEventType.orderChanged);
}
return response;
} catch (e) {
return ApiResponse.fail('提現申請失敗: $e');
}
}
/// 加載充提訂單
Future<void> loadFundOrders({int? type, int pageNum = 1, int pageSize = 20}) async {
_isLoadingOrders = true;
notifyListeners();
try {
final response = await _fundService.getOrders(
type: type,
pageNum: pageNum,
pageSize: pageSize,
);
if (response.success && response.data != null) {
final list = response.data!['list'] as List?;
_fundOrders = _fundService.parseOrderList(list);
}
} catch (_) {
// 忽略錯誤
}
_isLoadingOrders = false;
notifyListeners();
}
/// 加載交易記錄
Future<void> loadTradeOrders({int? direction, int pageNum = 1, int pageSize = 20}) async {
try {
final response = await _tradeService.getOrders(
direction: direction,
pageNum: pageNum,
pageSize: pageSize,
);
if (response.success && response.data != null) {
final list = response.data!['list'] as List?;
_tradeOrders = list?.map((e) => OrderTrade.fromJson(e as Map<String, dynamic>)).toList() ?? [];
notifyListeners();
}
} catch (_) {}
}
/// 取消訂單
Future<ApiResponse<void>> cancelOrder(String orderNo) async {
try {
final response = await _fundService.cancelOrder(orderNo);
if (response.success) {
await loadFundOrders();
await loadFundAccount(force: true);
_eventBus.fire(AppEventType.assetChanged);
_eventBus.fire(AppEventType.orderChanged);
}
return response;
} catch (e) {
return ApiResponse.fail('取消訂單失敗: $e');
}
}
/// 獲取可用提現網絡列表
Future<List<String>> getWalletNetworks() async {
try {
final response = await _fundService.getWalletNetworks();
if (response.success) {
return response.data ?? [];
}
return [];
} catch (_) {
return [];
}
}
/// 提现前检查45天规则
Future<Map<String, dynamic>?> withdrawCheck() async {
try {
final response = await _fundService.withdrawCheck();
if (response.success && response.data != null) {
return response.data;
}
} catch (_) {}
return null;
}
/// 刷新所有資產數據(带去重)
Future<void> refreshAll({bool force = false}) async {
if (_refreshAllCompleter != null && !_refreshAllCompleter!.isCompleted) {
return _refreshAllCompleter!.future;
}
_refreshAllCompleter = Completer<void>();
try {
await Future.wait([
loadOverview(force: force),
loadFundAccount(force: force),
loadTradeAccount(force: force),
]);
_refreshAllCompleter!.complete();
} catch (e) {
if (!_refreshAllCompleter!.isCompleted) _refreshAllCompleter!.completeError(e);
} finally {
_refreshAllCompleter = null;
}
}
/// 重置加載狀態(用於退出登錄時)
void resetLoadState() {
_overviewLoaded = false;
_fundAccountLoaded = false;
_tradeAccountLoaded = false;
_overview = null;
_fundAccount = null;
_tradeAccounts = [];
_flows = [];
_fundOrders = [];
_tradeOrders = [];
_error = null;
notifyListeners();
}
}