import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:provider/provider.dart'; import 'package:google_fonts/google_fonts.dart'; import '../../../core/theme/app_color_scheme.dart'; import '../../../core/theme/app_spacing.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'; import '../../../providers/auth_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); } } // ============================================ // 主题感知颜色辅助 // ============================================ /// 金色强调色 ($gold-accent) Color _goldAccent(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; return isDark ? AppColorScheme.darkSecondary : const Color(0xFFF59E0B); } /// 金色强调色带透明度 Color _goldAccentWithOpacity(BuildContext context, double opacity) { return _goldAccent(context).withOpacity(opacity); } /// 盈利绿色 ($profit-green) Color _profitGreen(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; return isDark ? const Color(0xFF4ADE80) : const Color(0xFF16A34A); } /// 盈利绿色背景 ($profit-green-bg) Color _profitGreenBg(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; return isDark ? const Color(0xFF052E16) : const Color(0xFFF0FDF4); } /// 文字静默色 ($text-muted) Color _textMuted(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; return isDark ? const Color(0xFF64748B) : const Color(0xFF94A3B8); } /// 第三级背景色 ($bg-tertiary) Color _bgTertiary(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; return isDark ? AppColorScheme.darkSurfaceContainerHigh : const Color(0xFFF1F5F9); } /// 卡片表面色 ($surface-card) Color _surfaceCard(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; return isDark ? AppColorScheme.darkSurfaceContainer : Colors.white; } /// 反色文字 ($text-inverse) Color _textInverse(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; return isDark ? const Color(0xFF0F172A) : Colors.white; } @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; final isDark = Theme.of(context).brightness == Brightness.dark; return Scaffold( backgroundColor: isDark ? AppColorScheme.darkBackground : const Color(0xFFF8FAFC), appBar: AppBar( backgroundColor: isDark ? AppColorScheme.darkBackground : Colors.white, elevation: 0, scrolledUnderElevation: 0, centerTitle: false, titleSpacing: 0, title: Text( '福利中心', style: GoogleFonts.inter( fontSize: 17, fontWeight: FontWeight.w600, color: colorScheme.onSurface, ), ), leading: IconButton( icon: Icon(LucideIcons.arrowLeft, color: colorScheme.onSurface, size: 24), onPressed: () => Navigator.of(context).pop(), ), ), body: _isLoading ? Center( child: CircularProgressIndicator( color: _goldAccent(context), strokeWidth: 2.5, ), ) : RefreshIndicator( onRefresh: _loadData, color: _goldAccent(context), 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 colorScheme = Theme.of(context).colorScheme; final referralCode = _welfareData?['referralCode'] as String? ?? ''; final gold = _goldAccent(context); return Container( width: double.infinity, padding: const EdgeInsets.all(24), decoration: BoxDecoration( borderRadius: BorderRadius.circular(AppRadius.xl), gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ _goldAccentWithOpacity(context, 0.15), _surfaceCard(context), ], ), border: Border.all( color: _goldAccentWithOpacity(context, 0.3), width: 1, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Row: gift icon + 标题 Row( children: [ Icon(LucideIcons.gift, color: gold, size: 24), const SizedBox(width: 10), Text( '我的邀请码', style: GoogleFonts.inter( fontSize: 16, fontWeight: FontWeight.w700, color: colorScheme.onSurface, ), ), ], ), const SizedBox(height: 16), // 邀请码 Text( referralCode.isEmpty ? '暂无邀请码' : referralCode, style: GoogleFonts.inter( fontSize: 24, fontWeight: FontWeight.w800, letterSpacing: 2, color: gold, ), ), 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: gold, foregroundColor: _textInverse(context), elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(AppRadius.lg), ), disabledBackgroundColor: gold.withOpacity(0.4), ), child: Text( '复制邀请码', style: GoogleFonts.inter( fontSize: 14, fontWeight: FontWeight.w600, ), ), ), ), ], ), ); } // ============================================ // 新人福利卡片 // ============================================ Widget _buildNewUserBonusCard(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; 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; final green = _profitGreen(context); final greenBg = _profitGreenBg(context); // 状态标签 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: BoxDecoration( color: _surfaceCard(context), borderRadius: BorderRadius.circular(AppRadius.lg), border: Border.all( color: colorScheme.outlineVariant.withOpacity(0.15), ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header: 标题 + 状态标签 Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '新人福利', style: GoogleFonts.inter( fontSize: 16, fontWeight: FontWeight.w700, color: colorScheme.onSurface, ), ), if (showAvailableBadge) Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: greenBg, borderRadius: BorderRadius.circular(AppRadius.sm), ), child: Text( badgeText, style: GoogleFonts.inter( fontSize: 11, fontWeight: FontWeight.w600, color: green, ), ), ), ], ), const SizedBox(height: 12), // 金额 Text( '+100 USDT', style: GoogleFonts.inter( fontSize: 28, fontWeight: FontWeight.w800, color: claimed ? colorScheme.onSurfaceVariant : green, ), ), const SizedBox(height: 8), // 描述 Text( description, style: GoogleFonts.inter( fontSize: 13, fontWeight: FontWeight.normal, color: colorScheme.onSurfaceVariant, ), ), const SizedBox(height: 16), // 领取按钮 SizedBox( width: double.infinity, height: 44, child: ElevatedButton( onPressed: canClaim ? () => _claimNewUserBonus() : null, style: ElevatedButton.styleFrom( backgroundColor: green, foregroundColor: Colors.white, elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(AppRadius.lg), ), disabledBackgroundColor: green.withOpacity(0.3), disabledForegroundColor: Colors.white70, ), child: Text( buttonText, style: GoogleFonts.inter( fontSize: 14, fontWeight: FontWeight.w700, ), ), ), ), ], ), ); } // ============================================ // 推广奖励列表 // ============================================ Widget _buildReferralRewardsSection(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; final referralRewards = _welfareData?['referralRewards'] as List? ?? []; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Section Header Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '推广奖励', style: GoogleFonts.inter( fontSize: 16, fontWeight: FontWeight.w600, color: colorScheme.onSurface, ), ), const SizedBox(height: 4), Text( '每邀请一位好友充值达标,奖励100 USDT', style: GoogleFonts.inter( fontSize: 11, fontWeight: FontWeight.normal, color: _textMuted(context), ), ), ], ), const SizedBox(height: 12), // 推广列表卡片 Container( width: double.infinity, decoration: BoxDecoration( color: _surfaceCard(context), borderRadius: BorderRadius.circular(AppRadius.lg), border: Border.all( color: colorScheme.outlineVariant.withOpacity(0.15), ), ), child: referralRewards.isEmpty ? _buildEmptyReferralList(context) : _buildReferralListItems(context, referralRewards), ), ], ); } Widget _buildEmptyReferralList(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return Padding( padding: const EdgeInsets.all(32), child: Center( child: Column( children: [ Icon( LucideIcons.users, size: 36, color: _textMuted(context).withOpacity(0.4), ), const SizedBox(height: 8), Text( '暂无推广用户', style: GoogleFonts.inter( fontSize: 13, color: colorScheme.onSurfaceVariant, ), ), ], ), ), ); } Widget _buildReferralListItems(BuildContext context, List referralRewards) { final colorScheme = Theme.of(context).colorScheme; final gold = _goldAccent(context); final green = _profitGreen(context); final greenBg = _profitGreenBg(context); 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; // 判断状态 bool hasClaimable = claimableCount > 0; bool hasAnyMilestone = milestones.isNotEmpty; bool allClaimed = milestones.isNotEmpty && milestones.every((m) => (m as Map)['claimed'] == true); // 进度计算 double progress = 0; if (milestones.isNotEmpty) { int earnedCount = milestones.where((m) { final milestone = m as Map; return milestone['earned'] as bool? ?? false; }).length; progress = earnedCount / milestones.length; } else { // 无里程碑数据时,根据充值金额估算 final deposit = double.tryParse(totalDeposit) ?? 0; progress = (deposit / 1000).clamp(0.0, 1.0); } // 状态颜色和文字 Color progressColor; Color statusTextColor; String statusText; Widget? actionWidget; if (hasClaimable) { // 可领取 (achieved, green) progressColor = green; statusTextColor = green; statusText = ''; actionWidget = GestureDetector( onTap: () => _claimReferralBonus(data['userId'] as int, milestones.isNotEmpty ? (milestones.firstWhere( (m) => (m as Map)['claimable'] == true, orElse: () => milestones.first, ) as Map)['milestone'] as int? ?? 1 : 1), child: Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6), decoration: BoxDecoration( color: greenBg, borderRadius: BorderRadius.circular(AppRadius.sm), ), child: Text( '领取', style: GoogleFonts.inter( fontSize: 12, fontWeight: FontWeight.w600, color: green, ), ), ), ); } else if (progress > 0) { // 进行中 (amber / gold) progressColor = gold; statusTextColor = const Color(0xFFD97706); statusText = ''; actionWidget = Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6), decoration: BoxDecoration( color: const Color(0xFFFEF3C7), borderRadius: BorderRadius.circular(AppRadius.sm), ), child: Text( '进行中', style: GoogleFonts.inter( fontSize: 12, fontWeight: FontWeight.w600, color: statusTextColor, ), ), ); } else { // 待达标 (gray) progressColor = _bgTertiary(context); statusTextColor = _textMuted(context); statusText = ''; actionWidget = Text( '待达标', style: GoogleFonts.inter( fontSize: 12, fontWeight: FontWeight.w500, color: _textMuted(context), ), ); } return Column( children: [ Padding( padding: const EdgeInsets.all(16), child: Column( children: [ // Top Row: avatar + name + deposit + action Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ // Avatar Container( width: 32, height: 32, decoration: BoxDecoration( color: _bgTertiary(context), shape: BoxShape.circle, ), child: Center( child: Text( username.isNotEmpty ? username[0].toUpperCase() : '?', style: GoogleFonts.inter( fontSize: 13, fontWeight: FontWeight.w500, color: colorScheme.onSurfaceVariant, ), ), ), ), const SizedBox(width: 10), Text( username, style: GoogleFonts.inter( fontSize: 13, fontWeight: FontWeight.w500, color: colorScheme.onSurface, ), ), const SizedBox(width: 10), Text( '充值: \u00A5$totalDeposit', style: GoogleFonts.inter( fontSize: 11, fontWeight: FontWeight.normal, color: colorScheme.onSurfaceVariant, ), ), ], ), if (actionWidget != null) actionWidget, ], ), const SizedBox(height: 10), // Progress bar ClipRRect( borderRadius: BorderRadius.circular(3), child: SizedBox( height: 6, child: LinearProgressIndicator( value: progress, backgroundColor: _bgTertiary(context), valueColor: AlwaysStoppedAnimation(progressColor), minHeight: 6, ), ), ), ], ), ), if (!isLast) Divider( height: 1, thickness: 1, color: colorScheme.outlineVariant.withOpacity(0.15), ), ], ); }), ); } // ============================================ // 奖励规则卡片 // ============================================ Widget _buildRulesCard(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return Container( width: double.infinity, padding: const EdgeInsets.fromLTRB(20, 16, 20, 16), decoration: BoxDecoration( color: _bgTertiary(context), borderRadius: BorderRadius.circular(AppRadius.lg), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '奖励规则', style: GoogleFonts.inter( fontSize: 13, fontWeight: FontWeight.w600, color: colorScheme.onSurface, ), ), const SizedBox(height: 8), _buildRuleItem('新用户注册完成实名认证奖励 100 USDT', context), _buildRuleItem('邀请好友充值每达 1000 USDT,双方各获得 100 USDT', context), _buildRuleItem('奖励直接发放至资金账户', context), ], ), ); } Widget _buildRuleItem(String text, BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 3), child: Text( '\u2022 $text', style: GoogleFonts.inter( fontSize: 12, fontWeight: FontWeight.normal, color: Theme.of(context).brightness == Brightness.dark ? AppColorScheme.darkOnSurfaceVariant : const Color(0xFF475569), ), ), ); } // ============================================ // 业务逻辑 // ============================================ 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'); } } }