import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:provider/provider.dart'; import '../../../providers/asset_provider.dart'; import '../orders/fund_orders_page.dart'; /// 资产页面 - 使用 shadcn_ui 现代化设计 class AssetPage extends StatefulWidget { const AssetPage({super.key}); @override State createState() => _AssetPageState(); } class _AssetPageState extends State with AutomaticKeepAliveClientMixin { @override bool get wantKeepAlive => true; int _activeTab = 0; // 0=资金账户, 1=交易账户 // 颜色常量 static const upColor = Color(0xFF00C853); static const downColor = Color(0xFFFF5252); @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { _loadData(); }); } void _loadData() { context.read().refreshAll(); } @override Widget build(BuildContext context) { super.build(context); final theme = ShadTheme.of(context); return Scaffold( backgroundColor: theme.colorScheme.background, body: Consumer( builder: (context, provider, _) { return RefreshIndicator( onRefresh: provider.refreshAll, color: theme.colorScheme.primary, child: SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), padding: const EdgeInsets.all(16), child: Column( children: [ _buildAssetCard(provider), const SizedBox(height: 16), _buildAccountTabs(), const SizedBox(height: 16), _activeTab == 0 ? _buildFundAccount(provider) : _buildTradeAccount(provider), ], ), ), ); }, ), ); } Widget _buildAssetCard(AssetProvider provider) { final theme = ShadTheme.of(context); final overview = provider.overview; // 自定义渐变色 const gradientColors = [ Color(0xFF00D4AA), Color(0xFF00B894), ]; return Container( width: double.infinity, padding: const EdgeInsets.all(24), decoration: BoxDecoration( gradient: const LinearGradient( colors: gradientColors, begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(20), ), child: Column( children: [ Text( '总资产估值(USDT)', style: theme.textTheme.small.copyWith(color: Colors.white70), ), const SizedBox(height: 8), Text( overview?.totalAsset ?? '0.00', style: theme.textTheme.h1.copyWith( fontWeight: FontWeight.bold, color: Colors.white, ), ), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( LucideIcons.trendingUp, color: Colors.white70, size: 16, ), const SizedBox(width: 4), Text( '总盈亏: ${overview?.totalProfit ?? '0.00'} USDT', style: theme.textTheme.small.copyWith(color: Colors.white70), ), ], ), ], ), ); } Widget _buildAccountTabs() { final theme = ShadTheme.of(context); return Container( padding: const EdgeInsets.all(4), decoration: BoxDecoration( color: theme.colorScheme.card, borderRadius: BorderRadius.circular(12), ), child: Row( children: [ Expanded( child: GestureDetector( onTap: () => setState(() => _activeTab = 0), child: Container( padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( color: _activeTab == 0 ? theme.colorScheme.primary : Colors.transparent, borderRadius: BorderRadius.circular(8), ), child: Center( child: Text( '资金账户', style: TextStyle( color: _activeTab == 0 ? Colors.white : theme.colorScheme.mutedForeground, fontWeight: _activeTab == 0 ? FontWeight.w600 : FontWeight.normal, ), ), ), ), ), ), Expanded( child: GestureDetector( onTap: () => setState(() => _activeTab = 1), child: Container( padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( color: _activeTab == 1 ? theme.colorScheme.primary : Colors.transparent, borderRadius: BorderRadius.circular(8), ), child: Center( child: Text( '交易账户', style: TextStyle( color: _activeTab == 1 ? Colors.white : theme.colorScheme.mutedForeground, fontWeight: _activeTab == 1 ? FontWeight.w600 : FontWeight.normal, ), ), ), ), ), ), ], ), ); } Widget _buildFundAccount(AssetProvider provider) { final theme = ShadTheme.of(context); final fund = provider.fundAccount; return ShadCard( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'USDT余额', style: theme.textTheme.muted, ), GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute(builder: (_) => const FundOrdersPage()), ); }, child: Row( children: [ Text( '充提记录', style: TextStyle( color: theme.colorScheme.primary, fontSize: 12, ), ), Icon( LucideIcons.chevronRight, size: 14, color: theme.colorScheme.primary, ), ], ), ), ], ), const SizedBox(height: 8), Text( fund?.balance ?? '0.00', style: theme.textTheme.h2.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 24), Row( children: [ Expanded( child: ShadButton( backgroundColor: const Color(0xFF00C853), onPressed: () => _showDepositDialog(provider), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(LucideIcons.plus, size: 18, color: Colors.white), const SizedBox(width: 4), const Text('充值'), ], ), ), ), const SizedBox(width: 12), Expanded( child: ShadButton( backgroundColor: const Color(0xFFFF9800), onPressed: () => _showWithdrawDialog(provider), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(LucideIcons.minus, size: 18, color: Colors.white), const SizedBox(width: 4), const Text('提现'), ], ), ), ), const SizedBox(width: 12), Expanded( child: ShadButton.outline( onPressed: () => _showTransferDialog(provider), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(LucideIcons.arrowRightLeft, size: 18), const SizedBox(width: 4), const Text('划转'), ], ), ), ), ], ), ], ), ); } Widget _buildTradeAccount(AssetProvider provider) { final theme = ShadTheme.of(context); final holdings = provider.holdings; return ShadCard( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '持仓列表', style: theme.textTheme.large.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), if (holdings.isEmpty) Center( child: Padding( padding: const EdgeInsets.all(32), child: Column( children: [ Icon( LucideIcons.wallet, size: 48, color: theme.colorScheme.mutedForeground, ), const SizedBox(height: 12), Text( '暂无持仓', style: theme.textTheme.muted, ), ], ), ), ) else ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: holdings.length, separatorBuilder: (_, __) => Divider( color: theme.colorScheme.border, height: 1, ), itemBuilder: (context, index) { final holding = holdings[index]; return _buildHoldingItem(holding); }, ), ], ), ); } Widget _buildHoldingItem(holding) { final theme = ShadTheme.of(context); return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Row( children: [ CircleAvatar( radius: 20, backgroundColor: theme.colorScheme.primary.withValues(alpha: 0.1), child: Text( holding.coinCode.substring(0, 1), style: TextStyle( color: theme.colorScheme.primary, fontWeight: FontWeight.bold, ), ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( holding.coinCode, style: theme.textTheme.large.copyWith( fontWeight: FontWeight.w600, ), ), Text( '数量: ${holding.quantity}', style: theme.textTheme.muted.copyWith(fontSize: 12), ), ], ), ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( '${holding.currentValue} USDT', style: theme.textTheme.small, ), Text( holding.formattedProfitRate, style: TextStyle( color: holding.isProfit ? upColor : downColor, fontSize: 12, ), ), ], ), ], ), ); } void _showDepositDialog(AssetProvider provider) { final amountController = TextEditingController(); final formKey = GlobalKey(); showShadDialog( context: context, builder: (context) => ShadDialog( title: const Text('充值'), child: ShadForm( key: formKey, child: Column( mainAxisSize: MainAxisSize.min, children: [ ShadInputFormField( id: 'amount', controller: amountController, placeholder: const Text('请输入充值金额(USDT)'), keyboardType: const TextInputType.numberWithOptions(decimal: true), validator: (value) { if (value == null || value.isEmpty) { return '请输入金额'; } final amount = double.tryParse(value); if (amount == null || amount <= 0) { return '请输入有效金额'; } return null; }, ), ], ), ), actions: [ ShadButton.outline( child: const Text('取消'), onPressed: () => Navigator.of(context).pop(), ), ShadButton( child: const Text('下一步'), onPressed: () async { if (formKey.currentState!.saveAndValidate()) { Navigator.of(context).pop(); // 提交充值申请 final response = await provider.deposit(amount: amountController.text); if (mounted) { if (response.success && response.data != null) { // 显示钱包地址 _showDepositResultDialog(response.data!); } else { _showResult('申请失败', response.message); } } } }, ), ], ), ); } /// 显示充值结果 - 包含钱包地址 void _showDepositResultDialog(Map data) { final orderNo = data['orderNo'] as String? ?? ''; final amount = data['amount']?.toString() ?? '0.00'; final walletAddress = data['walletAddress'] as String? ?? ''; final walletNetwork = data['walletNetwork'] as String? ?? 'TRC20'; final assetProvider = context.read(); showShadDialog( context: context, builder: (context) => ShadDialog( title: const Text('充值申请成功'), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('订单号: $orderNo', style: const TextStyle(fontSize: 12)), const SizedBox(height: 8), Text('充值金额: $amount USDT', style: const TextStyle(fontWeight: FontWeight.bold)), const SizedBox(height: 16), const Text('请向以下地址转账:', style: TextStyle(fontSize: 12)), const SizedBox(height: 8), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(8), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( walletAddress, style: const TextStyle(fontFamily: 'monospace', fontSize: 12), ), ), IconButton( icon: const Icon(LucideIcons.copy, size: 18), onPressed: () { Clipboard.setData(ClipboardData(text: walletAddress)); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('地址已复制到剪贴板')), ); }, tooltip: '复制地址', ), ], ), const SizedBox(height: 4), Text('网络: $walletNetwork', style: const TextStyle(fontSize: 12, color: Colors.grey)), ], ), ), const SizedBox(height: 12), const Text( '转账完成后请点击"已打款"按钮确认', style: TextStyle(fontSize: 12, color: Colors.orange), ), ], ), actions: [ ShadButton.outline( child: const Text('稍后确认'), onPressed: () => Navigator.of(context).pop(), ), ShadButton( child: const Text('已打款'), onPressed: () async { Navigator.of(context).pop(); final response = await assetProvider.confirmPay(orderNo); if (mounted) { _showResult( response.success ? '确认成功' : '确认失败', response.success ? '请等待管理员审核' : response.message, ); } }, ), ], ), ); } void _showWithdrawDialog(AssetProvider provider) { final amountController = TextEditingController(); final addressController = TextEditingController(); final contactController = TextEditingController(); final formKey = GlobalKey(); final fund = provider.fundAccount; showShadDialog( context: context, builder: (context) => ShadDialog( title: const Text('提现'), child: SingleChildScrollView( child: ShadForm( key: formKey, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ if (fund != null) Padding( padding: const EdgeInsets.only(bottom: 12), child: Text( '可用余额: ${fund.balance} USDT', style: const TextStyle(color: Colors.grey), ), ), ShadInputFormField( id: 'amount', controller: amountController, placeholder: const Text('请输入提现金额(USDT)'), keyboardType: const TextInputType.numberWithOptions(decimal: true), validator: (value) { if (value == null || value.isEmpty) { return '请输入金额'; } final amount = double.tryParse(value); if (amount == null || amount <= 0) { return '请输入有效金额'; } return null; }, ), const SizedBox(height: 12), ShadInputFormField( id: 'address', controller: addressController, placeholder: const Text('请输入提现地址'), validator: (value) { if (value == null || value.isEmpty) { return '请输入提现地址'; } return null; }, ), const SizedBox(height: 12), ShadInputFormField( id: 'contact', controller: contactController, placeholder: const Text('联系方式(可选)'), ), ], ), ), ), actions: [ ShadButton.outline( child: const Text('取消'), onPressed: () => Navigator.of(context).pop(), ), ShadButton( child: const Text('提交'), onPressed: () async { if (formKey.currentState!.saveAndValidate()) { Navigator.of(context).pop(); final response = await provider.withdraw( amount: amountController.text, withdrawAddress: addressController.text, withdrawContact: contactController.text.isNotEmpty ? contactController.text : null, ); if (mounted) { _showResult( response.success ? '申请成功' : '申请失败', response.success ? '请等待管理员审批' : response.message, ); } } }, ), ], ), ); } void _showTransferDialog(AssetProvider provider) { final controller = TextEditingController(); final formKey = GlobalKey(); int direction = 1; showShadDialog( context: context, builder: (context) => StatefulBuilder( builder: (context, setState) => ShadDialog( title: const Text('划转'), child: Column( mainAxisSize: MainAxisSize.min, children: [ const SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ShadButton.outline( size: ShadButtonSize.sm, onPressed: () => setState(() => direction = 1), child: Row( children: [ if (direction == 1) Icon(LucideIcons.check, size: 14) else const SizedBox(width: 14), const SizedBox(width: 4), const Text('资金→交易'), ], ), ), const SizedBox(width: 8), ShadButton.outline( size: ShadButtonSize.sm, onPressed: () => setState(() => direction = 2), child: Row( children: [ if (direction == 2) Icon(LucideIcons.check, size: 14) else const SizedBox(width: 14), const SizedBox(width: 4), const Text('交易→资金'), ], ), ), ], ), const SizedBox(height: 16), ShadForm( key: formKey, child: ShadInputFormField( id: 'amount', controller: controller, placeholder: const Text('请输入划转金额(USDT)'), keyboardType: const TextInputType.numberWithOptions(decimal: true), validator: (value) { if (value == null || value.isEmpty) { return '请输入金额'; } final amount = double.tryParse(value); if (amount == null || amount <= 0) { return '请输入有效金额'; } return null; }, ), ), ], ), actions: [ ShadButton.outline( child: const Text('取消'), onPressed: () => Navigator.of(context).pop(), ), ShadButton( child: const Text('确认'), onPressed: () async { if (formKey.currentState!.saveAndValidate()) { Navigator.of(context).pop(); final response = await provider.transfer( direction: direction, amount: controller.text, ); if (mounted) { _showResult( response.success ? '划转成功' : '划转失败', response.message, ); } } }, ), ], ), ), ); } void _showResult(String title, String? message) { showShadDialog( context: context, builder: (context) => ShadDialog.alert( title: Text(title), description: message != null ? Text(message) : null, actions: [ ShadButton( child: const Text('确定'), onPressed: () => Navigator.of(context).pop(), ), ], ), ); } }