import { Body, Controller, Get, Param, Post, Put, Query, Res, UseGuards } from '@nestjs/common'; import type { Response } from 'express'; import { Transform } from 'class-transformer'; import { IsBoolean, IsOptional, IsString, MaxLength } from 'class-validator'; import { JwtAuthGuard, AuthUser } from '../../common/guards/jwt-auth.guard'; import { OptionalJwtAuthGuard } from '../../common/guards/optional-jwt-auth.guard'; import { PartnerPrimaryGuard } from '../../common/guards/partner-primary.guard'; import { PartnerPermissionGuard } from '../../common/guards/partner-permission.guard'; import { CurrentUser } from '../../common/decorators/current-user.decorator'; import { PartnerAssocService } from './partner-assoc.service'; class BindPartnerAssocDto { @IsOptional() @IsString() scene?: string; @IsOptional() @IsString() partnerId?: string; } class TouchPartnerAssocDto extends BindPartnerAssocDto { @IsOptional() @Transform(({ value }) => { if (value === false || value === 'false' || value === 0 || value === '0') return false; if (value === true || value === 'true' || value === 1 || value === '1') return true; return undefined; }) @IsBoolean() countScan?: boolean; } class PartnerAssocRemarkDto { @IsOptional() @IsString() @MaxLength(128) remark?: string | null; } @Controller('user/partner-assoc') export class UserPartnerAssocPublicController { constructor(private readonly assoc: PartnerAssocService) {} @Post('touch') @UseGuards(OptionalJwtAuthGuard) touch(@Body() dto: TouchPartnerAssocDto) { return this.assoc.touchScan({ scene: dto.scene, partnerId: dto.partnerId, countScan: dto.countScan, }); } } @Controller('user/partner-assoc') @UseGuards(JwtAuthGuard) export class UserPartnerAssocController { constructor(private readonly assoc: PartnerAssocService) {} @Post('bind') bind(@CurrentUser() user: AuthUser, @Body() dto: BindPartnerAssocDto) { return this.assoc.bindUser(user.actorId, dto); } } @Controller('partner/assoc') @UseGuards(JwtAuthGuard, PartnerPermissionGuard) export class PartnerAssocController { constructor(private readonly assoc: PartnerAssocService) {} @Get() summary(@CurrentUser() user: AuthUser) { return this.assoc.getSummary(user.actorId); } @Get('stats') stats(@CurrentUser() user: AuthUser) { return this.assoc.getStats(user.actorId); } @Get('orders') assocOrders( @CurrentUser() user: AuthUser, @Query('page') page = '1', @Query('pageSize') pageSize = '20', ) { return this.assoc.listAssocOrders(user.actorId, Number(page) || 1, Number(pageSize) || 20); } @Get('users') users( @CurrentUser() user: AuthUser, @Query('page') page = '1', @Query('pageSize') pageSize = '20', @Query('keyword') keyword?: string, @Query('sort') sort?: string, ) { const allowed = sort === 'createdAt' || sort === 'boundAt' || sort === 'orderCount' ? sort : undefined; return this.assoc.listUsers(user.actorId, Number(page) || 1, Number(pageSize) || 20, true, { keyword, sort: allowed, }); } @Get('users/:userId/orders') userOrders( @CurrentUser() user: AuthUser, @Param('userId') userId: string, @Query('page') page = '1', @Query('pageSize') pageSize = '20', ) { return this.assoc.listAssocOrders( user.actorId, Number(page) || 1, Number(pageSize) || 20, BigInt(userId), ); } @Put('users/:userId/remark') setRemark( @CurrentUser() user: AuthUser, @Param('userId') userId: string, @Body() dto: PartnerAssocRemarkDto, ) { return this.assoc.setUserRemark(user.actorId, BigInt(userId), dto.remark); } @Get('qrcode') async qrcode(@CurrentUser() user: AuthUser, @Res() res: Response) { const { buffer, fileName } = await this.assoc.getQrcodeBuffer(user.actorId); res.setHeader('Content-Type', 'image/png'); res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`); res.send(buffer); } } @Controller('partner/commissions') @UseGuards(JwtAuthGuard, PartnerPrimaryGuard) export class PartnerCommissionController { constructor(private readonly assoc: PartnerAssocService) {} @Get('orders') orders( @CurrentUser() user: AuthUser, @Query('page') page = '1', @Query('pageSize') pageSize = '20', ) { return this.assoc.listCommissionOrders(user.actorId, Number(page) || 1, Number(pageSize) || 20); } }