| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- import 'package:dio/dio.dart';
- import 'package:flutter/foundation.dart';
- import '../../core/utils/spot_transfer_asset.dart';
- import '../models/finance/airdrop_eligibility.dart';
- import '../models/finance/airdrop_record_item.dart';
- import '../models/finance/staking_config.dart';
- import '../models/finance/staking_wallet_balance.dart';
- class StakingService {
- const StakingService(this._dio);
- final Dio _dio;
- void _log(String message) {
- if (kDebugMode) {
- debugPrint('[Airdrop][Service] $message');
- }
- }
- /// 与 Web `STAKING_COIN_UNIT` / `stakingCoinUnit()` 默认币种一致
- static const stakingCoinUnit = 'IBIT';
- Future<List<StakingConfig>> getConfigs() async {
- final resp =
- await _dio.post<Map<String, dynamic>>('uc/staking/config/list');
- final raw = resp.data?['data'];
- if (raw is List) {
- return raw
- .whereType<Map<String, dynamic>>()
- .map(StakingConfig.fromJson)
- .toList();
- }
- return const [];
- }
- Future<StakingConfig?> getMinOpenConfig() async {
- final resp =
- await _dio.post<Map<String, dynamic>>('uc/staking/config/min-open');
- final raw = resp.data?['data'];
- if (raw is Map<String, dynamic>) {
- return StakingConfig.fromJson(raw);
- }
- return null;
- }
- Future<void> submitStake({
- required int configId,
- required String amount,
- }) async {
- await _dio.post<dynamic>(
- 'uc/staking/stake',
- data: {'configId': configId, 'amount': amount},
- options: Options(contentType: Headers.formUrlEncodedContentType),
- );
- }
- Future<StakingWalletBalance> getStakingWalletBalance(String coinUnit) async {
- final resp = await _dio.post<Map<String, dynamic>>(
- 'uc/staking/wallet',
- data: {'coinUnit': coinUnit},
- options: Options(contentType: Headers.formUrlEncodedContentType),
- );
- final raw = resp.data?['data'];
- if (raw is Map<String, dynamic>) {
- return StakingWalletBalance.fromJson(raw);
- }
- return StakingWalletBalance.empty(coinUnit);
- }
- /// 可提现账户指定币种可用余额(对齐 Web `loadFundCoinBalance`)
- ///
- /// POST `/uc/asset/wallet`,解析逻辑同 `parseFundWalletBalances`。
- Future<String> getFundingWalletAvailable(String coinUnit) async {
- try {
- final resp = await _dio.post<Map<String, dynamic>>(
- 'uc/asset/wallet',
- data: <String, dynamic>{},
- );
- final map = parseFundWalletBalances(resp.data);
- return map[coinUnit.toUpperCase()] ?? '0';
- } catch (_) {
- return '0';
- }
- }
- Future<AirdropEligibility> getAirdropEligibility() async {
- final resp =
- await _dio.post<Map<String, dynamic>>('uc/airdrop/eligibility');
- final raw = resp.data?['data'];
- _log(
- 'eligibility response dataType=${raw.runtimeType} keys=${raw is Map<String, dynamic> ? raw.keys.toList() : 'n/a'}',
- );
- if (raw is Map<String, dynamic>) {
- return AirdropEligibility.fromJson(raw);
- }
- _log('eligibility fallback to empty because data is not map');
- return AirdropEligibility.empty();
- }
- Future<void> claimAirdrop() async {
- await _dio.post<Map<String, dynamic>>('uc/airdrop/claim');
- }
- Future<AirdropRecordPage> getAirdropRecords({
- required int pageNo,
- int pageSize = 10,
- }) async {
- final resp = await _dio.post<Map<String, dynamic>>(
- 'uc/airdrop/records',
- data: {'pageNo': pageNo, 'pageSize': pageSize},
- options: Options(contentType: Headers.formUrlEncodedContentType),
- );
- final raw = resp.data?['data'];
- _log(
- 'records response pageNo=$pageNo pageSize=$pageSize dataType=${raw.runtimeType}');
- if (raw is! Map<String, dynamic>) {
- _log('records fallback empty: data is not map');
- return const AirdropRecordPage(content: [], totalPages: 0, pageNo: 1);
- }
- final contentRaw = raw['content'];
- final content = contentRaw is List
- ? contentRaw
- .whereType<Map<String, dynamic>>()
- .map(AirdropRecordItem.fromJson)
- .toList()
- : <AirdropRecordItem>[];
- final totalPages = int.tryParse('${raw['totalPages'] ?? 0}') ?? 0;
- // 后端常见两种分页字段:
- // 1) pageNo: 1 基页码
- // 2) number: 0 基页码(Spring Pageable)
- final rawPageNo = int.tryParse('${raw['pageNo'] ?? ''}');
- final rawNumber = int.tryParse('${raw['number'] ?? ''}');
- final parsedPageNo = rawPageNo ?? ((rawNumber ?? (pageNo - 1)) + 1);
- _log(
- 'records parsed pageNo=$parsedPageNo(totalPages=$totalPages, rawPageNo=$rawPageNo, rawNumber=$rawNumber) contentRawType=${contentRaw.runtimeType} contentCount=${content.length}',
- );
- return AirdropRecordPage(
- content: content,
- totalPages: totalPages,
- pageNo: parsedPageNo,
- );
- }
- }
|