diff --git a/apps/backend-nest/src/filters/http-exception.filter.ts b/apps/backend-nest/src/filters/http-exception.filter.ts new file mode 100644 index 00000000000..cdcac0a6ae5 --- /dev/null +++ b/apps/backend-nest/src/filters/http-exception.filter.ts @@ -0,0 +1,42 @@ +import type { ArgumentsHost, ExceptionFilter } from '@nestjs/common'; +import type { Response } from 'express'; + +import { BadRequestException, Catch, HttpException } from '@nestjs/common'; + +import { ResponseClass } from '#/interfaces/response'; + +@Catch(HttpException) +export class HttpExceptionFilter implements ExceptionFilter { + catch(exception: HttpException, host: ArgumentsHost) { + const ctx = host.switchToHttp(); + const response = ctx.getResponse(); + const status = exception.getStatus(); + const results = exception.getResponse() as any; + + // eslint-disable-next-line unicorn/throw-new-error + const result = ResponseClass.Error(results.message); + + // 参数校验错误,默认都是BadRequestException + const isArrayMessage = Array.isArray(results.message); + const isValidationError = + isArrayMessage && + typeof results.message[0] === 'string' && + results.message[0].includes('⓿'); + if (exception instanceof BadRequestException && isValidationError) { + const message: Array<{ field: string; message: Array }> = []; + results.message.forEach((item: string) => { + const [key, val] = item.split('⓿') as [string, string]; + const findData = message.find((item) => item.field === key); + if (findData) { + findData.message.push(val); + } else { + message.push({ field: key, message: [val] }); + } + }); + + result.error = message; + } + + return response.status(status).json(result); + } +} diff --git a/apps/backend-nest/src/interceptor/transform.interceptor.ts b/apps/backend-nest/src/interceptor/transform.interceptor.ts new file mode 100644 index 00000000000..a813ad06eeb --- /dev/null +++ b/apps/backend-nest/src/interceptor/transform.interceptor.ts @@ -0,0 +1,23 @@ +import type { + CallHandler, + ExecutionContext, + NestInterceptor, +} from '@nestjs/common'; + +import { Injectable } from '@nestjs/common'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +import { ResponseClass } from '#/interfaces/response'; + +@Injectable() +export class TransformInterceptor + implements NestInterceptor> +{ + intercept( + _: ExecutionContext, + next: CallHandler, + ): Observable> { + return next.handle().pipe(map((data) => ResponseClass.Success(data))); + } +} diff --git a/apps/backend-nest/src/interfaces/response.ts b/apps/backend-nest/src/interfaces/response.ts new file mode 100644 index 00000000000..40696012845 --- /dev/null +++ b/apps/backend-nest/src/interfaces/response.ts @@ -0,0 +1,49 @@ +export class ResponseClass { + constructor( + public code: number, + public data: T, + public error: any, + public message: string | string[], + ) {} + + static Error(message: string | string[], error: any = null) { + return new ResponseClass(-1, null, error, message); + } + + static PageSuccess( + page: number | string, + pageSize: number | string, + list: T[], + { message = 'ok' } = {}, + ) { + const pageData = pagination( + Number.parseInt(`${page}`), + Number.parseInt(`${pageSize}`), + list, + ); + + const result = ResponseClass.Success({ + items: pageData, + total: list.length, + }); + + result.message = message; + + return result; + } + + static Success(data: T) { + return new ResponseClass(0, data, null, 'ok'); + } +} + +export function pagination( + pageNo: number, + pageSize: number, + array: T[], +): T[] { + const offset = (pageNo - 1) * Number(pageSize); + return offset + Number(pageSize) >= array.length + ? array.slice(offset) + : array.slice(offset, offset + Number(pageSize)); +}