rwadurian/frontend/mobile-app/lib/features/trading/presentation/pages/trading_page.dart

603 lines
18 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_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../../core/di/injection_container.dart';
import '../../../../routes/route_paths.dart';
/// 结算币种枚举
enum SettlementCurrency { bnb, og, usdt, dst }
/// 兑换页面 - 显示可结算收益和兑换功能
/// 支持一键结算和DST转USDT
class TradingPage extends ConsumerStatefulWidget {
const TradingPage({super.key});
@override
ConsumerState<TradingPage> createState() => _TradingPageState();
}
class _TradingPageState extends ConsumerState<TradingPage> {
// 当前选中的结算币种
SettlementCurrency _selectedCurrency = SettlementCurrency.usdt;
// 钱包数据(从 wallet-service 获取)
double _settleableAmount = 0.0;
double _dstBalance = 0.0;
double _usdtBalance = 0.0;
bool _isLoading = true;
bool _isSettling = false;
@override
void initState() {
super.initState();
_loadWalletData();
}
/// 加载钱包数据
Future<void> _loadWalletData() async {
try {
debugPrint('[TradingPage] 开始加载数据...');
// 从 reward-service 获取可结算收益(与 Profile 页面保持一致)
final rewardService = ref.read(rewardServiceProvider);
final summary = await rewardService.getMyRewardSummary();
// 从 wallet-service 获取 DST 余额
final walletService = ref.read(walletServiceProvider);
final wallet = await walletService.getMyWallet();
if (mounted) {
setState(() {
_settleableAmount = summary.settleableUsdt;
_dstBalance = wallet.balances.dst.available;
_usdtBalance = wallet.balances.usdt.available;
_isLoading = false;
});
debugPrint('[TradingPage] 数据加载成功:');
debugPrint('[TradingPage] 可结算 USDT: $_settleableAmount (from reward-service)');
debugPrint('[TradingPage] DST 余额: $_dstBalance (from wallet-service)');
debugPrint('[TradingPage] USDT 余额: $_usdtBalance (from wallet-service)');
}
} catch (e, stackTrace) {
debugPrint('[TradingPage] 加载数据失败: $e');
debugPrint('[TradingPage] 堆栈: $stackTrace');
if (mounted) {
setState(() {
_isLoading = false;
});
}
}
}
/// 选择结算币种
void _selectCurrency(SettlementCurrency currency) {
setState(() {
_selectedCurrency = currency;
});
}
/// 一键结算
void _onSettlement() {
if (_settleableAmount <= 0) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('没有可结算的收益'),
backgroundColor: Color(0xFF8B5A2B),
),
);
return;
}
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('确认结算'),
content: Text(
'确定将 ${_formatNumber(_settleableAmount)} USDT 结算为 ${_getCurrencyName(_selectedCurrency)} 吗?',
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('取消'),
),
TextButton(
onPressed: () {
Navigator.pop(context);
_doSettlement();
},
child: const Text('确认'),
),
],
),
);
}
/// 执行结算
Future<void> _doSettlement() async {
if (_isSettling) return;
setState(() {
_isSettling = true;
});
try {
debugPrint('[TradingPage] 开始结算...');
debugPrint('[TradingPage] 金额: $_settleableAmount USDT');
debugPrint('[TradingPage] 币种: ${_getCurrencyName(_selectedCurrency)}');
final walletService = ref.read(walletServiceProvider);
final orderId = await walletService.settleRewards(
usdtAmount: _settleableAmount,
settleCurrency: _getCurrencyName(_selectedCurrency),
);
debugPrint('[TradingPage] 结算成功: orderId=$orderId');
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('结算成功'),
backgroundColor: Color(0xFFD4AF37),
),
);
// 刷新钱包数据
_loadWalletData();
}
} catch (e) {
debugPrint('[TradingPage] 结算失败: $e');
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('结算失败: $e'),
backgroundColor: Colors.red,
),
);
}
} finally {
if (mounted) {
setState(() {
_isSettling = false;
});
}
}
}
/// 卖出DST转换为USDT
void _onSellDst() {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('卖出 DST'),
content: Text(
'确定将 ${_formatNumber(_dstBalance)} DST 转换为 USDT 吗?',
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('取消'),
),
TextButton(
onPressed: () {
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('转换成功'),
backgroundColor: Color(0xFFD4AF37),
),
);
},
child: const Text('确认'),
),
],
),
);
}
/// 格式化数字(添加千分位)
String _formatNumber(double number) {
final parts = number.toStringAsFixed(2).split('.');
final intPart = parts[0].replaceAllMapped(
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
(Match m) => '${m[1]},',
);
return '$intPart.${parts[1]}';
}
/// 获取币种名称
String _getCurrencyName(SettlementCurrency currency) {
switch (currency) {
case SettlementCurrency.bnb:
return 'BNB';
case SettlementCurrency.og:
return 'OG';
case SettlementCurrency.usdt:
return 'USDT';
case SettlementCurrency.dst:
return 'DST';
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Container(
width: double.infinity,
height: double.infinity,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFFFFF5E6),
Color(0xFFFFE4B5),
],
),
),
child: SafeArea(
child: SingleChildScrollView(
child: Column(
children: [
// 顶部标题栏
_buildAppBar(),
const SizedBox(height: 16),
// 可结算收益卡片
_buildSettleableCard(),
const SizedBox(height: 24),
// 一键结算按钮
_buildSettlementButton(),
const SizedBox(height: 16),
// 结算币种选择
_buildCurrencySelector(),
const SizedBox(height: 24),
// 分隔线
_buildDivider(),
const SizedBox(height: 24),
// 卖出DST按钮
_buildSellDstButton(),
const SizedBox(height: 8),
// DST余额显示
_buildDstBalance(),
const SizedBox(height: 24),
// 分隔线
_buildDivider(),
const SizedBox(height: 24),
// 提款/转账按钮
_buildWithdrawButton(),
const SizedBox(height: 8),
// USDT余额显示
_buildUsdtBalance(),
],
),
),
),
),
);
}
/// 构建顶部标题栏
Widget _buildAppBar() {
return Container(
height: 56,
padding: const EdgeInsets.symmetric(horizontal: 16),
child: const Center(
child: Text(
'兑换',
style: TextStyle(
fontSize: 18,
fontFamily: 'Inter',
fontWeight: FontWeight.w700,
height: 1.25,
letterSpacing: -0.27,
color: Color(0xFF5D4037),
),
),
),
);
}
/// 构建可结算收益卡片
Widget _buildSettleableCard() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Container(
width: double.infinity,
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: const Color(0x1A8B5A2B),
borderRadius: BorderRadius.circular(12),
),
child: Column(
children: [
const Text(
'可结算收益',
style: TextStyle(
fontSize: 14,
fontFamily: 'Inter',
height: 1.5,
color: Color(0xCC8B5A2B),
),
),
const SizedBox(height: 8),
_isLoading
? const SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Color(0xFFD4AF37)),
),
)
: Text(
'${_formatNumber(_settleableAmount)} USDT',
style: const TextStyle(
fontSize: 32,
fontFamily: 'Inter',
fontWeight: FontWeight.w700,
height: 1.25,
letterSpacing: -0.8,
color: Color(0xFF5D4037),
),
),
],
),
),
);
}
/// 构建一键结算按钮
/// 注意:一键结算功能暂时禁用
Widget _buildSettlementButton() {
// 功能暂时禁用,始终不可点击
const bool canSettle = false;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: GestureDetector(
onTap: null, // 功能暂时禁用
child: Container(
width: double.infinity,
height: 56,
decoration: BoxDecoration(
color: const Color(0x80D4AF37), // 禁用状态颜色
borderRadius: BorderRadius.circular(12),
),
child: const Center(
child: Text(
'一键结算(暂未开放)',
style: TextStyle(
fontSize: 16,
fontFamily: 'Inter',
fontWeight: FontWeight.w700,
height: 1.5,
letterSpacing: 0.24,
color: Colors.white,
),
),
),
),
),
);
}
/// 构建结算币种选择器
Widget _buildCurrencySelector() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
children: [
const Text(
'结算的币种',
style: TextStyle(
fontSize: 14,
fontFamily: 'Inter',
fontWeight: FontWeight.w700,
height: 1.5,
letterSpacing: 0.21,
color: Color(0xCC8B5A2B),
),
),
const SizedBox(height: 12),
Container(
padding: const EdgeInsets.all(6),
decoration: BoxDecoration(
color: const Color(0x1A8B5A2B),
borderRadius: BorderRadius.circular(12),
),
child: Row(
children: [
_buildCurrencyChip(SettlementCurrency.bnb, 'BNB'),
const SizedBox(width: 8),
_buildCurrencyChip(SettlementCurrency.og, 'OG'),
const SizedBox(width: 8),
_buildCurrencyChip(SettlementCurrency.usdt, 'USDT'),
const SizedBox(width: 8),
_buildCurrencyChip(SettlementCurrency.dst, 'DST'),
],
),
),
],
),
);
}
/// 构建币种选择标签
Widget _buildCurrencyChip(SettlementCurrency currency, String label) {
final isSelected = _selectedCurrency == currency;
return Expanded(
child: GestureDetector(
onTap: () => _selectCurrency(currency),
child: Container(
height: 40,
decoration: BoxDecoration(
color: isSelected ? const Color(0xFFD4AF37) : Colors.transparent,
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Text(
label,
style: TextStyle(
fontSize: 14,
fontFamily: 'Inter',
fontWeight: isSelected ? FontWeight.w700 : FontWeight.w600,
height: 1.43,
color: isSelected ? Colors.white : const Color(0xCC5D4037),
),
),
),
),
),
);
}
/// 构建分隔线
Widget _buildDivider() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Container(
height: 1,
color: const Color(0x1A8B5A2B),
),
);
}
/// 构建卖出DST按钮
/// 注意卖出DST功能暂时禁用
Widget _buildSellDstButton() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: GestureDetector(
onTap: null, // 功能暂时禁用
child: Container(
width: double.infinity,
height: 56,
decoration: BoxDecoration(
color: const Color(0x1A8B5A2B), // 禁用状态颜色更浅
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: const Color(0x408B5A2B), // 禁用状态边框更浅
width: 1,
),
),
child: const Center(
child: Text(
'卖出 DST 转换为 USDT暂未开放',
style: TextStyle(
fontSize: 16,
fontFamily: 'Inter',
fontWeight: FontWeight.w700,
height: 1.5,
letterSpacing: 0.24,
color: Color(0x808B5A2B), // 禁用状态文字颜色更浅
),
),
),
),
),
);
}
/// 构建DST余额显示
Widget _buildDstBalance() {
return _isLoading
? const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Color(0xFFD4AF37)),
),
)
: Text(
'DST 余额: ${_formatNumber(_dstBalance)}',
style: const TextStyle(
fontSize: 14,
fontFamily: 'Inter',
height: 1.5,
color: Color(0x995D4037),
),
);
}
/// 构建提款/转账按钮
/// 当 USDT 余额为 0 时禁用
Widget _buildWithdrawButton() {
// 余额为0时禁用
final bool canWithdraw = !_isLoading && _usdtBalance > 0;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: GestureDetector(
onTap: canWithdraw
? () {
context.push(RoutePaths.withdrawUsdt);
}
: null,
child: Container(
width: double.infinity,
height: 56,
decoration: BoxDecoration(
color: canWithdraw
? const Color(0xFFD4AF37)
: const Color(0x80D4AF37), // 禁用状态颜色
borderRadius: BorderRadius.circular(12),
boxShadow: canWithdraw
? const [
BoxShadow(
color: Color(0x4DD4AF37),
blurRadius: 14,
offset: Offset(0, 4),
),
]
: null, // 禁用时无阴影
),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.account_balance_wallet_outlined,
color: canWithdraw ? Colors.white : Colors.white70,
size: 20,
),
const SizedBox(width: 8),
Text(
'提款 / 转账',
style: TextStyle(
fontSize: 16,
fontFamily: 'Inter',
fontWeight: FontWeight.w700,
height: 1.5,
letterSpacing: 0.24,
color: canWithdraw ? Colors.white : Colors.white70,
),
),
],
),
),
),
),
);
}
/// 构建USDT余额显示
Widget _buildUsdtBalance() {
return _isLoading
? const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Color(0xFFD4AF37)),
),
)
: Text(
'USDT 余额: ${_formatNumber(_usdtBalance)}',
style: const TextStyle(
fontSize: 14,
fontFamily: 'Inter',
height: 1.5,
color: Color(0x995D4037),
),
);
}
}