import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../../core/utils/format_utils.dart'; import '../../providers/c2c_providers.dart'; import '../../providers/user_providers.dart'; import '../../providers/asset_providers.dart'; import '../../providers/trading_providers.dart'; class C2cPublishPage extends ConsumerStatefulWidget { const C2cPublishPage({super.key}); @override ConsumerState createState() => _C2cPublishPageState(); } class _C2cPublishPageState extends ConsumerState { static const Color _orange = Color(0xFFFF6B00); static const Color _green = Color(0xFF10B981); static const Color _red = Color(0xFFEF4444); static const Color _darkText = Color(0xFF1F2937); static const Color _grayText = Color(0xFF6B7280); static const Color _bgGray = Color(0xFFF3F4F6); int _selectedType = 1; // 0: 买入, 1: 卖出 final _priceController = TextEditingController(); final _quantityController = TextEditingController(); final _remarkController = TextEditingController(); // 收款信息(卖单必填) String _paymentMethod = 'ALIPAY'; // ALIPAY, WECHAT, BANK final _paymentAccountController = TextEditingController(); final _paymentRealNameController = TextEditingController(); @override void dispose() { _priceController.dispose(); _quantityController.dispose(); _remarkController.dispose(); _paymentAccountController.dispose(); _paymentRealNameController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final user = ref.watch(userNotifierProvider); final accountSequence = user.accountSequence ?? ''; final assetAsync = ref.watch(accountAssetProvider(accountSequence)); final priceAsync = ref.watch(currentPriceProvider); final c2cState = ref.watch(c2cTradingNotifierProvider); final asset = assetAsync.valueOrNull; final currentPrice = priceAsync.valueOrNull?.price ?? '0'; final availableShares = asset?.availableShares ?? '0'; final availableCash = asset?.availableCash ?? '0'; // 设置默认价格 if (_priceController.text.isEmpty && currentPrice != '0') { _priceController.text = currentPrice; } return Scaffold( backgroundColor: _bgGray, appBar: AppBar( backgroundColor: Colors.white, elevation: 0, leading: IconButton( icon: const Icon(Icons.arrow_back, color: _darkText), onPressed: () => context.pop(), ), title: const Text( '发布广告', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: _darkText, ), ), centerTitle: true, ), body: SingleChildScrollView( child: Column( children: [ const SizedBox(height: 16), // 交易类型选择 _buildTypeSelector(), const SizedBox(height: 16), // 可用余额 _buildBalanceCard(availableShares, availableCash), const SizedBox(height: 16), // 价格输入 _buildPriceInput(currentPrice), const SizedBox(height: 16), // 数量输入 _buildQuantityInput(availableShares, availableCash, currentPrice), const SizedBox(height: 16), // 收款信息(卖单必填) if (_selectedType == 1) ...[ _buildPaymentInfoInput(), const SizedBox(height: 16), ], // 备注 _buildRemarkInput(), const SizedBox(height: 16), // 预估信息 _buildEstimateCard(), const SizedBox(height: 24), // 发布按钮 _buildPublishButton(c2cState), const SizedBox(height: 16), // 提示信息 _buildTips(), const SizedBox(height: 24), ], ), ), ); } Widget _buildTypeSelector() { return Container( margin: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.all(4), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), ), child: Row( children: [ Expanded( child: GestureDetector( onTap: () => setState(() => _selectedType = 0), child: Container( padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( color: _selectedType == 0 ? _green : Colors.transparent, borderRadius: BorderRadius.circular(8), ), child: Text( '我要买入', textAlign: TextAlign.center, style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: _selectedType == 0 ? Colors.white : _grayText, ), ), ), ), ), Expanded( child: GestureDetector( onTap: () => setState(() => _selectedType = 1), child: Container( padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( color: _selectedType == 1 ? _red : Colors.transparent, borderRadius: BorderRadius.circular(8), ), child: Text( '我要卖出', textAlign: TextAlign.center, style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: _selectedType == 1 ? Colors.white : _grayText, ), ), ), ), ), ], ), ); } Widget _buildBalanceCard(String availableShares, String availableCash) { final isBuy = _selectedType == 0; return Container( margin: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( isBuy ? '可用积分值' : '可用积分股', style: const TextStyle(fontSize: 14, color: _grayText), ), Text( isBuy ? formatAmount(availableCash) : formatAmount(availableShares), style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: isBuy ? _green : _orange, ), ), ], ), ); } Widget _buildPriceInput(String currentPrice) { return Container( margin: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( '单价', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: _darkText, ), ), Text( '当前价: ${formatPrice(currentPrice)}', style: const TextStyle(fontSize: 12, color: _grayText), ), ], ), const SizedBox(height: 12), TextField( controller: _priceController, keyboardType: const TextInputType.numberWithOptions(decimal: true), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d{0,8}')), ], decoration: InputDecoration( hintText: '请输入单价', hintStyle: const TextStyle(color: _grayText), filled: true, fillColor: _bgGray, border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: _orange, width: 2), ), suffixText: '积分值/股', suffixStyle: const TextStyle(color: _grayText, fontSize: 14), ), onChanged: (_) => setState(() {}), ), ], ), ); } Widget _buildQuantityInput( String availableShares, String availableCash, String currentPrice, ) { final isBuy = _selectedType == 0; return Container( margin: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( '数量', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: _darkText, ), ), const SizedBox(height: 12), TextField( controller: _quantityController, keyboardType: const TextInputType.numberWithOptions(decimal: true), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d{0,4}')), ], decoration: InputDecoration( hintText: '请输入数量', hintStyle: const TextStyle(color: _grayText), filled: true, fillColor: _bgGray, border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: _orange, width: 2), ), suffixIcon: TextButton( onPressed: () { if (isBuy) { // 买入:根据可用积分值计算可买数量 final price = double.tryParse(_priceController.text) ?? 0; final cash = double.tryParse(availableCash) ?? 0; if (price > 0) { _quantityController.text = (cash / price).toStringAsFixed(4); } } else { // 卖出:填入全部可用积分股 _quantityController.text = availableShares; } setState(() {}); }, child: const Text( '全部', style: TextStyle( color: _orange, fontWeight: FontWeight.w500, ), ), ), suffixText: '积分股', suffixStyle: const TextStyle(color: _grayText, fontSize: 14), ), onChanged: (_) => setState(() {}), ), ], ), ); } Widget _buildPaymentInfoInput() { return Container( margin: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: const [ Text( '收款信息', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: _darkText, ), ), SizedBox(width: 8), Text( '(必填)', style: TextStyle(fontSize: 12, color: _red), ), ], ), const SizedBox(height: 16), // 收款方式选择 const Text( '收款方式', style: TextStyle(fontSize: 14, color: _grayText), ), const SizedBox(height: 8), Row( children: [ _buildPaymentMethodChip('ALIPAY', '支付宝', Icons.account_balance_wallet), const SizedBox(width: 12), _buildPaymentMethodChip('WECHAT', '微信', Icons.chat_bubble), const SizedBox(width: 12), _buildPaymentMethodChip('BANK', '银行卡', Icons.credit_card), ], ), const SizedBox(height: 16), // 收款账号 const Text( '收款账号', style: TextStyle(fontSize: 14, color: _grayText), ), const SizedBox(height: 8), TextField( controller: _paymentAccountController, decoration: InputDecoration( hintText: _paymentMethod == 'BANK' ? '请输入银行卡号' : '请输入收款账号', hintStyle: const TextStyle(color: _grayText), filled: true, fillColor: _bgGray, border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: _orange, width: 2), ), ), ), const SizedBox(height: 16), // 收款人实名 const Text( '收款人姓名', style: TextStyle(fontSize: 14, color: _grayText), ), const SizedBox(height: 8), TextField( controller: _paymentRealNameController, decoration: InputDecoration( hintText: '请输入收款人真实姓名', hintStyle: const TextStyle(color: _grayText), filled: true, fillColor: _bgGray, border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: _orange, width: 2), ), ), ), const SizedBox(height: 12), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: _orange.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Row( children: const [ Icon(Icons.info_outline, size: 16, color: _orange), SizedBox(width: 8), Expanded( child: Text( '买家会根据您填写的收款信息进行付款,请确保信息准确', style: TextStyle(fontSize: 12, color: _orange), ), ), ], ), ), ], ), ); } Widget _buildPaymentMethodChip(String value, String label, IconData icon) { final isSelected = _paymentMethod == value; return GestureDetector( onTap: () => setState(() => _paymentMethod = value), child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), decoration: BoxDecoration( color: isSelected ? _orange : _bgGray, borderRadius: BorderRadius.circular(8), border: isSelected ? null : Border.all(color: Colors.grey.shade300), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( icon, size: 18, color: isSelected ? Colors.white : _grayText, ), const SizedBox(width: 6), Text( label, style: TextStyle( fontSize: 13, color: isSelected ? Colors.white : _darkText, fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, ), ), ], ), ), ); } Widget _buildRemarkInput() { return Container( margin: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( '备注 (可选)', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: _darkText, ), ), const SizedBox(height: 12), TextField( controller: _remarkController, maxLength: 100, maxLines: 2, decoration: InputDecoration( hintText: '添加交易说明,如联系方式等', hintStyle: const TextStyle(color: _grayText), filled: true, fillColor: _bgGray, border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: _orange, width: 2), ), counterStyle: const TextStyle(color: _grayText), ), ), ], ), ); } Widget _buildEstimateCard() { final price = double.tryParse(_priceController.text) ?? 0; final quantity = double.tryParse(_quantityController.text) ?? 0; final total = price * quantity; final isBuy = _selectedType == 0; return Container( margin: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: _orange.withOpacity(0.05), borderRadius: BorderRadius.circular(12), border: Border.all(color: _orange.withOpacity(0.2)), ), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text('交易总额', style: TextStyle(fontSize: 14, color: _grayText)), Text( '${formatAmount(total.toString())} 积分值', style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: _orange, ), ), ], ), const SizedBox(height: 8), Divider(color: _orange.withOpacity(0.2)), const SizedBox(height: 8), Text( isBuy ? '发布后,其他用户可以接单卖出积分股给您' : '发布后,其他用户可以接单用积分值购买您的积分股', style: const TextStyle(fontSize: 12, color: _grayText), ), ], ), ); } Widget _buildPublishButton(C2cTradingState c2cState) { final price = double.tryParse(_priceController.text) ?? 0; final quantity = double.tryParse(_quantityController.text) ?? 0; final isSell = _selectedType == 1; // 卖单需要验证收款信息 bool isValid = price > 0 && quantity > 0; if (isSell) { isValid = isValid && _paymentAccountController.text.trim().isNotEmpty && _paymentRealNameController.text.trim().isNotEmpty; } return Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: SizedBox( width: double.infinity, height: 50, child: ElevatedButton( onPressed: isValid && !c2cState.isLoading ? _handlePublish : null, style: ElevatedButton.styleFrom( backgroundColor: _selectedType == 0 ? _green : _red, foregroundColor: Colors.white, disabledBackgroundColor: (_selectedType == 0 ? _green : _red).withOpacity(0.4), disabledForegroundColor: Colors.white70, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: c2cState.isLoading ? const SizedBox( width: 24, height: 24, child: CircularProgressIndicator( strokeWidth: 2, color: Colors.white, ), ) : Text( _selectedType == 0 ? '发布买入广告' : '发布卖出广告', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), ), ), ); } Widget _buildTips() { return Container( margin: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: const [ Icon(Icons.info_outline, size: 16, color: _orange), SizedBox(width: 8), Text( '交易说明', style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: _orange, ), ), ], ), const SizedBox(height: 8), const Text( '1. 发布广告后,您的资产将被冻结直到交易完成或取消\n' '2. 其他用户接单后,需在规定时间内完成交易\n' '3. 买方需先转账积分值,卖方确认收款后积分股自动划转\n' '4. 如遇问题,请联系客服处理', style: TextStyle( fontSize: 12, color: _grayText, height: 1.5, ), ), ], ), ); } Future _handlePublish() async { final price = _priceController.text.trim(); final quantity = _quantityController.text.trim(); final remark = _remarkController.text.trim(); final type = _selectedType == 0 ? 'BUY' : 'SELL'; final isSell = _selectedType == 1; // 卖单验证收款信息 if (isSell) { if (_paymentAccountController.text.trim().isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('请填写收款账号'), backgroundColor: _red), ); return; } if (_paymentRealNameController.text.trim().isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('请填写收款人姓名'), backgroundColor: _red), ); return; } } final paymentMethodText = _paymentMethod == 'ALIPAY' ? '支付宝' : _paymentMethod == 'WECHAT' ? '微信' : '银行卡'; // 确认对话框 final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( title: Text(_selectedType == 0 ? '确认发布买入广告' : '确认发布卖出广告'), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('单价: $price 积分值/股'), const SizedBox(height: 8), Text('数量: $quantity 积分股'), const SizedBox(height: 8), Text( '总额: ${formatAmount((double.parse(price) * double.parse(quantity)).toString())} 积分值', style: const TextStyle(fontWeight: FontWeight.bold), ), if (isSell) ...[ const SizedBox(height: 16), const Divider(), const SizedBox(height: 8), Text('收款方式: $paymentMethodText'), const SizedBox(height: 4), Text('收款账号: ${_paymentAccountController.text.trim()}'), const SizedBox(height: 4), Text('收款人: ${_paymentRealNameController.text.trim()}'), ], const SizedBox(height: 16), Text( _selectedType == 0 ? '发布后,您的积分值将被冻结' : '发布后,您的积分股将被冻结', style: TextStyle(fontSize: 12, color: _grayText), ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('取消'), ), TextButton( onPressed: () => Navigator.pop(context, true), child: Text( '确认发布', style: TextStyle(color: _selectedType == 0 ? _green : _red), ), ), ], ), ); if (confirmed != true) return; final notifier = ref.read(c2cTradingNotifierProvider.notifier); final success = await notifier.createOrder( type: type, price: price, quantity: quantity, // 收款信息(卖单时传递) paymentMethod: isSell ? _paymentMethod : null, paymentAccount: isSell ? _paymentAccountController.text.trim() : null, paymentRealName: isSell ? _paymentRealNameController.text.trim() : null, remark: remark.isEmpty ? null : remark, ); if (success && mounted) { // 刷新列表 ref.invalidate(c2cOrdersProvider(type)); ref.invalidate(myC2cOrdersProvider); // 刷新资产 final user = ref.read(userNotifierProvider); ref.invalidate(accountAssetProvider(user.accountSequence ?? '')); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('广告发布成功'), backgroundColor: _green, ), ); context.pop(); } else if (mounted) { final error = ref.read(c2cTradingNotifierProvider).error; ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('发布失败: ${error ?? '未知错误'}'), backgroundColor: _red, ), ); } } }