diff --git a/backend/services/mining-admin-service/src/api/api.module.ts b/backend/services/mining-admin-service/src/api/api.module.ts index 2e5bd2cc..b8066326 100644 --- a/backend/services/mining-admin-service/src/api/api.module.ts +++ b/backend/services/mining-admin-service/src/api/api.module.ts @@ -3,7 +3,6 @@ import { ApplicationModule } from '../application/application.module'; import { AuthController } from './controllers/auth.controller'; import { DashboardController } from './controllers/dashboard.controller'; import { ConfigController } from './controllers/config.controller'; -import { InitializationController } from './controllers/initialization.controller'; import { AuditController } from './controllers/audit.controller'; import { HealthController } from './controllers/health.controller'; import { UsersController } from './controllers/users.controller'; @@ -16,7 +15,6 @@ import { ReportsController } from './controllers/reports.controller'; AuthController, DashboardController, ConfigController, - InitializationController, AuditController, HealthController, UsersController, diff --git a/backend/services/mining-admin-service/src/api/controllers/initialization.controller.ts b/backend/services/mining-admin-service/src/api/controllers/initialization.controller.ts deleted file mode 100644 index fd0e524d..00000000 --- a/backend/services/mining-admin-service/src/api/controllers/initialization.controller.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { Controller, Post, Body, Req } from '@nestjs/common'; -import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger'; -import { InitializationService } from '../../application/services/initialization.service'; - -class InitMiningConfigDto { - totalShares: string; - distributionPool: string; - halvingPeriodYears: number; - burnTarget: string; -} - -@ApiTags('Initialization') -@ApiBearerAuth() -@Controller('initialization') -export class InitializationController { - constructor(private readonly initService: InitializationService) {} - - @Post('mining-config') - @ApiOperation({ summary: '初始化挖矿配置' }) - async initMiningConfig(@Body() dto: InitMiningConfigDto, @Req() req: any) { - return this.initService.initializeMiningConfig(req.admin.id, dto); - } - - @Post('system-accounts') - @ApiOperation({ summary: '初始化系统账户' }) - async initSystemAccounts(@Req() req: any) { - return this.initService.initializeSystemAccounts(req.admin.id); - } - - @Post('activate-mining') - @ApiOperation({ summary: '激活挖矿' }) - async activateMining(@Req() req: any) { - return this.initService.activateMining(req.admin.id); - } - - @Post('sync-users') - @ApiOperation({ summary: '同步所有用户数据(从auth-service初始同步)' }) - async syncUsers(@Req() req: any) { - return this.initService.syncAllUsers(req.admin.id); - } - - @Post('sync-contribution-accounts') - @ApiOperation({ summary: '同步所有算力账户(从contribution-service初始同步)' }) - async syncContributionAccounts(@Req() req: any) { - return this.initService.syncAllContributionAccounts(req.admin.id); - } - - @Post('sync-mining-accounts') - @ApiOperation({ summary: '同步所有挖矿账户(从mining-service初始同步)' }) - async syncMiningAccounts(@Req() req: any) { - return this.initService.syncAllMiningAccounts(req.admin.id); - } - - @Post('sync-trading-accounts') - @ApiOperation({ summary: '同步所有交易账户(从trading-service初始同步)' }) - async syncTradingAccounts(@Req() req: any) { - return this.initService.syncAllTradingAccounts(req.admin.id); - } - - @Post('sync-all') - @ApiOperation({ summary: '执行完整的数据同步(用户+算力+挖矿+交易)' }) - async syncAll(@Req() req: any) { - const adminId = req.admin.id; - const results = { - users: await this.initService.syncAllUsers(adminId), - contribution: await this.initService.syncAllContributionAccounts(adminId), - mining: await this.initService.syncAllMiningAccounts(adminId), - trading: await this.initService.syncAllTradingAccounts(adminId), - }; - - return { - success: true, - message: '全部同步完成', - details: results, - }; - } -} diff --git a/backend/services/mining-admin-service/src/application/application.module.ts b/backend/services/mining-admin-service/src/application/application.module.ts index ea15f370..5a250c49 100644 --- a/backend/services/mining-admin-service/src/application/application.module.ts +++ b/backend/services/mining-admin-service/src/application/application.module.ts @@ -2,7 +2,6 @@ import { Module, OnModuleInit } from '@nestjs/common'; import { InfrastructureModule } from '../infrastructure/infrastructure.module'; import { AuthService } from './services/auth.service'; import { ConfigManagementService } from './services/config.service'; -import { InitializationService } from './services/initialization.service'; import { DashboardService } from './services/dashboard.service'; import { UsersService } from './services/users.service'; import { SystemAccountsService } from './services/system-accounts.service'; @@ -13,7 +12,6 @@ import { DailyReportService } from './services/daily-report.service'; providers: [ AuthService, ConfigManagementService, - InitializationService, DashboardService, UsersService, SystemAccountsService, @@ -22,7 +20,6 @@ import { DailyReportService } from './services/daily-report.service'; exports: [ AuthService, ConfigManagementService, - InitializationService, DashboardService, UsersService, SystemAccountsService, diff --git a/backend/services/mining-admin-service/src/application/services/initialization.service.ts b/backend/services/mining-admin-service/src/application/services/initialization.service.ts deleted file mode 100644 index b5e4ceb1..00000000 --- a/backend/services/mining-admin-service/src/application/services/initialization.service.ts +++ /dev/null @@ -1,304 +0,0 @@ -import { Injectable, Logger } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; -import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service'; - -@Injectable() -export class InitializationService { - private readonly logger = new Logger(InitializationService.name); - - constructor( - private readonly prisma: PrismaService, - private readonly configService: ConfigService, - ) {} - - async initializeMiningConfig( - adminId: string, - config: { - totalShares: string; - distributionPool: string; - halvingPeriodYears: number; - burnTarget: string; - }, - ): Promise<{ success: boolean; message: string }> { - const record = await this.prisma.initializationRecord.create({ - data: { type: 'MINING_CONFIG', status: 'PENDING', config, executedBy: adminId }, - }); - - try { - const miningServiceUrl = this.configService.get('MINING_SERVICE_URL', 'http://localhost:3021'); - const response = await fetch(`${miningServiceUrl}/api/v1/admin/initialize`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(config), - }); - - if (!response.ok) { - throw new Error('Failed to initialize mining config'); - } - - await this.prisma.initializationRecord.update({ - where: { id: record.id }, - data: { status: 'COMPLETED', executedAt: new Date() }, - }); - - await this.prisma.auditLog.create({ - data: { adminId, action: 'INIT', resource: 'MINING', resourceId: record.id, newValue: config }, - }); - - return { success: true, message: 'Mining config initialized successfully' }; - } catch (error: any) { - await this.prisma.initializationRecord.update({ - where: { id: record.id }, - data: { status: 'FAILED', errorMessage: error.message }, - }); - - return { success: false, message: error.message }; - } - } - - async initializeSystemAccounts(adminId: string): Promise<{ success: boolean; message: string }> { - const accounts = [ - { accountType: 'OPERATION', name: '运营账户', description: '12% 运营收入' }, - { accountType: 'PROVINCE', name: '省公司账户', description: '1% 省公司收入' }, - { accountType: 'CITY', name: '市公司账户', description: '2% 市公司收入' }, - ]; - - for (const account of accounts) { - await this.prisma.systemAccount.upsert({ - where: { accountType: account.accountType }, - create: account, - update: { name: account.name, description: account.description }, - }); - } - - await this.prisma.auditLog.create({ - data: { adminId, action: 'INIT', resource: 'SYSTEM_ACCOUNT', newValue: accounts }, - }); - - return { success: true, message: 'System accounts initialized successfully' }; - } - - async activateMining(adminId: string): Promise<{ success: boolean; message: string }> { - try { - const miningServiceUrl = this.configService.get('MINING_SERVICE_URL', 'http://localhost:3021'); - const response = await fetch(`${miningServiceUrl}/api/v1/admin/activate`, { method: 'POST' }); - - if (!response.ok) { - throw new Error('Failed to activate mining'); - } - - await this.prisma.auditLog.create({ - data: { adminId, action: 'INIT', resource: 'MINING', newValue: { action: 'ACTIVATE' } }, - }); - - return { success: true, message: 'Mining activated successfully' }; - } catch (error: any) { - return { success: false, message: error.message }; - } - } - - async syncAllUsers(adminId: string): Promise<{ success: boolean; message: string; syncedCount?: number }> { - try { - const authServiceUrl = this.configService.get('AUTH_SERVICE_URL', 'http://localhost:3024'); - const response = await fetch(`${authServiceUrl}/api/v2/admin/users/sync`); - - if (!response.ok) { - throw new Error(`Failed to fetch users: ${response.statusText}`); - } - - const responseData = await response.json(); - const users = responseData.data?.users || responseData.users || []; - let syncedCount = 0; - - for (const user of users) { - try { - await this.prisma.syncedUser.upsert({ - where: { accountSequence: user.accountSequence }, - create: { - originalUserId: user.id || user.accountSequence, - accountSequence: user.accountSequence, - phone: user.phone, - status: user.status || 'ACTIVE', - kycStatus: user.kycStatus || 'PENDING', - realName: user.realName || null, - isLegacyUser: user.isLegacyUser || false, - createdAt: new Date(user.createdAt), - }, - update: { - phone: user.phone, - status: user.status || 'ACTIVE', - kycStatus: user.kycStatus || 'PENDING', - realName: user.realName || null, - }, - }); - syncedCount++; - } catch (err) { - this.logger.warn(`Failed to sync user ${user.accountSequence}: ${err}`); - } - } - - await this.prisma.auditLog.create({ - data: { adminId, action: 'SYNC', resource: 'USER', newValue: { syncedCount } }, - }); - - return { success: true, message: `Synced ${syncedCount} users`, syncedCount }; - } catch (error: any) { - return { success: false, message: error.message }; - } - } - - async syncAllContributionAccounts(adminId: string): Promise<{ success: boolean; message: string; syncedCount?: number }> { - try { - const contributionServiceUrl = this.configService.get('CONTRIBUTION_SERVICE_URL', 'http://localhost:3020'); - const response = await fetch(`${contributionServiceUrl}/api/v2/admin/accounts/sync`); - - if (!response.ok) { - throw new Error(`Failed to fetch accounts: ${response.statusText}`); - } - - const responseData = await response.json(); - const accounts = responseData.data?.accounts || responseData.accounts || []; - let syncedCount = 0; - - for (const account of accounts) { - try { - await this.prisma.syncedContributionAccount.upsert({ - where: { accountSequence: account.accountSequence }, - create: { - accountSequence: account.accountSequence, - personalContribution: account.personalContribution || 0, - teamLevelContribution: account.teamLevelContribution || 0, - teamBonusContribution: account.teamBonusContribution || 0, - totalContribution: account.totalContribution || 0, - effectiveContribution: account.effectiveContribution || 0, - hasAdopted: account.hasAdopted || false, - directReferralCount: account.directReferralAdoptedCount || 0, - unlockedLevelDepth: account.unlockedLevelDepth || 0, - unlockedBonusTiers: account.unlockedBonusTiers || 0, - }, - update: { - personalContribution: account.personalContribution, - teamLevelContribution: account.teamLevelContribution, - teamBonusContribution: account.teamBonusContribution, - totalContribution: account.totalContribution, - effectiveContribution: account.effectiveContribution, - hasAdopted: account.hasAdopted, - directReferralCount: account.directReferralAdoptedCount, - unlockedLevelDepth: account.unlockedLevelDepth, - unlockedBonusTiers: account.unlockedBonusTiers, - }, - }); - syncedCount++; - } catch (err) { - this.logger.warn(`Failed to sync account ${account.accountSequence}: ${err}`); - } - } - - await this.prisma.auditLog.create({ - data: { adminId, action: 'SYNC', resource: 'CONTRIBUTION_ACCOUNT', newValue: { syncedCount } }, - }); - - return { success: true, message: `Synced ${syncedCount} accounts`, syncedCount }; - } catch (error: any) { - return { success: false, message: error.message }; - } - } - - async syncAllMiningAccounts(adminId: string): Promise<{ success: boolean; message: string; syncedCount?: number }> { - try { - const miningServiceUrl = this.configService.get('MINING_SERVICE_URL', 'http://localhost:3021'); - const response = await fetch(`${miningServiceUrl}/api/v1/admin/accounts/sync`); - - if (!response.ok) { - throw new Error(`Failed to fetch accounts: ${response.statusText}`); - } - - const responseData = await response.json(); - const accounts = responseData.data?.accounts || responseData.accounts || []; - let syncedCount = 0; - - for (const account of accounts) { - try { - await this.prisma.syncedMiningAccount.upsert({ - where: { accountSequence: account.accountSequence }, - create: { - accountSequence: account.accountSequence, - totalMined: account.totalMined || 0, - availableBalance: account.availableBalance || 0, - frozenBalance: account.frozenBalance || 0, - totalContribution: account.totalContribution || 0, - }, - update: { - totalMined: account.totalMined, - availableBalance: account.availableBalance, - frozenBalance: account.frozenBalance, - totalContribution: account.totalContribution, - }, - }); - syncedCount++; - } catch (err) { - this.logger.warn(`Failed to sync mining account ${account.accountSequence}: ${err}`); - } - } - - await this.prisma.auditLog.create({ - data: { adminId, action: 'SYNC', resource: 'MINING_ACCOUNT', newValue: { syncedCount } }, - }); - - return { success: true, message: `Synced ${syncedCount} mining accounts`, syncedCount }; - } catch (error: any) { - return { success: false, message: error.message }; - } - } - - async syncAllTradingAccounts(adminId: string): Promise<{ success: boolean; message: string; syncedCount?: number }> { - try { - const tradingServiceUrl = this.configService.get('TRADING_SERVICE_URL', 'http://localhost:3022'); - const response = await fetch(`${tradingServiceUrl}/api/v1/admin/accounts/sync`); - - if (!response.ok) { - throw new Error(`Failed to fetch accounts: ${response.statusText}`); - } - - const responseData = await response.json(); - const accounts = responseData.data?.accounts || responseData.accounts || []; - let syncedCount = 0; - - for (const account of accounts) { - try { - await this.prisma.syncedTradingAccount.upsert({ - where: { accountSequence: account.accountSequence }, - create: { - accountSequence: account.accountSequence, - shareBalance: account.shareBalance || 0, - cashBalance: account.cashBalance || 0, - frozenShares: account.frozenShares || 0, - frozenCash: account.frozenCash || 0, - totalBought: account.totalBought || 0, - totalSold: account.totalSold || 0, - }, - update: { - shareBalance: account.shareBalance, - cashBalance: account.cashBalance, - frozenShares: account.frozenShares, - frozenCash: account.frozenCash, - totalBought: account.totalBought, - totalSold: account.totalSold, - }, - }); - syncedCount++; - } catch (err) { - this.logger.warn(`Failed to sync trading account ${account.accountSequence}: ${err}`); - } - } - - await this.prisma.auditLog.create({ - data: { adminId, action: 'SYNC', resource: 'TRADING_ACCOUNT', newValue: { syncedCount } }, - }); - - return { success: true, message: `Synced ${syncedCount} trading accounts`, syncedCount }; - } catch (error: any) { - return { success: false, message: error.message }; - } - } -} diff --git a/frontend/mining-admin-web/src/app/(dashboard)/initialization/page.tsx b/frontend/mining-admin-web/src/app/(dashboard)/initialization/page.tsx deleted file mode 100644 index ecf0687a..00000000 --- a/frontend/mining-admin-web/src/app/(dashboard)/initialization/page.tsx +++ /dev/null @@ -1,168 +0,0 @@ -'use client'; - -import { useState } from 'react'; -import { PageHeader } from '@/components/layout/page-header'; -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; -import { apiClient } from '@/lib/api/client'; -import { formatDateTime } from '@/lib/utils/date'; -import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; -import { Button } from '@/components/ui/button'; -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/dialog'; -import { Skeleton } from '@/components/ui/skeleton'; -import { useToast } from '@/lib/hooks/use-toast'; -import { Play, CheckCircle, AlertCircle, Loader2 } from 'lucide-react'; - -interface InitializationStatus { - initialized: boolean; - initializedAt: string | null; - initializedBy: string | null; - distributionPoolBalance: string; - blackHoleBalance: string; - circulationPoolBalance: string; -} - -export default function InitializationPage() { - const queryClient = useQueryClient(); - const { toast } = useToast(); - const [showConfirm, setShowConfirm] = useState(false); - - const { data: status, isLoading } = useQuery({ - queryKey: ['initialization', 'status'], - queryFn: async () => { - const response = await apiClient.get('/initialization/status'); - return response.data.data as InitializationStatus; - }, - }); - - const initializeMutation = useMutation({ - mutationFn: async () => { - const response = await apiClient.post('/initialization/initialize'); - return response.data; - }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['initialization', 'status'] }); - toast({ title: '初始化成功', variant: 'success' as any }); - setShowConfirm(false); - }, - onError: () => { - toast({ title: '初始化失败', variant: 'destructive' }); - }, - }); - - const handleInitialize = () => { - initializeMutation.mutate(); - }; - - return ( -
- - - - - 初始化状态 - 查看系统是否已完成初始化 - - - {isLoading ? ( - - ) : ( -
-
- {status?.initialized ? ( - <> - -
-

系统已初始化

-

- 初始化时间: {formatDateTime(status.initializedAt)} -

-

操作人: {status.initializedBy}

-
- - ) : ( - <> - -
-

系统未初始化

-

请点击下方按钮进行系统初始化

-
- - )} -
- - {!status?.initialized && ( - - )} -
- )} -
-
- - {status?.initialized && ( - - - 系统账户余额 - - -
-
-

分配池

-

{status.distributionPoolBalance}

-
-
-

黑洞

-

{status.blackHoleBalance}

-
-
-

流通池

-

{status.circulationPoolBalance}

-
-
-
-
- )} - - - - 初始化说明 - - -

系统初始化将执行以下操作:

-
    -
  1. 创建分配池账户,初始余额为 2 亿积分股
  2. -
  3. 创建黑洞账户,初始余额为 0
  4. -
  5. 创建流通池账户,初始余额为 0
  6. -
  7. 创建系统运营账户 (12% 分配比例)
  8. -
  9. 创建系统省级账户 (1% 分配比例)
  10. -
  11. 创建系统市级账户 (2% 分配比例)
  12. -
  13. 初始化系统配置参数
  14. -
-

注意: 初始化操作只能执行一次,请谨慎操作。

-
-
- - - - - 确认初始化 - - 系统初始化操作只能执行一次,确定要开始初始化吗? - - - - - - - - -
- ); -} diff --git a/frontend/mining-admin-web/src/components/layout/sidebar.tsx b/frontend/mining-admin-web/src/components/layout/sidebar.tsx index abcdc2bd..754846cc 100644 --- a/frontend/mining-admin-web/src/components/layout/sidebar.tsx +++ b/frontend/mining-admin-web/src/components/layout/sidebar.tsx @@ -11,7 +11,6 @@ import { Building2, FileBarChart, ClipboardList, - Play, ChevronLeft, ChevronRight, } from 'lucide-react'; @@ -24,7 +23,6 @@ const menuItems = [ { name: '系统账户', href: '/system-accounts', icon: Building2 }, { name: '报表统计', href: '/reports', icon: FileBarChart }, { name: '审计日志', href: '/audit-logs', icon: ClipboardList }, - { name: '初始化', href: '/initialization', icon: Play }, ]; export function Sidebar() {