From eccc637a0274514c575cf9b1d125830544cfc30a Mon Sep 17 00:00:00 2001 From: hailin Date: Wed, 7 Jan 2026 21:15:28 -0800 Subject: [PATCH] =?UTF-8?q?fix(admin-service):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E9=87=91=E9=A2=9D=E6=98=BE=E7=A4=BA=E5=8D=95=E4=BD=8D=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除错误的 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 --- .../api/controllers/user-detail.controller.ts | 56 +++++++-------- .../user-detail-query.repository.ts | 50 +++++++------- .../user-detail-query.repository.impl.ts | 68 +++++++++---------- 3 files changed, 81 insertions(+), 93 deletions(-) diff --git a/backend/services/admin-service/src/api/controllers/user-detail.controller.ts b/backend/services/admin-service/src/api/controllers/user-detail.controller.ts index 77728593..dacb2b90 100644 --- a/backend/services/admin-service/src/api/controllers/user-detail.controller.ts +++ b/backend/services/admin-service/src/api/controllers/user-detail.controller.ts @@ -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+$/, ''); - } } diff --git a/backend/services/admin-service/src/domain/repositories/user-detail-query.repository.ts b/backend/services/admin-service/src/domain/repositories/user-detail-query.repository.ts index e04198f3..0fdd8ab3 100644 --- a/backend/services/admin-service/src/domain/repositories/user-detail-query.repository.ts +++ b/backend/services/admin-service/src/domain/repositories/user-detail-query.repository.ts @@ -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; diff --git a/backend/services/admin-service/src/infrastructure/persistence/repositories/user-detail-query.repository.impl.ts b/backend/services/admin-service/src/infrastructure/persistence/repositories/user-detail-query.repository.impl.ts index 8be7ddc5..4b1b61ea 100644 --- a/backend/services/admin-service/src/infrastructure/persistence/repositories/user-detail-query.repository.impl.ts +++ b/backend/services/admin-service/src/infrastructure/persistence/repositories/user-detail-query.repository.impl.ts @@ -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+$/, ''); } }