206 lines
5.3 KiB
TypeScript
206 lines
5.3 KiB
TypeScript
import { Injectable, Logger, HttpException, HttpStatus } from '@nestjs/common';
|
|
import { ConfigService } from '@nestjs/config';
|
|
import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service';
|
|
|
|
export interface ManualMiningCalculateRequest {
|
|
accountSequence: string;
|
|
adoptionDate: string;
|
|
}
|
|
|
|
export interface ManualMiningExecuteRequest {
|
|
accountSequence: string;
|
|
adoptionDate: string;
|
|
operatorId: string;
|
|
operatorName: string;
|
|
reason: string;
|
|
}
|
|
|
|
/**
|
|
* 手工补发挖矿服务 - 管理后台层
|
|
* 负责调用 mining-service 的内部 API
|
|
*/
|
|
@Injectable()
|
|
export class ManualMiningService {
|
|
private readonly logger = new Logger(ManualMiningService.name);
|
|
private readonly miningServiceUrl: string;
|
|
|
|
constructor(
|
|
private readonly prisma: PrismaService,
|
|
private readonly configService: ConfigService,
|
|
) {
|
|
this.miningServiceUrl = this.configService.get<string>(
|
|
'MINING_SERVICE_URL',
|
|
'http://localhost:3021',
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 计算预估补发金额
|
|
*/
|
|
async calculate(request: ManualMiningCalculateRequest): Promise<any> {
|
|
try {
|
|
const response = await fetch(
|
|
`${this.miningServiceUrl}/admin/manual-mining/calculate`,
|
|
{
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(request),
|
|
},
|
|
);
|
|
|
|
const result = await response.json();
|
|
|
|
if (!response.ok) {
|
|
throw new HttpException(
|
|
result.message || '计算失败',
|
|
response.status,
|
|
);
|
|
}
|
|
|
|
return result;
|
|
} catch (error) {
|
|
if (error instanceof HttpException) {
|
|
throw error;
|
|
}
|
|
this.logger.error('Failed to calculate manual mining', error);
|
|
throw new HttpException(
|
|
`调用 mining-service 失败: ${error instanceof Error ? error.message : error}`,
|
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 执行手工补发
|
|
*/
|
|
async execute(
|
|
request: ManualMiningExecuteRequest,
|
|
adminId: string,
|
|
): Promise<any> {
|
|
try {
|
|
const response = await fetch(
|
|
`${this.miningServiceUrl}/admin/manual-mining/execute`,
|
|
{
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(request),
|
|
},
|
|
);
|
|
|
|
const result = await response.json();
|
|
|
|
if (!response.ok) {
|
|
throw new HttpException(
|
|
result.message || '执行失败',
|
|
response.status,
|
|
);
|
|
}
|
|
|
|
// 记录审计日志
|
|
await this.prisma.auditLog.create({
|
|
data: {
|
|
adminId,
|
|
action: 'CREATE',
|
|
resource: 'MANUAL_MINING',
|
|
resourceId: result.recordId,
|
|
newValue: {
|
|
accountSequence: request.accountSequence,
|
|
adoptionDate: request.adoptionDate,
|
|
amount: result.amount,
|
|
reason: request.reason,
|
|
},
|
|
},
|
|
});
|
|
|
|
this.logger.log(
|
|
`Manual mining executed by admin ${adminId}: account=${request.accountSequence}, amount=${result.amount}`,
|
|
);
|
|
|
|
return result;
|
|
} catch (error) {
|
|
if (error instanceof HttpException) {
|
|
throw error;
|
|
}
|
|
this.logger.error('Failed to execute manual mining', error);
|
|
throw new HttpException(
|
|
`调用 mining-service 失败: ${error instanceof Error ? error.message : error}`,
|
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取补发记录列表
|
|
*/
|
|
async getRecords(page: number = 1, pageSize: number = 20): Promise<any> {
|
|
try {
|
|
const response = await fetch(
|
|
`${this.miningServiceUrl}/admin/manual-mining/records?page=${page}&pageSize=${pageSize}`,
|
|
{
|
|
method: 'GET',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
},
|
|
);
|
|
|
|
const result = await response.json();
|
|
|
|
if (!response.ok) {
|
|
throw new HttpException(
|
|
result.message || '获取记录失败',
|
|
response.status,
|
|
);
|
|
}
|
|
|
|
return result;
|
|
} catch (error) {
|
|
if (error instanceof HttpException) {
|
|
throw error;
|
|
}
|
|
this.logger.error('Failed to get manual mining records', error);
|
|
throw new HttpException(
|
|
`调用 mining-service 失败: ${error instanceof Error ? error.message : error}`,
|
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 根据 accountSequence 获取补发记录
|
|
*/
|
|
async getRecordByAccountSequence(accountSequence: string): Promise<any> {
|
|
try {
|
|
const response = await fetch(
|
|
`${this.miningServiceUrl}/admin/manual-mining/records/${accountSequence}`,
|
|
{
|
|
method: 'GET',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
},
|
|
);
|
|
|
|
if (response.status === 404) {
|
|
return null;
|
|
}
|
|
|
|
const result = await response.json();
|
|
|
|
if (!response.ok) {
|
|
throw new HttpException(
|
|
result.message || '获取记录失败',
|
|
response.status,
|
|
);
|
|
}
|
|
|
|
return result;
|
|
} catch (error) {
|
|
if (error instanceof HttpException) {
|
|
throw error;
|
|
}
|
|
this.logger.error('Failed to get manual mining record', error);
|
|
throw new HttpException(
|
|
`调用 mining-service 失败: ${error instanceof Error ? error.message : error}`,
|
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
}
|