This commit is contained in:
2026-04-08 02:13:29 +08:00
12 changed files with 903 additions and 82 deletions

View File

@@ -1 +1 @@
{"version":2,"files":[{"path":"D:\\flutter\\bin\\cache\\dart-sdk\\version","hash":"800169ad7335b889bf428af171476466"},{"path":"D:\\workspace\\project\\com-rattan-spccloud\\flutter_monisuo\\.dart_tool\\package_config.json","hash":"d6b4a7aa67aeb750be9e5aec884f1f73"},{"path":"D:\\workspace\\project\\com-rattan-spccloud\\flutter_monisuo\\pubspec.yaml","hash":"03c567345af5a72ca098cfa0a67b3423"},{"path":"D:\\workspace\\project\\com-rattan-spccloud\\flutter_monisuo\\build\\9a5d09bec60a9bd952a3f584c1b9bd3b\\dart_build_result.json","hash":"92b3cbdc74276047205a9d2c62d9222f"},{"path":"D:\\flutter\\packages\\flutter_tools\\lib\\src\\build_system\\targets\\native_assets.dart","hash":"f78c405bcece3968277b212042da9ed6"},{"path":"d:\\workspace\\project\\com-rattan-spccloud\\flutter_monisuo\\.dart_tool\\package_config.json","hash":"d6b4a7aa67aeb750be9e5aec884f1f73"}]}
{"version":2,"files":[{"path":"D:\\flutter\\bin\\cache\\dart-sdk\\version","hash":"800169ad7335b889bf428af171476466"},{"path":"D:\\workspace\\project\\com-rattan-spccloud\\flutter_monisuo\\.dart_tool\\package_config.json","hash":"046ef7e2da888c543069af4aac7edaaf"},{"path":"D:\\workspace\\project\\com-rattan-spccloud\\flutter_monisuo\\pubspec.yaml","hash":"48b58d9876a092c0f3058304ec7c663a"},{"path":"D:\\workspace\\project\\com-rattan-spccloud\\flutter_monisuo\\build\\9a5d09bec60a9bd952a3f584c1b9bd3b\\dart_build_result.json","hash":"b04615af5d7000fefcedb23fde3ace71"},{"path":"D:\\flutter\\packages\\flutter_tools\\lib\\src\\build_system\\targets\\native_assets.dart","hash":"f78c405bcece3968277b212042da9ed6"},{"path":"d:\\workspace\\project\\com-rattan-spccloud\\flutter_monisuo\\.dart_tool\\package_config.json","hash":"046ef7e2da888c543069af4aac7edaaf"}]}

View File

@@ -1 +1 @@
{"build_start":"2026-04-06T18:39:07.915511","build_end":"2026-04-06T18:39:11.314962","dependencies":["file:///D:/flutter/bin/cache/dart-sdk/version","file:///D:/workspace/project/com-rattan-spccloud/flutter_monisuo/.dart_tool/package_config.json","file:///D:/workspace/project/com-rattan-spccloud/flutter_monisuo/pubspec.yaml","file:///d:/workspace/project/com-rattan-spccloud/flutter_monisuo/.dart_tool/package_config.json"],"code_assets":[],"data_assets":[]}
{"build_start":"2026-04-07T23:07:26.594437","build_end":"2026-04-07T23:07:33.162061","dependencies":["file:///D:/flutter/bin/cache/dart-sdk/version","file:///D:/workspace/project/com-rattan-spccloud/flutter_monisuo/.dart_tool/package_config.json","file:///D:/workspace/project/com-rattan-spccloud/flutter_monisuo/pubspec.yaml","file:///d:/workspace/project/com-rattan-spccloud/flutter_monisuo/.dart_tool/package_config.json"],"code_assets":[],"data_assets":[]}

View File

@@ -140,9 +140,11 @@ class _TransferPageState extends State<TransferPage> {
void _setQuickAmount(double percent) {
final available = double.tryParse(_availableBalance) ?? 0;
final amount = available * percent;
_amountController.text = amount
.toStringAsFixed(8)
.replaceAll(RegExp(r'\.?0+$'), '');
// 向下截斷到2位小數避免四捨五入超出餘額
_amountController.text =
((amount * 100).truncateToDouble() / 100).toStringAsFixed(2);
// Trigger haptic feedback
HapticFeedback.selectionClick();
}

View File

@@ -88,6 +88,11 @@ class _FundOrderCard extends StatelessWidget {
final isDeposit = order.type == 1;
final statusColor = _getStatusColor(order.status, isDeposit);
// 已出款的提現訂單顯示到賬金額,其餘顯示應付金額
final displayAmount = (!isDeposit && order.status == 2 && order.receivableAmount != null)
? order.receivableAmount
: order.amount;
return ShadCard(
padding: AppSpacing.cardPadding,
child: Column(
@@ -97,7 +102,7 @@ class _FundOrderCard extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${isDeposit ? '+' : '-'}${order.amount} USDT',
'${isDeposit ? '+' : '-'}$displayAmount USDT',
style: AppTextStyles.headlineMedium(context).copyWith(
color: statusColor,
fontWeight: FontWeight.w700,

View File

@@ -340,7 +340,7 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
const SizedBox(height: AppSpacing.sm - AppSpacing.xs),
],
if (order.fee != null && !order.isDeposit) ...[
_buildDetailRow('手續費', '${order.fee}%'),
_buildDetailRow('手續費', '${order.fee} USDT'),
const SizedBox(height: AppSpacing.sm - AppSpacing.xs),
],
_buildDetailRow(
@@ -400,7 +400,7 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('應付金額', style: AppTextStyles.headlineSmall(context).copyWith(color: context.colors.onSurfaceVariant)),
Text(order.status == 2 ? '到賬金額' : '應付金額', style: AppTextStyles.headlineSmall(context).copyWith(color: context.colors.onSurfaceVariant)),
Text('${order.receivableAmount} USDT', style: AppTextStyles.headlineMedium(context).copyWith(color: context.colors.onSurface)),
],
),

View File

@@ -97,19 +97,27 @@ class _TradePageState extends State<TradePage>
if (_tradeType == 0) {
return _availableUsdt;
} else {
// 賣出qty * price 截斷到2位
final qty = double.tryParse(_availableCoinQty) ?? 0;
return (qty * price).toStringAsFixed(2);
return ((qty * price * 100).truncateToDouble() / 100).toStringAsFixed(2);
}
}
/// 計算數量
/// 計算數量向下截斷到4位小數確保 price * quantity <= amount
String get _calculatedQuantity {
final amount = double.tryParse(_amountController.text) ?? 0;
final price = _selectedCoin?.price ?? 0;
if (price <= 0 || amount <= 0) return '0';
// 向下截斷到4位小數避免回算超出金額
final qty = amount / price;
return ((qty * 10000).truncateToDouble() / 10000).toStringAsFixed(4);
// 使用與後端一致的截斷邏輯先算原始數量截斷到4位再回算金額確保不超
final rawQty = amount / price;
final truncatedQty = (rawQty * 10000).truncateToDouble() / 10000;
// 回算roundedPrice * truncatedQty確保不超過 amount
final roundedPrice = (price * 100).truncateToDouble() / 100;
if (roundedPrice * truncatedQty > amount) {
// 回退一個最小單位0.0001
return (truncatedQty - 0.0001).toStringAsFixed(4);
}
return truncatedQty.toStringAsFixed(4);
}
@override
@@ -208,11 +216,16 @@ class _TradePageState extends State<TradePage>
void _fillPercent(double pct) {
final max = double.tryParse(_maxAmount) ?? 0;
final value = max * pct;
// 向下截斷到2位小數避免四捨五入超出可用餘額
// 向下截斷到2位小數再減0.01作為安全緩衝,避免精度問題導致餘額不足
final truncated = ((value * 100).truncateToDouble() / 100);
final safe = truncated > 0.01 ? truncated - 0.01 : truncated;
_amountController.text = safe.toStringAsFixed(2);
if (_tradeType == 0) {
// 買入向下截斷到2位小數
_amountController.text =
((value * 100).truncateToDouble() / 100).toStringAsFixed(2);
} else {
// 賣出_maxAmount 已是 qty*price 的四捨五入值,直接截斷
_amountController.text =
((value * 100).truncateToDouble() / 100).toStringAsFixed(2);
}
setState(() {});
}