Files
monisuo/flutter_monisuo/lib/ui/pages/mine/welfare_center_page.dart

922 lines
30 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 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import 'package:provider/provider.dart';
import '../../../core/theme/app_spacing.dart';
import '../../../core/theme/app_theme.dart';
import '../../../core/theme/app_theme_extension.dart';
import '../../../core/theme/app_color_scheme.dart';
import '../../../core/utils/toast_utils.dart';
import '../../../core/event/app_event_bus.dart';
import '../../../data/services/bonus_service.dart';
import '../../../providers/asset_provider.dart';
/// 福利中心頁面
class WelfareCenterPage extends StatefulWidget {
const WelfareCenterPage({super.key});
@override
State<WelfareCenterPage> createState() => _WelfareCenterPageState();
}
class _WelfareCenterPageState extends State<WelfareCenterPage> {
Map<String, dynamic>? _welfareData;
bool _isLoading = true;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) => _loadData());
}
Future<void> _loadData() async {
try {
final bonusService = context.read<BonusService>();
final response = await bonusService.getWelfareStatus();
if (mounted) {
setState(() {
_welfareData = response.data;
_isLoading = false;
});
}
} catch (_) {
if (mounted) setState(() => _isLoading = false);
}
}
// ============================================
// 容器樣式輔助
// ============================================
/// 標準卡片容器
BoxDecoration _cardDecoration({Color? borderColor}) {
return BoxDecoration(
color: context.appColors.surfaceCard,
borderRadius: BorderRadius.circular(AppRadius.lg),
border: Border.all(
color: borderColor ?? context.appColors.ghostBorder,
),
);
}
/// 金色漸變卡片容器
BoxDecoration _goldGradientDecoration() {
final isDark = context.isDark;
// Light Mode: 琥珀色漸變(從 amber 15% 到深灰 5%
// Dark Mode: 金色漸變
final gradientColors = isDark
? [
context.appColors.accentPrimary.withValues(alpha: 0.15),
context.appColors.surfaceCard,
]
: [
const Color(0xFFF59E0B).withValues(alpha: 0.15), // amber-500 with 15% opacity
const Color(0xFF1F2937).withValues(alpha: 0.05), // gray-800 with 5% opacity
];
return BoxDecoration(
borderRadius: BorderRadius.circular(AppRadius.xl),
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: gradientColors,
),
border: Border.all(
color: isDark
? context.appColors.accentPrimary.withValues(alpha: 0.3)
: const Color(0xFFF59E0B).withValues(alpha: 0.3),
width: 1,
),
);
}
/// 狀態膠囊標籤
Widget _statusBadge(String text, Color textColor, Color bgColor) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6), // [4,10] → [6,14]
decoration: BoxDecoration(
color: bgColor,
borderRadius: BorderRadius.circular(AppRadius.sm),
),
child: Text(
text,
style: AppTextStyles.labelSmall(context).copyWith(color: textColor),
),
);
}
/// 全寬按鈕
Widget _fullWidthButton({
required String text,
required Color backgroundColor,
required Color foregroundColor,
required VoidCallback? onPressed,
Color? disabledBackgroundColor,
}) {
return SizedBox(
width: double.infinity,
height: 44,
child: ElevatedButton(
onPressed: onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: backgroundColor,
foregroundColor: foregroundColor,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.lg),
),
disabledBackgroundColor:
disabledBackgroundColor ?? backgroundColor.withValues(alpha: 0.3),
disabledForegroundColor: foregroundColor.withValues(alpha: 0.7),
),
child: Text(
text,
style: AppTextStyles.headlineMedium(context).copyWith(
fontWeight: FontWeight.w700,
color: foregroundColor,
),
),
),
);
}
@override
Widget build(BuildContext context) {
final goldAccent = context.appColors.accentPrimary;
return Scaffold(
backgroundColor: context.colors.surface,
appBar: AppBar(
backgroundColor: context.colors.surface,
elevation: 0,
scrolledUnderElevation: 0,
centerTitle: false,
titleSpacing: 0,
title: Text(
'福利中心',
style: AppTextStyles.headlineLarge(context),
),
leading: IconButton(
icon: Icon(LucideIcons.arrowLeft, color: context.colors.onSurface, size: 24),
onPressed: () => Navigator.of(context).pop(),
),
),
body: _isLoading
? Center(
child: CircularProgressIndicator(
color: goldAccent,
strokeWidth: 2.5,
),
)
: RefreshIndicator(
onRefresh: _loadData,
color: goldAccent,
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
padding: const EdgeInsets.fromLTRB(16, 8, 16, 32),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildReferralCodeCard(context),
const SizedBox(height: 16),
_buildNewUserBonusCard(context),
const SizedBox(height: 16),
_buildReferralRewardsSection(context),
const SizedBox(height: 16),
_buildRulesCard(context),
],
),
),
),
);
}
// ============================================
// 推廣碼卡片(金色漸變邊框 Hero Card
// ============================================
Widget _buildReferralCodeCard(BuildContext context) {
final goldAccent = context.appColors.accentPrimary;
final referralCode = _welfareData?['referralCode'] as String? ?? '';
return Container(
width: double.infinity,
padding: const EdgeInsets.all(24),
decoration: _goldGradientDecoration(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header Row: gift icon + 標題
Row(
children: [
Icon(LucideIcons.gift, color: goldAccent, size: 24),
const SizedBox(width: 10),
Text(
'我的邀請碼',
style: AppTextStyles.headlineLarge(context).copyWith(
fontWeight: FontWeight.w700,
),
),
],
),
const SizedBox(height: 16),
Text(
referralCode.isEmpty ? '暫無邀請碼' : referralCode,
style: AppTextStyles.displayMedium(context).copyWith(
fontSize: 24, // 明確設置為 24px
fontWeight: FontWeight.w800,
color: goldAccent,
letterSpacing: 2,
),
),
const SizedBox(height: 16),
SizedBox(
width: double.infinity,
height: 40,
child: ElevatedButton(
onPressed: referralCode.isEmpty
? null
: () {
Clipboard.setData(ClipboardData(text: referralCode));
ToastUtils.showSuccess('邀請碼已複製');
},
style: ElevatedButton.styleFrom(
backgroundColor: goldAccent,
foregroundColor: context.colors.onPrimary,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.lg),
),
disabledBackgroundColor: goldAccent.withValues(alpha: 0.4),
),
child: Text(
'複製邀請碼',
style: AppTextStyles.headlineMedium(context).copyWith(color: context.colors.onPrimary),
),
),
),
],
),
);
}
// ============================================
// 新人福利卡片
// ============================================
Widget _buildNewUserBonusCard(BuildContext context) {
final profitGreen = context.appColors.up;
final profitGreenBg = context.appColors.upBackground;
final newUserBonus = _welfareData?['newUserBonus'] as Map<String, dynamic>?;
final eligible = newUserBonus?['eligible'] as bool? ?? false;
final claimed = newUserBonus?['claimed'] as bool? ?? false;
final deposited = newUserBonus?['deposited'] as bool? ?? false;
// 狀態判定
String badgeText;
bool showAvailableBadge;
String buttonText;
bool canClaim;
String description;
if (claimed) {
badgeText = '已領取';
showAvailableBadge = false;
buttonText = '已領取';
canClaim = false;
description = '新人福利已領取';
} else if (eligible) {
badgeText = '可領取';
showAvailableBadge = true;
buttonText = '立即領取';
canClaim = true;
description = '完成首次充值即可領取';
} else {
badgeText = deposited ? '已充值' : '待解鎖';
showAvailableBadge = false;
buttonText = '未解鎖';
canClaim = false;
description = deposited ? '已充值,等待系統確認' : '完成首次充值即可領取';
}
return Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: _cardDecoration(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header: 標題 + 狀態標籤
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'新人福利',
style: AppTextStyles.headlineLarge(context).copyWith(
fontWeight: FontWeight.w700,
),
),
if (showAvailableBadge)
_statusBadge(badgeText, profitGreen, profitGreenBg),
],
),
const SizedBox(height: 12),
Text(
'+100 USDT',
style: AppTextStyles.displayLarge(context).copyWith(
fontWeight: FontWeight.w800,
color: claimed ? context.colors.onSurfaceVariant : profitGreen,
),
),
const SizedBox(height: 8),
Text(
description,
style: AppTextStyles.bodyLarge(context).copyWith(
color: context.colors.onSurfaceVariant,
),
),
const SizedBox(height: 16),
_fullWidthButton(
text: buttonText,
backgroundColor: profitGreen,
foregroundColor: context.colors.onPrimary,
onPressed: canClaim ? () => _claimNewUserBonus() : null,
),
],
),
);
}
// ============================================
// 推廣獎勵列表
// ============================================
Widget _buildReferralRewardsSection(BuildContext context) {
final referralRewards =
_welfareData?['referralRewards'] as List<dynamic>? ?? [];
// 彙總統計
int totalEarned = 0;
int totalClaimable = 0;
for (var r in referralRewards) {
final map = r as Map<String, dynamic>;
final milestones = map['milestones'] as List<dynamic>? ?? [];
for (var m in milestones) {
final ms = m as Map<String, dynamic>;
if (ms['claimed'] as bool? ?? false) totalEarned++;
if (ms['claimable'] as bool? ?? false) totalClaimable++;
}
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Section Header
Text(
'推廣獎勵',
style: AppTextStyles.headlineLarge(context),
),
const SizedBox(height: 4),
Text(
'每邀請一位好友充值達標獎勵100 USDT',
style: AppTextStyles.bodySmall(context).copyWith(
color: context.appColors.onSurfaceMuted,
),
),
// 彙總統計
if (referralRewards.isNotEmpty) ...[
const SizedBox(height: 12),
Container(
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md, vertical: AppSpacing.sm),
decoration: BoxDecoration(
color: context.appColors.surfaceCard,
borderRadius: BorderRadius.circular(AppRadius.md),
border: Border.all(color: context.appColors.ghostBorder),
),
child: Row(
children: [
_buildStatItem('已邀請', '${referralRewards.length}'),
Container(width: 1, height: 20, color: context.appColors.ghostBorder),
_buildStatItem('已獲得', '${totalEarned * 100} USDT'),
if (totalClaimable > 0) ...[
Container(width: 1, height: 20, color: context.appColors.ghostBorder),
_buildStatItem('待領取', '$totalClaimable個', highlight: true),
],
],
),
),
],
const SizedBox(height: 12),
// 推廣列表卡片
Container(
width: double.infinity,
decoration: _cardDecoration(),
child: referralRewards.isEmpty
? _buildEmptyReferralList(context)
: _buildReferralListItems(context, referralRewards),
),
],
);
}
Widget _buildStatItem(String label, String value, {bool highlight = false}) {
return Expanded(
child: Column(
children: [
Text(label, style: AppTextStyles.bodySmall(context).copyWith(
color: context.colors.onSurfaceVariant,
)),
const SizedBox(height: 2),
Text(value, style: AppTextStyles.headlineSmall(context).copyWith(
fontWeight: FontWeight.w700,
color: highlight ? context.appColors.up : context.colors.onSurface,
)),
],
),
);
}
Widget _buildEmptyReferralList(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(32),
child: Center(
child: Column(
children: [
Icon(
LucideIcons.users,
size: 36,
color: context.appColors.onSurfaceMuted.withValues(alpha: 0.4),
),
const SizedBox(height: 8),
Text(
'暫無推廣用戶',
style: AppTextStyles.bodyLarge(context).copyWith(
color: context.colors.onSurfaceVariant,
),
),
],
),
),
);
}
Widget _buildReferralListItems(BuildContext context, List<dynamic> referralRewards) {
return Column(
children: List.generate(referralRewards.length, (index) {
final data = referralRewards[index] as Map<String, dynamic>;
final username = data['username'] as String? ?? '';
final totalDeposit = data['totalDeposit']?.toString() ?? '0';
final claimableCount = data['claimableCount'] as int? ?? 0;
final milestones = data['milestones'] as List<dynamic>? ?? [];
final userId = data['userId'] as int? ?? 0;
final indirectRefCount = data['indirectRefCount'] as int? ?? 0;
final indirectClaimableCount = data['indirectClaimableCount'] as int? ?? 0;
final indirectMilestones = data['indirectMilestones'] as List<dynamic>? ?? [];
final isLast = index == referralRewards.length - 1;
// 進度計算
final progress = _computeProgress(milestones, totalDeposit);
// 操作按鈕
final actionWidget = _buildReferralAction(
data: data,
claimableCount: claimableCount,
milestones: milestones,
progress: progress,
);
// 進度條顏色
final progressColor = _referralProgressColor(claimableCount, progress);
return Column(
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
_buildAvatar(username),
const SizedBox(width: 10),
Text(
username,
style: AppTextStyles.headlineSmall(context).copyWith(
fontWeight: FontWeight.w500,
),
),
const SizedBox(width: 10),
Text(
'充值: \u00A5$totalDeposit',
style: AppTextStyles.bodySmall(context),
),
],
),
if (actionWidget != null) actionWidget,
],
),
const SizedBox(height: 10),
ClipRRect(
borderRadius: BorderRadius.circular(3),
child: SizedBox(
height: 6,
child: LinearProgressIndicator(
value: progress,
backgroundColor: context.appColors.surfaceCardHigh,
valueColor: AlwaysStoppedAnimation<Color>(progressColor),
minHeight: 6,
),
),
),
// 里程碑詳情
if (milestones.isNotEmpty) ...[
const SizedBox(height: 12),
_buildMilestoneDetails(milestones, userId),
],
// 間接推廣獎勵
if (indirectRefCount > 0) ...[
const SizedBox(height: 12),
_buildIndirectSection(
userId,
indirectRefCount,
indirectClaimableCount,
indirectMilestones,
),
],
],
),
),
if (!isLast)
Divider(
height: 1,
thickness: 1,
color: context.appColors.ghostBorder,
),
],
);
}),
);
}
/// 里程碑詳情行 — 顯示每個里程碑狀態
Widget _buildMilestoneDetails(List<dynamic> milestones, int userId) {
final upColor = context.appColors.up;
return Wrap(
spacing: 6,
runSpacing: 6,
children: milestones.map((m) {
final ms = m as Map<String, dynamic>;
final milestoneVal = ms['milestone'] as int? ?? 1;
final earned = ms['earned'] as bool? ?? false;
final claimed = ms['claimed'] as bool? ?? false;
final claimable = ms['claimable'] as bool? ?? false;
final threshold = ms['threshold']?.toString() ?? '${milestoneVal * 1000}';
Color bgColor;
Color textColor;
String label;
if (claimed) {
bgColor = upColor.withValues(alpha: 0.1);
textColor = upColor;
label = '${threshold}';
} else if (claimable) {
bgColor = context.appColors.accentPrimary.withValues(alpha: 0.15);
textColor = context.appColors.accentPrimary;
label = '${threshold}🎁';
} else if (earned) {
bgColor = upColor.withValues(alpha: 0.06);
textColor = upColor;
label = '${threshold}';
} else {
bgColor = context.appColors.surfaceCardHigh;
textColor = context.colors.onSurfaceVariant;
label = '${threshold}';
}
return GestureDetector(
onTap: claimable ? () => _claimReferralBonus(userId, milestoneVal) : null,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: bgColor,
borderRadius: BorderRadius.circular(AppRadius.sm),
border: claimable ? Border.all(color: textColor.withValues(alpha: 0.3)) : null,
),
child: Text(
label,
style: AppTextStyles.bodySmall(context).copyWith(
fontSize: 11,
fontWeight: FontWeight.w600,
color: textColor,
),
),
),
);
}).toList(),
);
}
Widget _buildAvatar(String username) {
return Container(
width: 32,
height: 32,
decoration: BoxDecoration(
color: context.appColors.surfaceCardHigh,
shape: BoxShape.circle,
),
child: Center(
child: Text(
username.isNotEmpty ? username[0].toUpperCase() : '?',
style: AppTextStyles.headlineSmall(context).copyWith(
color: context.colors.onSurfaceVariant,
),
),
),
);
}
/// 計算推薦獎勵進度
double _computeProgress(List<dynamic> milestones, String totalDeposit) {
if (milestones.isNotEmpty) {
int earnedCount = milestones.where((m) {
final milestone = m as Map<String, dynamic>;
return milestone['earned'] as bool? ?? false;
}).length;
return earnedCount / milestones.length;
}
final deposit = double.tryParse(totalDeposit) ?? 0;
return (deposit / 1000).clamp(0.0, 1.0);
}
/// 根據狀態獲取進度條顏色
Color _referralProgressColor(int claimableCount, double progress) {
if (claimableCount > 0) return context.appColors.up;
if (progress > 0) return context.appColors.accentPrimary;
return context.appColors.surfaceCardHigh;
}
/// 構建推薦獎勵的操作按鈕
Widget? _buildReferralAction({
required Map<String, dynamic> data,
required int claimableCount,
required List<dynamic> milestones,
required double progress,
}) {
final profitGreen = context.appColors.up;
final profitGreenBg = context.appColors.upBackground;
if (claimableCount > 0) {
final int milestoneValue = milestones.isNotEmpty
? (milestones.firstWhere(
(m) => (m as Map<String, dynamic>)['claimable'] == true,
orElse: () => milestones.first,
) as Map<String, dynamic>)['milestone'] as int? ?? 1
: 1;
return GestureDetector(
onTap: () => _claimReferralBonus(data['userId'] as int, milestoneValue),
child: _statusBadge('領取', profitGreen, profitGreenBg),
);
}
if (progress > 0) {
final warningColor = AppColorScheme.warning;
return _statusBadge('進行中', warningColor, warningColor.withValues(alpha: 0.15));
}
return Text(
'待達標',
style: AppTextStyles.labelLarge(context).copyWith(color: context.appColors.onSurfaceMuted),
);
}
// ============================================
// 間接推廣獎勵區塊
// ============================================
Widget _buildIndirectSection(
int directReferralId,
int indirectRefCount,
int indirectClaimableCount,
List<dynamic> indirectMilestones,
) {
final goldAccent = context.appColors.accentPrimary;
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: context.appColors.surfaceCardHigh.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(AppRadius.md),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(LucideIcons.users, size: 14, color: goldAccent),
const SizedBox(width: 6),
Text(
'已推廣 $indirectRefCount',
style: AppTextStyles.bodyMedium(context).copyWith(
color: context.colors.onSurfaceVariant,
),
),
if (indirectClaimableCount > 0) ...[
const Spacer(),
_statusBadge(
'$indirectClaimableCount 個可領',
context.appColors.up,
context.appColors.upBackground,
),
],
],
),
// 間接里程碑標籤
if (indirectMilestones.isNotEmpty) ...[
const SizedBox(height: 8),
_buildIndirectMilestoneTags(directReferralId, indirectMilestones),
],
],
),
);
}
Widget _buildIndirectMilestoneTags(int directReferralId, List<dynamic> milestones) {
final upColor = context.appColors.up;
return Wrap(
spacing: 6,
runSpacing: 6,
children: milestones.map((m) {
final ms = m as Map<String, dynamic>;
final milestoneVal = ms['milestone'] as int? ?? 1;
final earned = ms['earned'] as bool? ?? false;
final claimed = ms['claimed'] as bool? ?? false;
final claimable = ms['claimable'] as bool? ?? false;
final indirectReferredUserId = ms['indirectReferredUserId'] as int? ?? 0;
// 不顯示未達標的里程碑
if (!earned && !claimed) return const SizedBox.shrink();
Color bgColor;
Color textColor;
String label;
if (claimed) {
bgColor = upColor.withValues(alpha: 0.1);
textColor = upColor;
label = '50\u2713';
} else if (claimable) {
bgColor = context.appColors.accentPrimary.withValues(alpha: 0.15);
textColor = context.appColors.accentPrimary;
label = '50\u{1F381}';
} else {
bgColor = context.appColors.surfaceCardHigh;
textColor = context.colors.onSurfaceVariant;
label = '50';
}
return GestureDetector(
onTap: claimable
? () => _claimIndirectReferralBonus(
directReferralId,
indirectReferredUserId,
milestoneVal,
)
: null,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: bgColor,
borderRadius: BorderRadius.circular(AppRadius.sm),
border: claimable ? Border.all(color: textColor.withValues(alpha: 0.3)) : null,
),
child: Text(
label,
style: AppTextStyles.bodySmall(context).copyWith(
fontSize: 11,
fontWeight: FontWeight.w600,
color: textColor,
),
),
),
);
}).toList(),
);
}
// ============================================
// 獎勵規則卡片
// ============================================
Widget _buildRulesCard(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.fromLTRB(20, 16, 20, 16),
decoration: BoxDecoration(
color: context.appColors.surfaceCardHigh,
borderRadius: BorderRadius.circular(AppRadius.lg),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'獎勵規則',
style: AppTextStyles.headlineSmall(context),
),
const SizedBox(height: 8),
_buildRuleItem('新用戶註冊完成實名認證獎勵 100 USDT'),
_buildRuleItem('邀請好友充值每達 1000 USDT獎勵 100 USDT'),
_buildRuleItem('好友推廣的人充值每達 1000 USDT額外獎勵 50 USDT'),
_buildRuleItem('獎勵直接發放至資金賬戶'),
],
),
);
}
Widget _buildRuleItem(String text) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 3),
child: Text(
'\u2022 $text',
style: AppTextStyles.bodyMedium(context).copyWith(
color: context.colors.onSurfaceVariant,
),
),
);
}
// ============================================
// 業務邏輯
// ============================================
Future<void> _claimNewUserBonus() async {
try {
final bonusService = context.read<BonusService>();
final response = await bonusService.claimNewUserBonus();
if (!mounted) return;
if (response.success) {
context.read<AssetProvider>().refreshAll(force: true);
context.read<AppEventBus>().fire(AppEventType.assetChanged);
ToastUtils.showSuccess('領取成功100 USDT 已到賬');
_loadData();
} else {
ToastUtils.showError(response.message ?? '領取失敗');
}
} catch (e) {
ToastUtils.showError('領取失敗: $e');
}
}
Future<void> _claimReferralBonus(int referredUserId, int milestone) async {
try {
final bonusService = context.read<BonusService>();
final response = await bonusService.claimReferralBonus(
referredUserId,
milestone,
);
if (!mounted) return;
if (response.success) {
context.read<AssetProvider>().refreshAll(force: true);
context.read<AppEventBus>().fire(AppEventType.assetChanged);
ToastUtils.showSuccess('領取成功100 USDT 已到賬');
_loadData();
} else {
ToastUtils.showError(response.message ?? '領取失敗');
}
} catch (e) {
ToastUtils.showError('領取失敗: $e');
}
}
Future<void> _claimIndirectReferralBonus(
int directReferralId,
int indirectReferredUserId,
int milestone,
) async {
try {
final bonusService = context.read<BonusService>();
final response = await bonusService.claimIndirectReferralBonus(
directReferralId,
indirectReferredUserId,
milestone,
);
if (!mounted) return;
if (response.success) {
context.read<AssetProvider>().refreshAll(force: true);
context.read<AppEventBus>().fire(AppEventType.assetChanged);
ToastUtils.showSuccess('領取成功50 USDT 已到賬');
_loadData();
} else {
ToastUtils.showError(response.message ?? '領取失敗');
}
} catch (e) {
ToastUtils.showError('領取失敗: $e');
}
}
}