fix(admin-service): 修复金额显示单位错误

移除错误的 1e8 乘除转换:
- 数据库存储的是实际金额 (Decimal(20,8)),不需要缩放
- decimalToBigint → decimalToString: 直接格式化为字符串
- 移除 controller 中不再需要的 formatDecimal 方法
- 更新接口类型: bigint → string (金额相关字段)

影响的接口:
- PlantingSummary.totalAmount
- PlantingLedgerItem.totalAmount
- WalletSummary 所有余额字段
- WalletLedgerItem.amount/balanceAfter
- SystemAccountLedger.amount/balanceAfter

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-01-07 21:15:28 -08:00
parent 1c5fd9eaad
commit eccc637a02
3 changed files with 81 additions and 93 deletions

View File

@ -217,7 +217,7 @@ export class UserDetailController {
summary: {
totalOrders: summary?.totalOrders || 0,
totalTreeCount: summary?.totalTreeCount || 0,
totalAmount: this.formatDecimal(summary?.totalAmount),
totalAmount: summary?.totalAmount || '0',
effectiveTreeCount: summary?.effectiveTreeCount || 0,
pendingTreeCount: summary?.pendingTreeCount || 0,
firstPlantingAt: summary?.firstPlantingAt?.toISOString() || null,
@ -227,7 +227,7 @@ export class UserDetailController {
orderId: item.orderId.toString(),
orderNo: item.orderNo,
treeCount: item.treeCount,
totalAmount: this.formatDecimal(item.totalAmount),
totalAmount: item.totalAmount,
status: item.status,
selectedProvince: item.selectedProvince,
selectedCity: item.selectedCity,
@ -281,32 +281,32 @@ export class UserDetailController {
return {
summary: {
usdtAvailable: this.formatDecimal(summary?.usdtAvailable),
usdtFrozen: this.formatDecimal(summary?.usdtFrozen),
dstAvailable: this.formatDecimal(summary?.dstAvailable),
dstFrozen: this.formatDecimal(summary?.dstFrozen),
bnbAvailable: this.formatDecimal(summary?.bnbAvailable),
bnbFrozen: this.formatDecimal(summary?.bnbFrozen),
ogAvailable: this.formatDecimal(summary?.ogAvailable),
ogFrozen: this.formatDecimal(summary?.ogFrozen),
rwadAvailable: this.formatDecimal(summary?.rwadAvailable),
rwadFrozen: this.formatDecimal(summary?.rwadFrozen),
hashpower: this.formatDecimal(summary?.hashpower),
pendingUsdt: this.formatDecimal(summary?.pendingUsdt),
pendingHashpower: this.formatDecimal(summary?.pendingHashpower),
settleableUsdt: this.formatDecimal(summary?.settleableUsdt),
settleableHashpower: this.formatDecimal(summary?.settleableHashpower),
settledTotalUsdt: this.formatDecimal(summary?.settledTotalUsdt),
settledTotalHashpower: this.formatDecimal(summary?.settledTotalHashpower),
expiredTotalUsdt: this.formatDecimal(summary?.expiredTotalUsdt),
expiredTotalHashpower: this.formatDecimal(summary?.expiredTotalHashpower),
usdtAvailable: summary?.usdtAvailable || '0',
usdtFrozen: summary?.usdtFrozen || '0',
dstAvailable: summary?.dstAvailable || '0',
dstFrozen: summary?.dstFrozen || '0',
bnbAvailable: summary?.bnbAvailable || '0',
bnbFrozen: summary?.bnbFrozen || '0',
ogAvailable: summary?.ogAvailable || '0',
ogFrozen: summary?.ogFrozen || '0',
rwadAvailable: summary?.rwadAvailable || '0',
rwadFrozen: summary?.rwadFrozen || '0',
hashpower: summary?.hashpower || '0',
pendingUsdt: summary?.pendingUsdt || '0',
pendingHashpower: summary?.pendingHashpower || '0',
settleableUsdt: summary?.settleableUsdt || '0',
settleableHashpower: summary?.settleableHashpower || '0',
settledTotalUsdt: summary?.settledTotalUsdt || '0',
settledTotalHashpower: summary?.settledTotalHashpower || '0',
expiredTotalUsdt: summary?.expiredTotalUsdt || '0',
expiredTotalHashpower: summary?.expiredTotalHashpower || '0',
},
items: ledger.items.map((item) => ({
entryId: item.entryId.toString(),
entryType: item.entryType,
assetType: item.assetType,
amount: this.formatDecimal(item.amount),
balanceAfter: item.balanceAfter ? this.formatDecimal(item.balanceAfter) : null,
amount: item.amount,
balanceAfter: item.balanceAfter,
refOrderId: item.refOrderId,
refTxHash: item.refTxHash,
memo: item.memo,
@ -380,8 +380,8 @@ export class UserDetailController {
accountId: ledger.accountId.toString(),
accountType: ledger.accountType,
entryType: ledger.entryType,
amount: this.formatDecimal(ledger.amount),
balanceAfter: this.formatDecimal(ledger.balanceAfter),
amount: ledger.amount,
balanceAfter: ledger.balanceAfter,
sourceOrderId: ledger.sourceOrderId?.toString() || null,
sourceRewardId: ledger.sourceRewardId?.toString() || null,
txHash: ledger.txHash,
@ -408,10 +408,4 @@ export class UserDetailController {
}
}
private formatDecimal(value: bigint | null | undefined): string {
if (!value) return '0';
// bigint 已经乘以 1e8需要转回小数
const num = Number(value) / 1e8;
return num.toFixed(8).replace(/\.?0+$/, '');
}
}

View File

@ -36,7 +36,7 @@ export interface ReferralNode {
export interface PlantingSummary {
totalOrders: number;
totalTreeCount: number;
totalAmount: bigint; // Decimal as bigint for precision
totalAmount: string; // 格式化后的金额字符串
effectiveTreeCount: number;
pendingTreeCount: number;
firstPlantingAt: Date | null;
@ -47,7 +47,7 @@ export interface PlantingLedgerItem {
orderId: bigint;
orderNo: string;
treeCount: number;
totalAmount: bigint;
totalAmount: string; // 格式化后的金额字符串
status: string;
selectedProvince: string | null;
selectedCity: string | null;
@ -70,33 +70,33 @@ export interface PlantingLedgerResult {
// ============================================================================
export interface WalletSummary {
usdtAvailable: bigint;
usdtFrozen: bigint;
dstAvailable: bigint;
dstFrozen: bigint;
bnbAvailable: bigint;
bnbFrozen: bigint;
ogAvailable: bigint;
ogFrozen: bigint;
rwadAvailable: bigint;
rwadFrozen: bigint;
hashpower: bigint;
pendingUsdt: bigint;
pendingHashpower: bigint;
settleableUsdt: bigint;
settleableHashpower: bigint;
settledTotalUsdt: bigint;
settledTotalHashpower: bigint;
expiredTotalUsdt: bigint;
expiredTotalHashpower: bigint;
usdtAvailable: string;
usdtFrozen: string;
dstAvailable: string;
dstFrozen: string;
bnbAvailable: string;
bnbFrozen: string;
ogAvailable: string;
ogFrozen: string;
rwadAvailable: string;
rwadFrozen: string;
hashpower: string;
pendingUsdt: string;
pendingHashpower: string;
settleableUsdt: string;
settleableHashpower: string;
settledTotalUsdt: string;
settledTotalHashpower: string;
expiredTotalUsdt: string;
expiredTotalHashpower: string;
}
export interface WalletLedgerItem {
entryId: bigint;
entryType: string;
assetType: string;
amount: bigint;
balanceAfter: bigint | null;
amount: string; // 格式化后的金额字符串
balanceAfter: string | null; // 格式化后的余额字符串
refOrderId: string | null;
refTxHash: string | null;
memo: string | null;
@ -164,8 +164,8 @@ export interface SystemAccountLedger {
accountId: bigint;
accountType: string;
entryType: string;
amount: bigint;
balanceAfter: bigint;
amount: string; // 格式化后的金额字符串
balanceAfter: string; // 格式化后的余额字符串
sourceOrderId: bigint | null;
sourceRewardId: bigint | null;
txHash: string | null;

View File

@ -208,7 +208,7 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
return {
totalOrders: orderStats._count,
totalTreeCount: orderStats._sum.treeCount || 0,
totalAmount: this.decimalToBigint(orderStats._sum.totalAmount),
totalAmount: this.decimalToString(orderStats._sum.totalAmount),
effectiveTreeCount: position?.effectiveTreeCount || 0,
pendingTreeCount: position?.pendingTreeCount || 0,
firstPlantingAt: firstOrder?.paidAt || null,
@ -246,7 +246,7 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
orderId: item.id,
orderNo: item.orderNo,
treeCount: item.treeCount,
totalAmount: this.decimalToBigint(item.totalAmount),
totalAmount: this.decimalToString(item.totalAmount),
status: item.status,
selectedProvince: item.selectedProvince,
selectedCity: item.selectedCity,
@ -278,25 +278,25 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
if (!wallet) return null;
return {
usdtAvailable: this.decimalToBigint(wallet.usdtAvailable),
usdtFrozen: this.decimalToBigint(wallet.usdtFrozen),
dstAvailable: this.decimalToBigint(wallet.dstAvailable),
dstFrozen: this.decimalToBigint(wallet.dstFrozen),
bnbAvailable: this.decimalToBigint(wallet.bnbAvailable),
bnbFrozen: this.decimalToBigint(wallet.bnbFrozen),
ogAvailable: this.decimalToBigint(wallet.ogAvailable),
ogFrozen: this.decimalToBigint(wallet.ogFrozen),
rwadAvailable: this.decimalToBigint(wallet.rwadAvailable),
rwadFrozen: this.decimalToBigint(wallet.rwadFrozen),
hashpower: this.decimalToBigint(wallet.hashpower),
pendingUsdt: this.decimalToBigint(wallet.pendingUsdt),
pendingHashpower: this.decimalToBigint(wallet.pendingHashpower),
settleableUsdt: this.decimalToBigint(wallet.settleableUsdt),
settleableHashpower: this.decimalToBigint(wallet.settleableHashpower),
settledTotalUsdt: this.decimalToBigint(wallet.settledTotalUsdt),
settledTotalHashpower: this.decimalToBigint(wallet.settledTotalHashpower),
expiredTotalUsdt: this.decimalToBigint(wallet.expiredTotalUsdt),
expiredTotalHashpower: this.decimalToBigint(wallet.expiredTotalHashpower),
usdtAvailable: this.decimalToString(wallet.usdtAvailable),
usdtFrozen: this.decimalToString(wallet.usdtFrozen),
dstAvailable: this.decimalToString(wallet.dstAvailable),
dstFrozen: this.decimalToString(wallet.dstFrozen),
bnbAvailable: this.decimalToString(wallet.bnbAvailable),
bnbFrozen: this.decimalToString(wallet.bnbFrozen),
ogAvailable: this.decimalToString(wallet.ogAvailable),
ogFrozen: this.decimalToString(wallet.ogFrozen),
rwadAvailable: this.decimalToString(wallet.rwadAvailable),
rwadFrozen: this.decimalToString(wallet.rwadFrozen),
hashpower: this.decimalToString(wallet.hashpower),
pendingUsdt: this.decimalToString(wallet.pendingUsdt),
pendingHashpower: this.decimalToString(wallet.pendingHashpower),
settleableUsdt: this.decimalToString(wallet.settleableUsdt),
settleableHashpower: this.decimalToString(wallet.settleableHashpower),
settledTotalUsdt: this.decimalToString(wallet.settledTotalUsdt),
settledTotalHashpower: this.decimalToString(wallet.settledTotalHashpower),
expiredTotalUsdt: this.decimalToString(wallet.expiredTotalUsdt),
expiredTotalHashpower: this.decimalToString(wallet.expiredTotalHashpower),
};
}
@ -337,8 +337,8 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
entryId: item.id,
entryType: item.entryType,
assetType: item.assetType,
amount: this.decimalToBigint(item.amount),
balanceAfter: item.balanceAfter ? this.decimalToBigint(item.balanceAfter) : null,
amount: this.decimalToString(item.amount),
balanceAfter: item.balanceAfter ? this.decimalToString(item.balanceAfter) : null,
refOrderId: item.refOrderId,
refTxHash: item.refTxHash,
memo: item.memo,
@ -431,19 +431,13 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
// 辅助方法
// ============================================================================
private decimalToBigint(decimal: Decimal | null | undefined): bigint {
if (!decimal) return BigInt(0);
// 转换为字符串后解析,保留精度
const str = decimal.toString();
// 移除小数点,按整数处理
const parts = str.split('.');
if (parts.length === 1) {
return BigInt(parts[0]);
}
// 有小数部分,乘以 10^小数位数
const scale = parts[1].length;
const intPart = parts[0] + parts[1];
// 返回原始数值(不做缩放,保持 decimal 格式)
return BigInt(Math.round(parseFloat(str) * 1e8));
/**
* Decimal
* 8
*/
private decimalToString(decimal: Decimal | null | undefined): string {
if (!decimal) return '0';
// 直接转字符串,去掉尾部多余的 0
return decimal.toFixed(8).replace(/\.?0+$/, '');
}
}