feat(mining-app): 市场数据3个小数字段显示后端返回的完整精度

原先 formatCompact/formatWithCommas 内部用 double 运算,double 有效精度
仅约15-16位,对大数值(如98亿)除以1e8后小数部分会丢失精度。
后端 3 个字段均为 Decimal(30,8),通过 toFixed(8) 返回 8 位小数。

新增 formatCompactFull / formatWithCommasFull 函数:
- _shiftDecimalLeft: 纯字符串小数点移位,不经 double 转换,零精度损失
- _addCommasFullPrecision: 整数部分加千位逗号 + 小数部分原样保留
- formatCompactFull: 万/亿缩写 + 完整后端精度(替代 formatCompact)
- formatWithCommasFull: 逗号分隔 + 完整后端精度(替代 formatWithCommas)

兑换页 (trading_page.dart) 修改:
- 剩余积分股: formatCompact(precision:4) → formatCompactFull (8位小数)
- 已分配积分股: formatCompact(precision:2) → formatCompactFull (8位小数)
- 积分股池: formatWithCommas → formatWithCommasFull (8位小数)
- 已销毁量: 保持 formatIntWithCommas 整数显示不变

贡献值页 (contribution_page.dart) 修改:
- 100亿销毁剩余量: formatAmount(4位) → formatCompactFull (完整精度)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-03-02 23:58:58 -08:00
parent af2afeda56
commit 1e31d6d863
3 changed files with 93 additions and 6 deletions

View File

@ -44,6 +44,94 @@ String formatWithCommas(String? value) {
}
}
/// [positions]
/// e.g., _shiftDecimalLeft("9813194959.8105", 8) "98.131949598105"
String _shiftDecimalLeft(String numStr, int positions) {
String sign = '';
String v = numStr.trim();
if (v.startsWith('-')) {
sign = '-';
v = v.substring(1);
}
String intPart, decPart;
final dotIndex = v.indexOf('.');
if (dotIndex >= 0) {
intPart = v.substring(0, dotIndex);
decPart = v.substring(dotIndex + 1);
} else {
intPart = v;
decPart = '';
}
String digits = intPart + decPart;
int newDecPos = intPart.length - positions;
while (newDecPos <= 0) {
digits = '0$digits';
newDecPos++;
}
final newInt = digits.substring(0, newDecPos);
var newDec = digits.substring(newDecPos);
newDec = newDec.replaceFirst(RegExp(r'0+$'), '');
if (newDec.isEmpty) return '$sign$newInt';
return '$sign$newInt.$newDec';
}
/// +
String _addCommasFullPrecision(String numStr) {
String sign = '';
String v = numStr.trim();
if (v.startsWith('-')) {
sign = '-';
v = v.substring(1);
}
String intPart, decPart;
final dotIndex = v.indexOf('.');
if (dotIndex >= 0) {
intPart = v.substring(0, dotIndex);
decPart = v.substring(dotIndex); //
} else {
intPart = v;
decPart = '';
}
final formatted = NumberFormat('#,##0', 'zh_CN').format(int.parse(intPart));
if (decPart.isNotEmpty) {
decPart = decPart.replaceFirst(RegExp(r'0+$'), '');
if (decPart == '.') decPart = '';
}
return '$sign$formatted$decPart';
}
/// formatCompact /亿使
String formatCompactFull(String? value) {
if (value == null || value.isEmpty) return '0';
try {
final d = Decimal.parse(value);
final abs = d.abs();
if (abs >= Decimal.parse('1000000000000')) {
return '${_shiftDecimalLeft(value, 12)}万亿';
}
if (abs >= Decimal.parse('100000000')) {
return '${_shiftDecimalLeft(value, 8)}亿';
}
if (abs >= Decimal.parse('10000')) {
return '${_shiftDecimalLeft(value, 4)}';
}
return _addCommasFullPrecision(value);
} catch (e) {
return '0';
}
}
/// + double
String formatWithCommasFull(String? value) {
if (value == null || value.isEmpty) return '0';
try {
Decimal.parse(value); // validate
return _addCommasFullPrecision(value);
} catch (e) {
return '0';
}
}
/// +
String formatIntWithCommas(String? value) {
if (value == null || value.isEmpty) return '0';

View File

@ -231,7 +231,7 @@ class ContributionPage extends ConsumerWidget {
hideAmounts
? '******'
: market != null
? formatAmount(
? formatCompactFull(
(Decimal.parse(market.totalShares) -
Decimal.parse(market.totalMined) -
Decimal.parse(market.blackHoleAmount))

View File

@ -360,12 +360,11 @@ class _TradingPageState extends ConsumerState<TradingPage> {
_buildMarketDataItem(
'剩余积分股',
market != null
? formatCompact(
? formatCompactFull(
(Decimal.parse(market.totalShares) -
Decimal.parse(market.totalMined) -
Decimal.parse(market.blackHoleAmount))
.toString(),
precision: 4)
.toString())
: null,
_orange,
isLoading,
@ -376,7 +375,7 @@ class _TradingPageState extends ConsumerState<TradingPage> {
// circulationPool0
_buildMarketDataItem(
'已分配积分股',
market != null ? formatCompact(market.totalMined) : null,
market != null ? formatCompactFull(market.totalMined) : null,
_orange,
isLoading,
),
@ -389,7 +388,7 @@ class _TradingPageState extends ConsumerState<TradingPage> {
children: [
_buildMarketDataItem(
'积分股池',
market != null ? formatWithCommas(market.greenPoints) : null,
market != null ? formatWithCommasFull(market.greenPoints) : null,
_orange,
isLoading,
),