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

371 lines
12 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../core/constants/app_colors.dart';
import '../../../core/utils/format_utils.dart';
import '../../providers/mining_providers.dart';
import '../../providers/user_providers.dart';
import '../../providers/trading_providers.dart';
class TradingPage extends ConsumerWidget {
const TradingPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final globalState = ref.watch(globalStateProvider);
final user = ref.watch(userNotifierProvider);
final accountSequence = user.accountSequence ?? '';
final accountAsync = ref.watch(shareAccountProvider(accountSequence));
return Scaffold(
appBar: AppBar(
title: const Text('兑换'),
backgroundColor: AppColors.primary,
foregroundColor: Colors.white,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 价格卡片
globalState.when(
data: (state) {
if (state == null) return const SizedBox.shrink();
return _buildPriceCard(state);
},
loading: () => const Card(
child: Padding(
padding: EdgeInsets.all(32),
child: Center(child: CircularProgressIndicator()),
),
),
error: (_, __) => const Card(
child: Padding(
padding: EdgeInsets.all(32),
child: Center(child: Text('加载失败')),
),
),
),
const SizedBox(height: 24),
// 账户余额
const Text(
'账户余额',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
accountAsync.when(
data: (account) {
if (account == null) return const SizedBox.shrink();
return _buildBalanceCard(account);
},
loading: () => const Card(
child: Padding(
padding: EdgeInsets.all(32),
child: Center(child: CircularProgressIndicator()),
),
),
error: (_, __) => const Card(
child: Padding(
padding: EdgeInsets.all(32),
child: Center(child: Text('加载失败')),
),
),
),
const SizedBox(height: 24),
// 买卖按钮
Row(
children: [
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.up,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
onPressed: () => _showBuyDialog(context, ref, accountSequence),
child: const Text(
'买入',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
),
),
const SizedBox(width: 16),
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.down,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
onPressed: () => _showSellDialog(context, ref, accountSequence),
child: const Text(
'卖出',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
),
),
],
),
const SizedBox(height: 24),
// 交易说明
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'交易说明',
style: TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
_buildInfoRow('买入', '使用绿积分购买积分股'),
_buildInfoRow('卖出', '出售积分股获得绿积分'),
_buildInfoRow('划转', '需先将挖矿账户余额划转到交易账户'),
],
),
),
),
],
),
),
);
}
Widget _buildPriceCard(state) {
final isPriceUp = state.isPriceUp;
return Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: [
const Text(
'当前价格',
style: TextStyle(color: AppColors.textSecondary, fontSize: 14),
),
const SizedBox(height: 8),
Text(
formatPrice(state.currentPrice),
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
color: isPriceUp ? AppColors.up : AppColors.down,
),
),
const SizedBox(height: 4),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
decoration: BoxDecoration(
color: (isPriceUp ? AppColors.up : AppColors.down).withOpacity(0.1),
borderRadius: BorderRadius.circular(20),
),
child: Text(
'${isPriceUp ? '+' : ''}${formatPercent(state.priceChange24h)} 24h',
style: TextStyle(
color: isPriceUp ? AppColors.up : AppColors.down,
fontSize: 12,
),
),
),
],
),
),
);
}
Widget _buildBalanceCard(account) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'挖矿账户',
style: TextStyle(color: AppColors.textSecondary, fontSize: 12),
),
const SizedBox(height: 4),
Text(
formatAmount(account.miningBalance),
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
],
),
),
Container(
width: 1,
height: 40,
color: AppColors.border,
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'交易账户',
style: TextStyle(color: AppColors.textSecondary, fontSize: 12),
),
const SizedBox(height: 4),
Text(
formatAmount(account.tradingBalance),
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
],
),
),
),
],
),
),
);
}
Widget _buildInfoRow(String title, String description) {
return Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 6,
height: 6,
margin: const EdgeInsets.only(top: 6),
decoration: const BoxDecoration(
color: AppColors.primary,
shape: BoxShape.circle,
),
),
const SizedBox(width: 8),
Expanded(
child: RichText(
text: TextSpan(
style: const TextStyle(color: AppColors.textSecondary, fontSize: 13),
children: [
TextSpan(
text: '$title: ',
style: const TextStyle(fontWeight: FontWeight.w500),
),
TextSpan(text: description),
],
),
),
),
],
),
);
}
void _showBuyDialog(BuildContext context, WidgetRef ref, String accountSequence) {
final controller = TextEditingController();
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('买入积分股'),
content: TextField(
controller: controller,
keyboardType: const TextInputType.numberWithOptions(decimal: true),
decoration: const InputDecoration(
labelText: '买入数量',
hintText: '请输入买入数量',
suffixText: '',
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('取消'),
),
ElevatedButton(
onPressed: () async {
if (controller.text.isNotEmpty) {
final success = await ref
.read(tradingNotifierProvider.notifier)
.buyShares(accountSequence, controller.text);
if (context.mounted) {
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(success ? '买入订单已提交' : '买入失败'),
backgroundColor: success ? AppColors.up : AppColors.error,
),
);
if (success) {
ref.invalidate(shareAccountProvider(accountSequence));
}
}
}
},
style: ElevatedButton.styleFrom(backgroundColor: AppColors.up),
child: const Text('确认买入'),
),
],
),
);
}
void _showSellDialog(BuildContext context, WidgetRef ref, String accountSequence) {
final controller = TextEditingController();
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('卖出积分股'),
content: TextField(
controller: controller,
keyboardType: const TextInputType.numberWithOptions(decimal: true),
decoration: const InputDecoration(
labelText: '卖出数量',
hintText: '请输入卖出数量',
suffixText: '',
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('取消'),
),
ElevatedButton(
onPressed: () async {
if (controller.text.isNotEmpty) {
final success = await ref
.read(tradingNotifierProvider.notifier)
.sellShares(accountSequence, controller.text);
if (context.mounted) {
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(success ? '卖出订单已提交' : '卖出失败'),
backgroundColor: success ? AppColors.down : AppColors.error,
),
);
if (success) {
ref.invalidate(shareAccountProvider(accountSequence));
}
}
}
},
style: ElevatedButton.styleFrom(backgroundColor: AppColors.down),
child: const Text('确认卖出'),
),
],
),
);
}
}