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 createState() => _WelfareCenterPageState(); } class _WelfareCenterPageState extends State { Map? _welfareData; bool _isLoading = true; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) => _loadData()); } Future _loadData() async { try { final bonusService = context.read(); 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: 10, vertical: 4), 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( 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.show('邀请码已复制'); }, 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?; 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? ?? []; 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, ), ), const SizedBox(height: 12), // 推广列表卡片 Container( width: double.infinity, decoration: _cardDecoration(), child: referralRewards.isEmpty ? _buildEmptyReferralList(context) : _buildReferralListItems(context, referralRewards), ), ], ); } 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 referralRewards) { return Column( children: List.generate(referralRewards.length, (index) { final data = referralRewards[index] as Map; 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? ?? []; 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), ), 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(progressColor), minHeight: 6, ), ), ), ], ), ), if (!isLast) Divider( height: 1, thickness: 1, color: context.appColors.ghostBorder, ), ], ); }), ); } 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 milestones, String totalDeposit) { if (milestones.isNotEmpty) { int earnedCount = milestones.where((m) { final milestone = m as Map; 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 data, required int claimableCount, required List 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)['claimable'] == true, orElse: () => milestones.first, ) as Map)['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 _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('奖励直接发放至资金账户'), ], ), ); } 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 _claimNewUserBonus() async { try { final bonusService = context.read(); final response = await bonusService.claimNewUserBonus(); if (!mounted) return; if (response.success) { context.read().refreshAll(force: true); context.read().fire(AppEventType.assetChanged); ToastUtils.show('领取成功!100 USDT 已到账'); _loadData(); } else { ToastUtils.show(response.message ?? '领取失败'); } } catch (e) { ToastUtils.show('领取失败: $e'); } } Future _claimReferralBonus(int referredUserId, int milestone) async { try { final bonusService = context.read(); final response = await bonusService.claimReferralBonus( referredUserId, milestone, ); if (!mounted) return; if (response.success) { context.read().refreshAll(force: true); context.read().fire(AppEventType.assetChanged); ToastUtils.show('领取成功!100 USDT 已到账'); _loadData(); } else { ToastUtils.show(response.message ?? '领取失败'); } } catch (e) { ToastUtils.show('领取失败: $e'); } } }