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 '../../../providers/asset_provider.dart'; import '../../../data/models/account_models.dart'; import '../../shared/ui_constants.dart'; import '../../components/glass_panel.dart'; import '../../components/neon_glow.dart'; /// 划转页面 - 资金账户与交易账户互相划转 class TransferPage extends StatefulWidget { const TransferPage({super.key}); @override State createState() => _TransferPageState(); } class _TransferPageState extends State { final _amountController = TextEditingController(); final _formKey = GlobalKey(); int _direction = 1; // 1: 资金→交易, 2: 交易→资金 bool _isLoading = false; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { context.read().refreshAll(force: true); }); } @override void dispose() { _amountController.dispose(); super.dispose(); } /// 获取资金账户余额 String get _fundBalance { final provider = context.read(); return provider.fundAccount?.balance ?? provider.overview?.fundBalance ?? '0.00'; } /// 获取交易账户 USDT 余额 String get _tradeUsdtBalance { final provider = context.read(); final usdtHolding = provider.tradeAccounts.firstWhere( (t) => t.coinCode.toUpperCase() == 'USDT', orElse: () => AccountTrade( id: 0, userId: 0, coinCode: 'USDT', quantity: '0', avgPrice: '1', totalCost: '0', currentValue: '0', profit: '0', profitRate: 0, ), ); return usdtHolding.quantity; } /// 获取当前可用余额(根据方向) String get _availableBalance { return _direction == 1 ? _fundBalance : _tradeUsdtBalance; } /// 执行划转 Future _doTransfer() async { if (!_formKey.currentState!.saveAndValidate()) return; final amount = _amountController.text; final available = double.tryParse(_availableBalance) ?? 0; final transferAmount = double.tryParse(amount) ?? 0; if (transferAmount <= 0) { _showSnackBar('请输入有效的划转金额'); return; } if (transferAmount > available) { _showSnackBar('余额不足'); return; } setState(() => _isLoading = true); try { final response = await context.read().transfer( direction: _direction, amount: amount, ); if (mounted) { if (response.success) { _amountController.clear(); _showSnackBar('划转成功'); Navigator.of(context).pop(true); // 返回成功标记 } else { _showSnackBar(response.message ?? '划转失败'); } } } finally { if (mounted) { setState(() => _isLoading = false); } } } void _showSnackBar(String message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(message)), ); } @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; final isDark = Theme.of(context).brightness == Brightness.dark; return Scaffold( backgroundColor: colorScheme.background, appBar: AppBar( backgroundColor: Colors.transparent, elevation: 0, leading: IconButton( icon: Icon(Icons.arrow_back, color: colorScheme.onSurface), onPressed: () => Navigator.of(context).pop(), ), title: Text( '资金划转', style: GoogleFonts.spaceGrotesk( fontSize: 18, fontWeight: FontWeight.bold, color: colorScheme.onSurface, ), ), centerTitle: true, ), body: Consumer( builder: (context, provider, _) { return SingleChildScrollView( padding: AppSpacing.pagePadding, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 说明卡片 _buildInfoCard(colorScheme), SizedBox(height: AppSpacing.lg), // 划转方向选择 _buildDirectionSelector(colorScheme), SizedBox(height: AppSpacing.lg), // 账户余额显示 _buildBalanceCards(provider, colorScheme, isDark), SizedBox(height: AppSpacing.lg), // 金额输入 _buildAmountInput(colorScheme), SizedBox(height: AppSpacing.xl), // 确认按钮 _buildSubmitButton(colorScheme), SizedBox(height: AppSpacing.lg), // 提示信息 _buildTips(colorScheme), ], ), ); }, ), ); } /// 说明卡片 Widget _buildInfoCard(ColorScheme colorScheme) { return Container( padding: EdgeInsets.all(AppSpacing.md), decoration: BoxDecoration( color: colorScheme.primary.withOpacity(0.1), borderRadius: BorderRadius.circular(AppRadius.md), border: Border.all( color: colorScheme.primary.withOpacity(0.2), ), ), child: Row( children: [ Icon( LucideIcons.info, size: 18, color: colorScheme.primary, ), SizedBox(width: AppSpacing.sm), Expanded( child: Text( _direction == 1 ? '资金账户 → 交易账户:相当于用资金账户的钱购买 USDT' : '交易账户 → 资金账户:相当于卖掉 USDT 换回资金', style: TextStyle( fontSize: 12, color: colorScheme.onSurfaceVariant, ), ), ), ], ), ); } /// 划转方向选择器 Widget _buildDirectionSelector(ColorScheme colorScheme) { return GlassPanel( padding: EdgeInsets.all(AppSpacing.md), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '划转方向', style: GoogleFonts.spaceGrotesk( fontSize: 14, fontWeight: FontWeight.w600, color: colorScheme.onSurface, ), ), SizedBox(height: AppSpacing.md), Row( children: [ Expanded( child: _DirectionCard( title: '资金账户', subtitle: '交易账户', icon: LucideIcons.arrowRight, isSelected: _direction == 1, onTap: () => setState(() => _direction = 1), ), ), SizedBox(width: AppSpacing.sm), Expanded( child: _DirectionCard( title: '交易账户', subtitle: '资金账户', icon: LucideIcons.arrowRight, isSelected: _direction == 2, onTap: () => setState(() => _direction = 2), ), ), ], ), if (_direction == 2) ...[ SizedBox(height: AppSpacing.sm), Container( padding: EdgeInsets.all(AppSpacing.sm), decoration: BoxDecoration( color: AppColorScheme.warning.withOpacity(0.1), borderRadius: BorderRadius.circular(AppRadius.sm), ), child: Row( children: [ Icon( LucideIcons.triangleAlert, size: 14, color: AppColorScheme.warning, ), SizedBox(width: AppSpacing.xs), Expanded( child: Text( '仅支持 USDT 资产划转到资金账户', style: TextStyle( fontSize: 11, color: AppColorScheme.warning, ), ), ), ], ), ), ], ], ), ); } /// 账户余额卡片 Widget _buildBalanceCards(AssetProvider provider, ColorScheme colorScheme, bool isDark) { final fundBalance = provider.fundAccount?.balance ?? provider.overview?.fundBalance ?? '0.00'; final tradeUsdtBalance = _tradeUsdtBalance; return Row( children: [ Expanded( child: _BalanceCard( title: '资金账户', balance: fundBalance, isActive: _direction == 1, colorScheme: colorScheme, ), ), SizedBox(width: AppSpacing.sm), // 中间的转换图标 Container( width: 40, height: 40, decoration: BoxDecoration( color: colorScheme.primary.withOpacity(0.1), shape: BoxShape.circle, ), child: Icon( _direction == 1 ? LucideIcons.arrowRight : LucideIcons.arrowLeft, color: colorScheme.primary, size: 18, ), ), SizedBox(width: AppSpacing.sm), Expanded( child: _BalanceCard( title: '交易账户(USDT)', balance: tradeUsdtBalance, isActive: _direction == 2, colorScheme: colorScheme, ), ), ], ); } /// 金额输入 Widget _buildAmountInput(ColorScheme colorScheme) { final available = _availableBalance; return GlassPanel( padding: EdgeInsets.all(AppSpacing.md), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '划转金额', style: GoogleFonts.spaceGrotesk( fontSize: 14, fontWeight: FontWeight.w600, color: colorScheme.onSurface, ), ), GestureDetector( onTap: () { _amountController.text = available; }, child: Container( padding: EdgeInsets.symmetric( horizontal: AppSpacing.sm, vertical: AppSpacing.xs, ), decoration: BoxDecoration( color: colorScheme.primary.withOpacity(0.1), borderRadius: BorderRadius.circular(AppRadius.sm), ), child: Text( '全部', style: TextStyle( fontSize: 12, color: colorScheme.primary, fontWeight: FontWeight.w600, ), ), ), ), ], ), SizedBox(height: AppSpacing.sm), Text( '可用: $available USDT', style: TextStyle( fontSize: 12, color: colorScheme.onSurfaceVariant, ), ), SizedBox(height: AppSpacing.md), ShadForm( key: _formKey, child: ShadInputFormField( id: 'amount', controller: _amountController, placeholder: const Text('请输入划转金额'), keyboardType: const TextInputType.numberWithOptions(decimal: true), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d{0,8}')), ], validator: (value) { if (value == null || value.isEmpty) { return '请输入划转金额'; } final amount = double.tryParse(value); if (amount == null || amount <= 0) { return '请输入有效金额'; } final available = double.tryParse(_availableBalance) ?? 0; if (amount > available) { return '余额不足'; } return null; }, ), ), ], ), ); } /// 提交按钮 Widget _buildSubmitButton(ColorScheme colorScheme) { return SizedBox( width: double.infinity, child: NeonButton( text: _isLoading ? '处理中...' : '确认划转', type: NeonButtonType.primary, onPressed: _isLoading ? null : _doTransfer, height: 52, showGlow: true, ), ); } /// 提示信息 Widget _buildTips(ColorScheme colorScheme) { return Container( padding: EdgeInsets.all(AppSpacing.md), decoration: BoxDecoration( color: colorScheme.surfaceContainerHighest, borderRadius: BorderRadius.circular(AppRadius.md), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '划转说明', style: GoogleFonts.spaceGrotesk( fontSize: 12, fontWeight: FontWeight.w600, color: colorScheme.onSurfaceVariant, ), ), SizedBox(height: AppSpacing.sm), _buildTipItem('资金账户用于充提,交易账户用于买卖币种', colorScheme), _buildTipItem('划转操作即时到账,不可撤销', colorScheme), _buildTipItem('交易账户只有 USDT 可直接划转到资金账户', colorScheme), _buildTipItem('其他币种需先卖出换成 USDT 后才能划转', colorScheme), ], ), ); } Widget _buildTipItem(String text, ColorScheme colorScheme) { return Padding( padding: EdgeInsets.only(bottom: AppSpacing.xs), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: 4, height: 4, margin: EdgeInsets.only(top: 6, right: AppSpacing.sm), decoration: BoxDecoration( color: colorScheme.onSurfaceVariant, shape: BoxShape.circle, ), ), Expanded( child: Text( text, style: TextStyle( fontSize: 11, color: colorScheme.onSurfaceVariant, ), ), ), ], ), ); } } /// 方向选择卡片 class _DirectionCard extends StatelessWidget { final String title; final String subtitle; final IconData icon; final bool isSelected; final VoidCallback onTap; const _DirectionCard({ required this.title, required this.subtitle, required this.icon, required this.isSelected, required this.onTap, }); @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return GestureDetector( onTap: onTap, child: AnimatedContainer( duration: const Duration(milliseconds: 200), padding: EdgeInsets.all(AppSpacing.md), decoration: BoxDecoration( color: isSelected ? colorScheme.primary.withOpacity(0.15) : colorScheme.surfaceContainerHigh, borderRadius: BorderRadius.circular(AppRadius.md), border: isSelected ? Border.all(color: colorScheme.primary.withOpacity(0.5)) : null, ), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( title, style: TextStyle( fontSize: 11, color: colorScheme.onSurfaceVariant, ), ), SizedBox(width: AppSpacing.xs), Icon( icon, size: 12, color: colorScheme.onSurfaceVariant, ), SizedBox(width: AppSpacing.xs), Text( subtitle, style: TextStyle( fontSize: 11, color: isSelected ? colorScheme.primary : colorScheme.onSurfaceVariant, fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, ), ), ], ), if (isSelected) ...[ SizedBox(height: AppSpacing.xs), Icon( LucideIcons.check, size: 14, color: colorScheme.primary, ), ], ], ), ), ); } } /// 余额卡片 class _BalanceCard extends StatelessWidget { final String title; final String balance; final bool isActive; final ColorScheme colorScheme; const _BalanceCard({ required this.title, required this.balance, required this.isActive, required this.colorScheme, }); @override Widget build(BuildContext context) { return AnimatedContainer( duration: const Duration(milliseconds: 200), padding: EdgeInsets.all(AppSpacing.md), decoration: BoxDecoration( color: isActive ? colorScheme.primary.withOpacity(0.1) : colorScheme.surfaceContainerHigh, borderRadius: BorderRadius.circular(AppRadius.md), border: isActive ? Border.all(color: colorScheme.primary.withOpacity(0.3)) : null, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: 10, color: colorScheme.onSurfaceVariant, ), ), SizedBox(height: AppSpacing.xs), Text( balance, style: GoogleFonts.spaceGrotesk( fontSize: 16, fontWeight: FontWeight.bold, color: isActive ? colorScheme.primary : colorScheme.onSurface, ), ), Text( 'USDT', style: TextStyle( fontSize: 10, color: colorScheme.onSurfaceVariant, ), ), ], ), ); } }