import { Controller, Get, Post, Body, UseGuards, Headers, HttpException, HttpStatus } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiBearerAuth, ApiResponse } from '@nestjs/swagger'; import { WalletApplicationService } from '@/application/services'; import { GetMyWalletQuery } from '@/application/queries'; import { ClaimRewardsCommand, SettleRewardsCommand, RequestWithdrawalCommand } from '@/application/commands'; import { CurrentUser, CurrentUserPayload } from '@/shared/decorators'; import { JwtAuthGuard } from '@/shared/guards/jwt-auth.guard'; import { SettleRewardsDTO, RequestWithdrawalDTO } from '@/api/dto/request'; import { WalletResponseDTO, WithdrawalResponseDTO, WithdrawalListItemDTO } from '@/api/dto/response'; import { IdentityClientService } from '@/infrastructure/external/identity'; @ApiTags('Wallet') @Controller('wallet') @UseGuards(JwtAuthGuard) @ApiBearerAuth() export class WalletController { constructor( private readonly walletService: WalletApplicationService, private readonly identityClient: IdentityClientService, ) {} @Get('my-wallet') @ApiOperation({ summary: '查询我的钱包', description: '获取当前用户的钱包余额、算力和奖励信息' }) @ApiResponse({ status: 200, type: WalletResponseDTO }) async getMyWallet(@CurrentUser() user: CurrentUserPayload): Promise { const query = new GetMyWalletQuery( user.accountSequence, user.userId, ); return this.walletService.getMyWallet(query); } @Post('claim-rewards') @ApiOperation({ summary: '领取奖励', description: '将待领取的奖励转为可结算状态' }) @ApiResponse({ status: 200, description: '领取成功' }) async claimRewards(@CurrentUser() user: CurrentUserPayload): Promise<{ message: string }> { const command = new ClaimRewardsCommand(user.userId); await this.walletService.claimRewards(command); return { message: 'Rewards claimed successfully' }; } @Post('settle') @ApiOperation({ summary: '结算收益', description: '将可结算的USDT兑换为指定币种' }) @ApiResponse({ status: 200, description: '结算成功' }) async settleRewards( @CurrentUser() user: CurrentUserPayload, @Body() dto: SettleRewardsDTO, ): Promise<{ settlementOrderId: string }> { const command = new SettleRewardsCommand( user.userId, dto.usdtAmount, dto.settleCurrency, ); const orderId = await this.walletService.settleRewards(command); return { settlementOrderId: orderId }; } @Post('withdraw/send-sms') @ApiOperation({ summary: '发送提取验证短信', description: '向用户手机发送提取验证码' }) @ApiResponse({ status: 200, description: '发送成功' }) async sendWithdrawSms( @CurrentUser() user: CurrentUserPayload, @Headers('authorization') authHeader: string, ): Promise<{ message: string }> { const token = authHeader?.replace('Bearer ', '') || ''; // 调用 identity-service 发送短信验证码 await this.identityClient.sendWithdrawSmsCode(user.userId, token); return { message: '验证码已发送' }; } @Post('withdraw') @ApiOperation({ summary: '申请提现', description: '将USDT提现到指定地址,需要短信验证和密码验证' }) @ApiResponse({ status: 201, type: WithdrawalResponseDTO }) async requestWithdrawal( @CurrentUser() user: CurrentUserPayload, @Body() dto: RequestWithdrawalDTO, @Headers('authorization') authHeader: string, ): Promise { // 提取 JWT token const token = authHeader?.replace('Bearer ', '') || ''; // 验证短信验证码 if (!dto.smsCode) { throw new HttpException('请输入短信验证码', HttpStatus.BAD_REQUEST); } const isSmsValid = await this.identityClient.verifyWithdrawSmsCode(user.userId, dto.smsCode, token); if (!isSmsValid) { throw new HttpException('短信验证码错误,请重试', HttpStatus.BAD_REQUEST); } // 验证登录密码 if (!dto.password) { throw new HttpException('请输入登录密码', HttpStatus.BAD_REQUEST); } const isPasswordValid = await this.identityClient.verifyPassword(user.userId, dto.password, token); if (!isPasswordValid) { throw new HttpException('登录密码错误,请重试', HttpStatus.BAD_REQUEST); } // 处理 toAddress: 如果是 accountSequence 格式,转换为区块链地址 let actualAddress = dto.toAddress; if (dto.toAddress.startsWith('D') && dto.toAddress.length === 12) { // accountSequence 格式,需要查询对应的区块链地址 const resolvedAddress = await this.identityClient.resolveAccountSequenceToAddress( dto.toAddress, dto.chainType, token, ); if (!resolvedAddress) { throw new HttpException('无效的充值ID,未找到对应地址', HttpStatus.BAD_REQUEST); } actualAddress = resolvedAddress; } const command = new RequestWithdrawalCommand( user.userId, dto.amount, actualAddress, dto.chainType, ); return this.walletService.requestWithdrawal(command); } @Get('withdrawals') @ApiOperation({ summary: '查询提现记录', description: '获取用户的提现订单列表' }) @ApiResponse({ status: 200, type: [WithdrawalListItemDTO] }) async getWithdrawals( @CurrentUser() user: CurrentUserPayload, ): Promise { return this.walletService.getWithdrawals(user.userId); } @Get('pending-rewards') @ApiOperation({ summary: '查询待领取奖励列表', description: '获取用户的逐笔待领取奖励,包含过期时间' }) @ApiResponse({ status: 200, description: '待领取奖励列表' }) async getPendingRewards( @CurrentUser() user: CurrentUserPayload, ): Promise> { return this.walletService.getPendingRewards(user.accountSequence); } @Get('settleable-rewards') @ApiOperation({ summary: '查询可结算奖励列表', description: '获取用户的逐笔可结算奖励(已领取待结算)' }) @ApiResponse({ status: 200, description: '可结算奖励列表' }) async getSettleableRewards( @CurrentUser() user: CurrentUserPayload, ): Promise> { return this.walletService.getSettleableRewards(user.accountSequence); } @Get('expired-rewards') @ApiOperation({ summary: '查询已过期奖励列表', description: '获取用户的逐笔已过期奖励(24h未领取)' }) @ApiResponse({ status: 200, description: '已过期奖励列表' }) async getExpiredRewards( @CurrentUser() user: CurrentUserPayload, ): Promise> { return this.walletService.getExpiredRewards(user.accountSequence); } }