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:
parent
af2afeda56
commit
1e31d6d863
|
|
@ -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) {
|
String formatIntWithCommas(String? value) {
|
||||||
if (value == null || value.isEmpty) return '0';
|
if (value == null || value.isEmpty) return '0';
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ class ContributionPage extends ConsumerWidget {
|
||||||
hideAmounts
|
hideAmounts
|
||||||
? '******'
|
? '******'
|
||||||
: market != null
|
: market != null
|
||||||
? formatAmount(
|
? formatCompactFull(
|
||||||
(Decimal.parse(market.totalShares) -
|
(Decimal.parse(market.totalShares) -
|
||||||
Decimal.parse(market.totalMined) -
|
Decimal.parse(market.totalMined) -
|
||||||
Decimal.parse(market.blackHoleAmount))
|
Decimal.parse(market.blackHoleAmount))
|
||||||
|
|
|
||||||
|
|
@ -360,12 +360,11 @@ class _TradingPageState extends ConsumerState<TradingPage> {
|
||||||
_buildMarketDataItem(
|
_buildMarketDataItem(
|
||||||
'剩余积分股',
|
'剩余积分股',
|
||||||
market != null
|
market != null
|
||||||
? formatCompact(
|
? formatCompactFull(
|
||||||
(Decimal.parse(market.totalShares) -
|
(Decimal.parse(market.totalShares) -
|
||||||
Decimal.parse(market.totalMined) -
|
Decimal.parse(market.totalMined) -
|
||||||
Decimal.parse(market.blackHoleAmount))
|
Decimal.parse(market.blackHoleAmount))
|
||||||
.toString(),
|
.toString())
|
||||||
precision: 4)
|
|
||||||
: null,
|
: null,
|
||||||
_orange,
|
_orange,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
|
@ -376,7 +375,7 @@ class _TradingPageState extends ConsumerState<TradingPage> {
|
||||||
// 而非交易流通池(circulationPool,目前无交易故为0)
|
// 而非交易流通池(circulationPool,目前无交易故为0)
|
||||||
_buildMarketDataItem(
|
_buildMarketDataItem(
|
||||||
'已分配积分股',
|
'已分配积分股',
|
||||||
market != null ? formatCompact(market.totalMined) : null,
|
market != null ? formatCompactFull(market.totalMined) : null,
|
||||||
_orange,
|
_orange,
|
||||||
isLoading,
|
isLoading,
|
||||||
),
|
),
|
||||||
|
|
@ -389,7 +388,7 @@ class _TradingPageState extends ConsumerState<TradingPage> {
|
||||||
children: [
|
children: [
|
||||||
_buildMarketDataItem(
|
_buildMarketDataItem(
|
||||||
'积分股池',
|
'积分股池',
|
||||||
market != null ? formatWithCommas(market.greenPoints) : null,
|
market != null ? formatWithCommasFull(market.greenPoints) : null,
|
||||||
_orange,
|
_orange,
|
||||||
isLoading,
|
isLoading,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue