221 lines
6.3 KiB
TypeScript
221 lines
6.3 KiB
TypeScript
/**
|
||
* System Withdrawal Controller
|
||
*
|
||
* 系统账户转出管理 API
|
||
* 仅供内部管理后台调用
|
||
*/
|
||
|
||
import {
|
||
Controller,
|
||
Get,
|
||
Post,
|
||
Body,
|
||
Query,
|
||
Logger,
|
||
BadRequestException,
|
||
} from '@nestjs/common';
|
||
import {
|
||
ApiTags,
|
||
ApiOperation,
|
||
ApiResponse,
|
||
ApiQuery,
|
||
ApiBody,
|
||
} from '@nestjs/swagger';
|
||
import { Public } from '@/shared/decorators';
|
||
import { SystemWithdrawalApplicationService } from '@/application/services';
|
||
|
||
// DTO 定义
|
||
class SystemWithdrawalRequestDTO {
|
||
fromAccountSequence: string;
|
||
toAccountSequence: string;
|
||
amount: number;
|
||
memo?: string;
|
||
operatorId: string;
|
||
operatorName?: string;
|
||
}
|
||
|
||
/**
|
||
* 系统账户转出控制器
|
||
* 供管理后台调用,用于从系统账户转出资金到用户账户
|
||
*/
|
||
@ApiTags('System Withdrawal (Internal)')
|
||
@Controller('system-withdrawal')
|
||
export class SystemWithdrawalController {
|
||
private readonly logger = new Logger(SystemWithdrawalController.name);
|
||
|
||
constructor(
|
||
private readonly systemWithdrawalService: SystemWithdrawalApplicationService,
|
||
) {}
|
||
|
||
/**
|
||
* 发起系统账户转出
|
||
*/
|
||
@Post('request')
|
||
@Public()
|
||
@ApiOperation({
|
||
summary: '发起系统账户转出(内部API)',
|
||
description: '从系统账户(总部、运营、区域等)转出资金到用户账户',
|
||
})
|
||
@ApiBody({
|
||
schema: {
|
||
type: 'object',
|
||
required: ['fromAccountSequence', 'toAccountSequence', 'amount', 'operatorId'],
|
||
properties: {
|
||
fromAccountSequence: {
|
||
type: 'string',
|
||
description: '转出方系统账户序列号',
|
||
example: 'S0000000003',
|
||
},
|
||
toAccountSequence: {
|
||
type: 'string',
|
||
description: '接收方用户充值ID',
|
||
example: 'D25122800032',
|
||
},
|
||
amount: {
|
||
type: 'number',
|
||
description: '转出金额(绿积分)',
|
||
example: 1000,
|
||
},
|
||
memo: {
|
||
type: 'string',
|
||
description: '备注',
|
||
example: '补发奖励',
|
||
},
|
||
operatorId: {
|
||
type: 'string',
|
||
description: '操作管理员ID',
|
||
example: 'admin_001',
|
||
},
|
||
operatorName: {
|
||
type: 'string',
|
||
description: '操作管理员姓名',
|
||
example: '管理员张三',
|
||
},
|
||
},
|
||
},
|
||
})
|
||
@ApiResponse({ status: 200, description: '转出订单创建成功' })
|
||
@ApiResponse({ status: 400, description: '参数错误或余额不足' })
|
||
async requestSystemWithdrawal(@Body() dto: SystemWithdrawalRequestDTO) {
|
||
this.logger.log(`[REQUEST] 系统账户转出请求: ${JSON.stringify(dto)}`);
|
||
|
||
// 验证必填参数
|
||
if (!dto.fromAccountSequence) {
|
||
throw new BadRequestException('转出账户不能为空');
|
||
}
|
||
if (!dto.toAccountSequence) {
|
||
throw new BadRequestException('接收账户不能为空');
|
||
}
|
||
if (!dto.amount || dto.amount <= 0) {
|
||
throw new BadRequestException('转出金额必须大于0');
|
||
}
|
||
if (!dto.operatorId) {
|
||
throw new BadRequestException('操作员ID不能为空');
|
||
}
|
||
|
||
const result = await this.systemWithdrawalService.requestSystemWithdrawal({
|
||
fromAccountSequence: dto.fromAccountSequence,
|
||
toAccountSequence: dto.toAccountSequence,
|
||
amount: dto.amount,
|
||
memo: dto.memo,
|
||
operatorId: dto.operatorId,
|
||
operatorName: dto.operatorName,
|
||
});
|
||
|
||
this.logger.log(`[REQUEST] 转出订单创建成功: ${result.orderNo}`);
|
||
|
||
return {
|
||
success: true,
|
||
data: result,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 获取可转出的系统账户列表
|
||
*/
|
||
@Get('accounts')
|
||
@Public()
|
||
@ApiOperation({
|
||
summary: '获取可转出的系统账户列表(内部API)',
|
||
description: '获取所有允许转出的系统账户及其余额',
|
||
})
|
||
@ApiResponse({ status: 200, description: '系统账户列表' })
|
||
async getWithdrawableAccounts() {
|
||
this.logger.log('[ACCOUNTS] 查询可转出系统账户');
|
||
|
||
const accounts = await this.systemWithdrawalService.getWithdrawableSystemAccounts();
|
||
|
||
return {
|
||
success: true,
|
||
data: accounts,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 查询转出订单列表
|
||
*/
|
||
@Get('orders')
|
||
@Public()
|
||
@ApiOperation({
|
||
summary: '查询系统账户转出订单列表(内部API)',
|
||
description: '分页查询系统账户转出订单',
|
||
})
|
||
@ApiQuery({ name: 'fromAccountSequence', required: false, description: '转出账户筛选' })
|
||
@ApiQuery({ name: 'toAccountSequence', required: false, description: '接收账户筛选' })
|
||
@ApiQuery({ name: 'status', required: false, description: '状态筛选 (PENDING/FROZEN/CONFIRMED/FAILED)' })
|
||
@ApiQuery({ name: 'page', required: false, description: '页码,默认1' })
|
||
@ApiQuery({ name: 'pageSize', required: false, description: '每页数量,默认20' })
|
||
@ApiResponse({ status: 200, description: '订单列表' })
|
||
async getOrders(
|
||
@Query('fromAccountSequence') fromAccountSequence?: string,
|
||
@Query('toAccountSequence') toAccountSequence?: string,
|
||
@Query('status') status?: string,
|
||
@Query('page') page?: string,
|
||
@Query('pageSize') pageSize?: string,
|
||
) {
|
||
this.logger.log(`[ORDERS] 查询转出订单: from=${fromAccountSequence}, to=${toAccountSequence}, status=${status}`);
|
||
|
||
const result = await this.systemWithdrawalService.getSystemWithdrawalOrders({
|
||
fromAccountSequence,
|
||
toAccountSequence,
|
||
status,
|
||
page: page ? parseInt(page, 10) : 1,
|
||
pageSize: pageSize ? parseInt(pageSize, 10) : 20,
|
||
});
|
||
|
||
return {
|
||
success: true,
|
||
data: result,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 获取系统账户名称
|
||
*/
|
||
@Get('account-name')
|
||
@Public()
|
||
@ApiOperation({
|
||
summary: '获取系统账户名称(内部API)',
|
||
description: '根据账户序列号获取系统账户的显示名称',
|
||
})
|
||
@ApiQuery({ name: 'accountSequence', required: true, description: '账户序列号' })
|
||
@ApiResponse({ status: 200, description: '账户名称' })
|
||
async getAccountName(@Query('accountSequence') accountSequence: string) {
|
||
if (!accountSequence) {
|
||
throw new BadRequestException('账户序列号不能为空');
|
||
}
|
||
|
||
const name = this.systemWithdrawalService.getSystemAccountName(accountSequence);
|
||
const isAllowed = this.systemWithdrawalService.isWithdrawalAllowed(accountSequence);
|
||
|
||
return {
|
||
success: true,
|
||
data: {
|
||
accountSequence,
|
||
name,
|
||
isWithdrawalAllowed: isAllowed,
|
||
},
|
||
};
|
||
}
|
||
}
|