guofei 2024-09-23 19:35:11 +08:00
parent c06e108173
commit 9e7d3137e6
19 changed files with 258 additions and 96 deletions

View File

@ -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' }],
},
};

View File

@ -1,5 +1,7 @@
{
"singleQuote": true,
"trailingComma": "all",
"endOfLine": "auto"
"endOfLine": "auto",
"printWidth": 120,
"bracketSpacing": true
}

View File

@ -1,85 +1 @@
<p align="center">
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
</p>
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
[circleci-url]: https://circleci.com/gh/nestjs/nest
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
<p align="center">
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
<a href="https://coveralls.io/github/nestjs/nest?branch=master" target="_blank"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9" alt="Coverage" /></a>
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg" alt="Donate us"/></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow" alt="Follow us on Twitter"></a>
</p>
<!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)
[![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->
## 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

0
aa.conf 100644
View File

View File

@ -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"

View File

@ -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

View File

@ -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 { }

View File

@ -0,0 +1,12 @@
import { IsNumber, IsOptional } from 'class-validator';
export class PaginationDto {
@IsNumber()
@IsOptional()
current: number;
@IsNumber()
@IsOptional()
pageSize: number;
}

View File

@ -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) };
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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 <T extends any[]>(queryList: [PrismaPromise<T>, PrismaPromise<number>]) => {
const [data, count] = await $db.$transaction(queryList);
return {
data,
count,
success: true,
};
};
export { $db, connection, findAndCount };

View File

@ -0,0 +1,9 @@
import { Global, Module } from '@nestjs/common';
import { DBService } from './DB.service';
@Global()
@Module({
providers: [DBService],
exports: [DBService],
})
export class DBModule { }

View File

@ -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();
}
}

View File

@ -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<typeof PrismaClient>[0]) {
super(options);
return extendClient(this) as this;
}
}
const ExtendedPrismaClient = UntypedExtendedClient as unknown as new (
options?: ConstructorParameters<typeof PrismaClient>[0],
) => ReturnType<typeof extendClient>;
export { ExtendedPrismaClient };

View File

@ -0,0 +1,35 @@
import { Prisma } from '@prisma/client';
export type FindManyAndCountResult<T> = [T[], number, number];
export const findManyAndCountExtension = Prisma.defineExtension((client) => {
return client.$extends({
name: 'findManyAndCount',
model: {
$allModels: {
async findManyAndCount<TModel, TArgs extends Prisma.Args<TModel, 'findMany'>>(
this: TModel,
args?: Prisma.Exact<TArgs, Prisma.Args<TModel, 'findMany'>>,
): Promise<FindManyAndCountResult<Prisma.Result<TModel, TArgs, 'findMany'>>> {
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];
},
},
},
});
});

1
src/utils/db/typing.d.ts vendored 100644
View File

@ -0,0 +1 @@
export type findManyArgs<TModel> = Prisma.Exact<TArgs, Prisma.Args<TModel, 'findMany'>>;

View File

@ -0,0 +1,7 @@
export enum ErrorShowType {
SILENT = 0,
WARN_MESSAGE = 1,
ERROR_MESSAGE = 2,
NOTIFICATION = 3,
REDIRECT = 9,
}

View File

@ -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<T> {
code: number;
message: string;
data: T;
meta: Record<string, any>;
showType: ErrorShowType;
constructor(code: number, message: string, result?: T, meta?: Record<string, any>, showType?: ErrorShowType) {
this.code = code;
this.message = message;
this.data = result;
if (meta) this.meta = meta;
if (showType) this.showType = showType;
}
static successToMessage<T>(message: string, result?: T): ApiResponse<T> {
return new ApiResponse<T>(ResponseCode.SUCCESS, message, result);
}
static success<T>(result?: T): ApiResponse<T> {
if (get(result, 'data')) {
return new ApiResponse<T>(
ResponseCode.SUCCESS,
ResponseMessage[ResponseCode.SUCCESS],
result['data'],
result['meta'],
);
}
return new ApiResponse<T>(ResponseCode.SUCCESS, ResponseMessage[ResponseCode.SUCCESS], result);
}
static failShowType<T>(code: number, message: string, showType: ErrorShowType): ApiResponse<T> {
const respone = new ApiResponse<T>(code, message);
respone.showType = showType;
return respone;
}
static failToCodeMessage<T>(code: number, message: string): ApiResponse<T> {
return new ApiResponse<T>(code, message);
}
static failToMessage<T>(message: string): ApiResponse<T> {
return new ApiResponse<T>(ResponseCode.ERROR, message);
}
static fail<T>(): ApiResponse<T> {
return new ApiResponse<T>(ResponseCode.ERROR, ResponseMessage[ResponseCode.ERROR]);
}
}