main
parent
c06e108173
commit
9e7d3137e6
|
@ -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' }],
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"endOfLine": "auto"
|
||||
"endOfLine": "auto",
|
||||
"printWidth": 120,
|
||||
"bracketSpacing": true
|
||||
}
|
86
README.md
86
README.md
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2,9 +2,11 @@ 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],
|
||||
})
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import { IsNumber, IsOptional } from 'class-validator';
|
||||
|
||||
export class PaginationDto {
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
current: number;
|
||||
|
||||
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
pageSize: number;
|
||||
}
|
|
@ -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) };
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import { Global, Module } from '@nestjs/common';
|
||||
import { DBService } from './DB.service';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
providers: [DBService],
|
||||
exports: [DBService],
|
||||
})
|
||||
export class DBModule { }
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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 };
|
|
@ -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];
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
|
@ -0,0 +1 @@
|
|||
export type findManyArgs<TModel> = Prisma.Exact<TArgs, Prisma.Args<TModel, 'findMany'>>;
|
|
@ -0,0 +1,7 @@
|
|||
export enum ErrorShowType {
|
||||
SILENT = 0,
|
||||
WARN_MESSAGE = 1,
|
||||
ERROR_MESSAGE = 2,
|
||||
NOTIFICATION = 3,
|
||||
REDIRECT = 9,
|
||||
}
|
|
@ -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]);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue