From 9e7d3137e6210563b5fd2b38c0bbd3bef6907e71 Mon Sep 17 00:00:00 2001 From: guofei Date: Mon, 23 Sep 2024 19:35:11 +0800 Subject: [PATCH] 1 --- .eslintrc.js | 1 + .prettierrc | 4 +- README.md | 86 +------------------ aa.conf | 0 package.json | 1 + pnpm-lock.yaml | 3 + src/app.module.ts | 6 +- src/common/pagination/PaginationDto.dto.ts | 12 +++ src/common/pagination/index.ts | 11 +++ .../SystemCharter/SystemCharter.controller.ts | 48 +++++++++-- .../SystemCharter/dto/SystemCharter.dto.ts | 3 +- src/utils/db.ts | 18 +++- src/utils/db/DB.module.ts | 9 ++ src/utils/db/DB.service.ts | 13 +++ src/utils/db/extended-client.ts | 21 +++++ src/utils/db/find-many-count.extension.ts | 35 ++++++++ src/utils/db/typing.d.ts | 1 + src/utils/response/response-type.ts | 7 ++ src/utils/response/response.ts | 75 ++++++++++++++++ 19 files changed, 258 insertions(+), 96 deletions(-) create mode 100644 aa.conf create mode 100644 src/common/pagination/PaginationDto.dto.ts create mode 100644 src/common/pagination/index.ts create mode 100644 src/utils/db/DB.module.ts create mode 100644 src/utils/db/DB.service.ts create mode 100644 src/utils/db/extended-client.ts create mode 100644 src/utils/db/find-many-count.extension.ts create mode 100644 src/utils/db/typing.d.ts create mode 100644 src/utils/response/response-type.ts create mode 100644 src/utils/response/response.ts diff --git a/.eslintrc.js b/.eslintrc.js index 81168c9..cffd566 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -21,5 +21,6 @@ module.exports = { '@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/no-explicit-any': 'off', + 'prettier/prettier': ['error', { printWidth: 120, endOfLine: 'auto' }], }, }; diff --git a/.prettierrc b/.prettierrc index 26bd50f..6c1c390 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,7 @@ { "singleQuote": true, "trailingComma": "all", - "endOfLine": "auto" + "endOfLine": "auto", + "printWidth": 120, + "bracketSpacing": true } \ No newline at end of file diff --git a/README.md b/README.md index d2e3189..398b0ab 100644 --- a/README.md +++ b/README.md @@ -1,85 +1 @@ -

- Nest Logo -

- -[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 -[circleci-url]: https://circleci.com/gh/nestjs/nest - -

A progressive Node.js framework for building efficient and scalable server-side applications.

-

-NPM Version -Package License -NPM Downloads -CircleCI -Coverage -Discord -Backers on Open Collective -Sponsors on Open Collective - Donate us - Support us - Follow us on Twitter -

- - -## Description - -[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. - -## Project setup - -```bash -$ pnpm install -``` - -## Compile and run the project - -```bash -# development -$ pnpm run start - -# watch mode -$ pnpm run start:dev - -# production mode -$ pnpm run start:prod -``` - -## Run tests - -```bash -# unit tests -$ pnpm run test - -# e2e tests -$ pnpm run test:e2e - -# test coverage -$ pnpm run test:cov -``` - -## Resources - -Check out a few resources that may come in handy when working with NestJS: - -- Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework. -- For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy). -- To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/). -- Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com). -- Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com). -- To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs). -- Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com). - -## Support - -Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). - -## Stay in touch - -- Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec) -- Website - [https://nestjs.com](https://nestjs.com/) -- Twitter - [@nestframework](https://twitter.com/nestframework) - -## License - -Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE). +pm2 start --name admin-banban-new-nest npm -- run start:prod \ No newline at end of file diff --git a/aa.conf b/aa.conf new file mode 100644 index 0000000..e69de29 diff --git a/package.json b/package.json index 65a6e0f..ca44b1e 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@nestjs/platform-express": "^10.0.0", "@prisma/client": "^5.19.1", "class-validator": "^0.14.1", + "lodash": "^4.17.21", "prisma": "^5.19.1", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fbc0424..78bb618 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: class-validator: specifier: ^0.14.1 version: 0.14.1 + lodash: + specifier: ^4.17.21 + version: 4.17.21 prisma: specifier: ^5.19.1 version: 5.19.1 diff --git a/src/app.module.ts b/src/app.module.ts index f2a708e..1a85134 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -2,10 +2,12 @@ import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { SystemCharterModule } from './modules/index'; +import { DBModule } from './utils/db/DB.module'; + @Module({ - imports: [SystemCharterModule], + imports: [DBModule, SystemCharterModule], controllers: [AppController], providers: [AppService], }) -export class AppModule {} +export class AppModule { } diff --git a/src/common/pagination/PaginationDto.dto.ts b/src/common/pagination/PaginationDto.dto.ts new file mode 100644 index 0000000..5c493a0 --- /dev/null +++ b/src/common/pagination/PaginationDto.dto.ts @@ -0,0 +1,12 @@ +import { IsNumber, IsOptional } from 'class-validator'; + +export class PaginationDto { + @IsNumber() + @IsOptional() + current: number; + + + @IsNumber() + @IsOptional() + pageSize: number; +} \ No newline at end of file diff --git a/src/common/pagination/index.ts b/src/common/pagination/index.ts new file mode 100644 index 0000000..3e3b903 --- /dev/null +++ b/src/common/pagination/index.ts @@ -0,0 +1,11 @@ +export class Pagination { + static getPage(current: any, pageSize?: any) { + if (current == undefined) { + current = '1'; + } + if (pageSize == undefined) { + pageSize = '10'; + } + return { skip: (parseInt(current) - 1) * parseInt(pageSize), take: parseInt(pageSize) }; + } +} diff --git a/src/modules/SystemCharter/SystemCharter.controller.ts b/src/modules/SystemCharter/SystemCharter.controller.ts index 6d1e795..d28f526 100644 --- a/src/modules/SystemCharter/SystemCharter.controller.ts +++ b/src/modules/SystemCharter/SystemCharter.controller.ts @@ -1,17 +1,55 @@ -import { Body, Controller, Post } from '@nestjs/common'; -import { $db } from 'src/utils/db'; +import { Body, Controller, Get, Post, Query } from '@nestjs/common'; import { SystemCharterlDto } from './dto/SystemCharter.dto'; +import { Pagination } from 'src/common/pagination'; +import { DBService } from 'src/utils/db/DB.service'; +import { ApiResponse } from 'src/utils/response/response'; @Controller('/system/charter') export class SystemCharterController { + constructor(private readonly dbService: DBService) { } + + + @Get('/getList') + async getList(@Query() query: SystemCharterlDto) { + const { current, pageSize, ...other } = query; + const where = {}; + if (query.roleName) { + where['roleName'] = other.roleName; + } + + const [record, total] = await this.dbService.systemCharter.findManyAndCount({ + where, + ...Pagination.getPage(current, pageSize), + orderBy: { + createdAt: 'desc', + }, + }); + return ApiResponse.success({ + data: record, + meta: { + total: total, + }, + }); + } + @Post('/add') async addSystemCharter(@Body() object: SystemCharterlDto) { - console.log('---', object); delete object.id; - const newRecord = await $db.systemCharter.create({ + const newRecord = await this.dbService.systemCharter.create({ data: object, }); - console.log(newRecord); + return newRecord; + } + + @Post('/update') + async updateSystemCharter(@Body() object: SystemCharterlDto) { + const { id, ...other } = object; + const newRecord = await this.dbService.systemCharter.update({ + where: { + id: id, + }, + data: other, + }); return newRecord; } } diff --git a/src/modules/SystemCharter/dto/SystemCharter.dto.ts b/src/modules/SystemCharter/dto/SystemCharter.dto.ts index b8267e1..0133355 100644 --- a/src/modules/SystemCharter/dto/SystemCharter.dto.ts +++ b/src/modules/SystemCharter/dto/SystemCharter.dto.ts @@ -1,6 +1,7 @@ import { IsOptional, IsString } from 'class-validator'; +import { PaginationDto } from 'src/common/pagination/PaginationDto.dto'; -export class SystemCharterlDto { +export class SystemCharterlDto extends PaginationDto { @IsString() @IsOptional() id: string; diff --git a/src/utils/db.ts b/src/utils/db.ts index 92dfbb8..82905c4 100644 --- a/src/utils/db.ts +++ b/src/utils/db.ts @@ -1,4 +1,4 @@ -import { PrismaClient } from '@prisma/client'; +import { PrismaClient, PrismaPromise } from '@prisma/client'; import { $logger } from './logger'; let $db: PrismaClient; @@ -14,4 +14,18 @@ const connection = async () => { } }; -export { $db, connection }; +/** + * 查询并统计结果,(用于分页) + * @param queryList + * @returns + */ +const findAndCount = async (queryList: [PrismaPromise, PrismaPromise]) => { + const [data, count] = await $db.$transaction(queryList); + return { + data, + count, + success: true, + }; +}; + +export { $db, connection, findAndCount }; diff --git a/src/utils/db/DB.module.ts b/src/utils/db/DB.module.ts new file mode 100644 index 0000000..03a8246 --- /dev/null +++ b/src/utils/db/DB.module.ts @@ -0,0 +1,9 @@ +import { Global, Module } from '@nestjs/common'; +import { DBService } from './DB.service'; + +@Global() +@Module({ + providers: [DBService], + exports: [DBService], +}) +export class DBModule { } diff --git a/src/utils/db/DB.service.ts b/src/utils/db/DB.service.ts new file mode 100644 index 0000000..b4dd3b0 --- /dev/null +++ b/src/utils/db/DB.service.ts @@ -0,0 +1,13 @@ +import { OnModuleInit, OnModuleDestroy, Injectable } from '@nestjs/common'; +import { ExtendedPrismaClient } from './extended-client'; + +@Injectable() +export class DBService extends ExtendedPrismaClient implements OnModuleInit, OnModuleDestroy { + async onModuleInit() { + await this.$connect(); + } + + async onModuleDestroy() { + await this.$disconnect(); + } +} diff --git a/src/utils/db/extended-client.ts b/src/utils/db/extended-client.ts new file mode 100644 index 0000000..55117ff --- /dev/null +++ b/src/utils/db/extended-client.ts @@ -0,0 +1,21 @@ +import { PrismaClient } from '@prisma/client'; + +import { findManyAndCountExtension } from './find-many-count.extension'; + +function extendClient(base: PrismaClient) { + return base.$extends(findManyAndCountExtension); +} + +class UntypedExtendedClient extends PrismaClient { + constructor(options?: ConstructorParameters[0]) { + super(options); + + return extendClient(this) as this; + } +} + +const ExtendedPrismaClient = UntypedExtendedClient as unknown as new ( + options?: ConstructorParameters[0], +) => ReturnType; + +export { ExtendedPrismaClient }; diff --git a/src/utils/db/find-many-count.extension.ts b/src/utils/db/find-many-count.extension.ts new file mode 100644 index 0000000..c95fd6c --- /dev/null +++ b/src/utils/db/find-many-count.extension.ts @@ -0,0 +1,35 @@ +import { Prisma } from '@prisma/client'; + +export type FindManyAndCountResult = [T[], number, number]; + +export const findManyAndCountExtension = Prisma.defineExtension((client) => { + return client.$extends({ + name: 'findManyAndCount', + model: { + $allModels: { + async findManyAndCount>( + this: TModel, + args?: Prisma.Exact>, + ): Promise>> { + const context = Prisma.getExtensionContext(this); + + const [records, totalRecords] = await client.$transaction([ + (context as any).findMany(args), + (context as any).count({ where: (args as any)?.where }), + ]); + + const take = (args as any)?.take; + let totalPages = totalRecords === 0 ? 0 : 1; + + if (take === 0) { + totalPages = 0; + } else if (typeof take === 'number') { + totalPages = Math.ceil(totalRecords / take); + } + + return [records, totalRecords, totalPages]; + }, + }, + }, + }); +}); diff --git a/src/utils/db/typing.d.ts b/src/utils/db/typing.d.ts new file mode 100644 index 0000000..2a3ee66 --- /dev/null +++ b/src/utils/db/typing.d.ts @@ -0,0 +1 @@ +export type findManyArgs = Prisma.Exact>; diff --git a/src/utils/response/response-type.ts b/src/utils/response/response-type.ts new file mode 100644 index 0000000..8a0ea29 --- /dev/null +++ b/src/utils/response/response-type.ts @@ -0,0 +1,7 @@ +export enum ErrorShowType { + SILENT = 0, + WARN_MESSAGE = 1, + ERROR_MESSAGE = 2, + NOTIFICATION = 3, + REDIRECT = 9, +} diff --git a/src/utils/response/response.ts b/src/utils/response/response.ts new file mode 100644 index 0000000..3cc1d9b --- /dev/null +++ b/src/utils/response/response.ts @@ -0,0 +1,75 @@ +import { get } from 'lodash'; +import { ErrorShowType } from './response-type'; + +export enum ResponseCode { + SUCCESS = 200, + FAILURE = 201, + INVALID_TOKEN = 401, + OFFLINE = 405, + ERROR = 500, + PARAM_ERROR = 1000, + ACCESS_DENIED = 2002, + USERNAME_OR_PASSWORD_ERROR = 2003, + USER_DISABLED = 403, +} + +export const ResponseMessage = { + [ResponseCode.SUCCESS]: '操作成功!', + [ResponseCode.FAILURE]: '操作失败', + [ResponseCode.ERROR]: '系统异常,请稍后重试', + [ResponseCode.PARAM_ERROR]: '参数异常', + [ResponseCode.INVALID_TOKEN]: '访问令牌不合法', + [ResponseCode.ACCESS_DENIED]: '没有权限访问该资源', + [ResponseCode.USERNAME_OR_PASSWORD_ERROR]: '用户名或密码错误', + [ResponseCode.OFFLINE]: '账号在其他电脑登录', + [ResponseCode.USER_DISABLED]: '您的账号已被禁用', +}; + +export class ApiResponse { + code: number; + message: string; + data: T; + meta: Record; + showType: ErrorShowType; + constructor(code: number, message: string, result?: T, meta?: Record, showType?: ErrorShowType) { + this.code = code; + this.message = message; + this.data = result; + if (meta) this.meta = meta; + if (showType) this.showType = showType; + } + + static successToMessage(message: string, result?: T): ApiResponse { + return new ApiResponse(ResponseCode.SUCCESS, message, result); + } + + static success(result?: T): ApiResponse { + if (get(result, 'data')) { + return new ApiResponse( + ResponseCode.SUCCESS, + ResponseMessage[ResponseCode.SUCCESS], + result['data'], + result['meta'], + ); + } + return new ApiResponse(ResponseCode.SUCCESS, ResponseMessage[ResponseCode.SUCCESS], result); + } + + static failShowType(code: number, message: string, showType: ErrorShowType): ApiResponse { + const respone = new ApiResponse(code, message); + respone.showType = showType; + return respone; + } + + static failToCodeMessage(code: number, message: string): ApiResponse { + return new ApiResponse(code, message); + } + + static failToMessage(message: string): ApiResponse { + return new ApiResponse(ResponseCode.ERROR, message); + } + + static fail(): ApiResponse { + return new ApiResponse(ResponseCode.ERROR, ResponseMessage[ResponseCode.ERROR]); + } +}