diff --git a/backend/services/mining-admin-service/src/application/services/dashboard.service.ts b/backend/services/mining-admin-service/src/application/services/dashboard.service.ts index b6a796fe..0d36b49d 100644 --- a/backend/services/mining-admin-service/src/application/services/dashboard.service.ts +++ b/backend/services/mining-admin-service/src/application/services/dashboard.service.ts @@ -220,8 +220,119 @@ export class DashboardService { /** * 获取详细算力分解统计(按用户需求) + * 优先从 contribution-service API 获取完整数据(包含 pending), + * 如果 API 调用失败则回退到本地数据 */ private async getDetailedContributionStats() { + // 尝试从 contribution-service 获取完整数据 + const contributionServiceData = await this.fetchContributionServiceStats(); + if (contributionServiceData) { + return contributionServiceData; + } + + // 回退:从本地同步数据计算 + return this.getDetailedContributionStatsFromLocal(); + } + + /** + * 从 contribution-service API 获取详细算力统计 + */ + private async fetchContributionServiceStats(): Promise { + const contributionServiceUrl = this.configService.get( + 'CONTRIBUTION_SERVICE_URL', + 'http://localhost:3020', + ); + + try { + const response = await fetch(`${contributionServiceUrl}/api/v2/contribution/stats`); + if (!response.ok) { + this.logger.warn(`Contribution service returned ${response.status}`); + return null; + } + + const result = await response.json(); + const data = result.data || result; + + // 获取系统账户实际值(本地数据) + const systemAccounts = await this.prisma.syncedSystemContribution.findMany(); + let operationActual = new Decimal(0); + let provinceActual = new Decimal(0); + let cityActual = new Decimal(0); + for (const account of systemAccounts) { + const balance = new Decimal(account.contributionBalance || 0); + if (account.accountType === 'OPERATION') operationActual = operationActual.plus(balance); + else if (account.accountType === 'PROVINCE') provinceActual = provinceActual.plus(balance); + else if (account.accountType === 'CITY') cityActual = cityActual.plus(balance); + } + + return { + totalTrees: data.totalTrees || 0, + // 理论值 + networkTotalTheory: data.networkTotalContribution || '0', + personalTheory: data.personalTotalContribution || '0', + operationTheory: data.operationTotalContribution || '0', + provinceTheory: data.provinceTotalContribution || '0', + cityTheory: data.cityTotalContribution || '0', + levelTheory: data.levelContribution?.total || '0', + bonusTheory: data.bonusContribution?.total || '0', + + // 实际值 + operationActual: operationActual.toString(), + provinceActual: provinceActual.toString(), + cityActual: cityActual.toString(), + + // 层级算力详情(包含正确的 pending 数据) + levelContribution: { + total: data.levelContribution?.total || '0', + unlocked: data.levelContribution?.unlocked || '0', + pending: data.levelContribution?.pending || '0', + byTier: { + tier1: { + unlocked: data.levelContribution?.byTier?.tier1?.unlocked || '0', + pending: data.levelContribution?.byTier?.tier1?.pending || '0', + }, + tier2: { + unlocked: data.levelContribution?.byTier?.tier2?.unlocked || '0', + pending: data.levelContribution?.byTier?.tier2?.pending || '0', + }, + tier3: { + unlocked: data.levelContribution?.byTier?.tier3?.unlocked || '0', + pending: data.levelContribution?.byTier?.tier3?.pending || '0', + }, + }, + }, + + // 团队奖励算力详情(包含正确的 pending 数据) + bonusContribution: { + total: data.bonusContribution?.total || '0', + unlocked: data.bonusContribution?.unlocked || '0', + pending: data.bonusContribution?.pending || '0', + byTier: { + tier1: { + unlocked: data.bonusContribution?.byTier?.tier1?.unlocked || '0', + pending: data.bonusContribution?.byTier?.tier1?.pending || '0', + }, + tier2: { + unlocked: data.bonusContribution?.byTier?.tier2?.unlocked || '0', + pending: data.bonusContribution?.byTier?.tier2?.pending || '0', + }, + tier3: { + unlocked: data.bonusContribution?.byTier?.tier3?.unlocked || '0', + pending: data.bonusContribution?.byTier?.tier3?.pending || '0', + }, + }, + }, + }; + } catch (error) { + this.logger.warn(`Failed to fetch contribution service stats: ${error.message}`); + return null; + } + } + + /** + * 从本地同步数据计算详细算力统计(回退方案) + */ + private async getDetailedContributionStatsFromLocal() { // 获取总树数 const adoptionStats = await this.prisma.syncedAdoption.aggregate({ where: { status: 'MINING_ENABLED' }, @@ -288,7 +399,7 @@ export class DashboardService { const levelTheory = networkTotal.mul(RATE_LEVEL_TOTAL); const bonusTheory = networkTotal.mul(RATE_BONUS_TOTAL); - // 计算未解锁(理论 - 已解锁) + // 计算未解锁(理论 - 已解锁)- 仅用于总数,各档位无法获取 const levelPending = levelTheory.minus(levelUnlocked).greaterThan(0) ? levelTheory.minus(levelUnlocked) : new Decimal(0); @@ -323,27 +434,27 @@ export class DashboardService { provinceActual: provinceActual.toString(), cityActual: cityActual.toString(), - // 层级算力详情 + // 层级算力详情(本地无法获取各档位 pending,显示为 N/A) levelContribution: { total: levelTheory.toString(), unlocked: levelUnlocked.toString(), pending: levelPending.toString(), byTier: { - tier1: { unlocked: levelTier1.toString(), pending: '0' }, - tier2: { unlocked: levelTier2.toString(), pending: '0' }, - tier3: { unlocked: levelTier3.toString(), pending: '0' }, + tier1: { unlocked: levelTier1.toString(), pending: 'N/A' }, + tier2: { unlocked: levelTier2.toString(), pending: 'N/A' }, + tier3: { unlocked: levelTier3.toString(), pending: 'N/A' }, }, }, - // 团队奖励算力详情 + // 团队奖励算力详情(本地无法获取各档位 pending,显示为 N/A) bonusContribution: { total: bonusTheory.toString(), unlocked: bonusUnlocked.toString(), pending: bonusPending.toString(), byTier: { - tier1: { unlocked: bonusTier1.toString(), pending: '0' }, - tier2: { unlocked: bonusTier2.toString(), pending: '0' }, - tier3: { unlocked: bonusTier3.toString(), pending: '0' }, + tier1: { unlocked: bonusTier1.toString(), pending: 'N/A' }, + tier2: { unlocked: bonusTier2.toString(), pending: 'N/A' }, + tier3: { unlocked: bonusTier3.toString(), pending: 'N/A' }, }, }, }; diff --git a/backend/services/mining-service/src/application/services/mining-distribution.service.ts b/backend/services/mining-service/src/application/services/mining-distribution.service.ts index 28069b61..09baaeca 100644 --- a/backend/services/mining-service/src/application/services/mining-distribution.service.ts +++ b/backend/services/mining-service/src/application/services/mining-distribution.service.ts @@ -726,7 +726,7 @@ export class MiningDistributionService { remainingDistribution: newRemaining.toString(), halvingPeriodYears: config.halvingPeriodYears, currentEra: config.currentEra, - minuteDistribution: config.minuteDistribution.toString(), + secondDistribution: config.secondDistribution.toString(), isActive: config.isActive, activatedAt: config.activatedAt?.toISOString(), },