refactor:

This commit is contained in:
louis 2024-02-29 09:29:03 +08:00
parent 6b9b4cdd17
commit 88a97ee162
144 changed files with 387 additions and 387 deletions

View File

@ -33,7 +33,7 @@ import { ContractModule } from './modules/contract/contract.module';
expandVariables: true, expandVariables: true,
// 指定多个 env 文件时,第一个优先级最高 // 指定多个 env 文件时,第一个优先级最高
envFilePath: ['.env.local', `.env.${process.env.NODE_ENV}`, '.env'], envFilePath: ['.env.local', `.env.${process.env.NODE_ENV}`, '.env'],
load: [...Object.values(config)], load: [...Object.values(config)]
}), }),
SharedModule, SharedModule,
DatabaseModule, DatabaseModule,
@ -53,7 +53,7 @@ import { ContractModule } from './modules/contract/contract.module';
TodoModule, TodoModule,
ContractModule, ContractModule
], ],
providers: [ providers: [
{ provide: APP_FILTER, useClass: AllExceptionsFilter }, { provide: APP_FILTER, useClass: AllExceptionsFilter },
@ -64,7 +64,7 @@ import { ContractModule } from './modules/contract/contract.module';
{ provide: APP_INTERCEPTOR, useClass: IdempotenceInterceptor }, { provide: APP_INTERCEPTOR, useClass: IdempotenceInterceptor },
{ provide: APP_GUARD, useClass: JwtAuthGuard }, { provide: APP_GUARD, useClass: JwtAuthGuard },
{ provide: APP_GUARD, useClass: RbacGuard }, { provide: APP_GUARD, useClass: RbacGuard }
], ]
}) })
export class AppModule {} export class AppModule {}

View File

@ -4,7 +4,7 @@ import { FastifyAdapter } from '@nestjs/platform-fastify';
const app: FastifyAdapter = new FastifyAdapter({ const app: FastifyAdapter = new FastifyAdapter({
trustProxy: true, trustProxy: true,
logger: false, logger: false
// forceCloseConnections: true, // forceCloseConnections: true,
}); });
export { app as fastifyApp }; export { app as fastifyApp };
@ -13,12 +13,12 @@ app.register(FastifyMultipart, {
limits: { limits: {
fields: 10, // Max number of non-file fields fields: 10, // Max number of non-file fields
fileSize: 1024 * 1024 * 6, // limit size 6M fileSize: 1024 * 1024 * 6, // limit size 6M
files: 5, // Max number of file fields files: 5 // Max number of file fields
}, }
}); });
app.register(FastifyCookie, { app.register(FastifyCookie, {
secret: 'cookie-secret', // 这个 secret 不太重要,不存鉴权相关,无关紧要 secret: 'cookie-secret' // 这个 secret 不太重要,不存鉴权相关,无关紧要
}); });
app.getInstance().addHook('onRequest', (request, reply, done) => { app.getInstance().addHook('onRequest', (request, reply, done) => {

View File

@ -18,7 +18,7 @@ export class RedisIoAdapter extends IoAdapter {
const redisAdapter = createAdapter(pubClient, subClient, { const redisAdapter = createAdapter(pubClient, subClient, {
key: RedisIoAdapterKey, key: RedisIoAdapterKey,
requestsTimeout: 10000, requestsTimeout: 10000
}); });
server.adapter(redisAdapter); server.adapter(redisAdapter);
return server; return server;

View File

@ -16,7 +16,7 @@ function genBaseProp(type: Type<any>) {
export function ApiResult<TModel extends Type<any>>({ export function ApiResult<TModel extends Type<any>>({
type, type,
isPage, isPage,
status, status
}: { }: {
type?: TModel | TModel[]; type?: TModel | TModel[];
isPage?: boolean; isPage?: boolean;
@ -31,7 +31,7 @@ export function ApiResult<TModel extends Type<any>>({
properties: { properties: {
items: { items: {
type: 'array', type: 'array',
items: { $ref: getSchemaPath(type[0]) }, items: { $ref: getSchemaPath(type[0]) }
}, },
meta: { meta: {
type: 'object', type: 'object',
@ -40,15 +40,15 @@ export function ApiResult<TModel extends Type<any>>({
totalItems: { type: 'number', default: 0 }, totalItems: { type: 'number', default: 0 },
itemsPerPage: { type: 'number', default: 0 }, itemsPerPage: { type: 'number', default: 0 },
totalPages: { type: 'number', default: 0 }, totalPages: { type: 'number', default: 0 },
currentPage: { type: 'number', default: 0 }, currentPage: { type: 'number', default: 0 }
}, }
}, }
}, }
}; };
} else { } else {
prop = { prop = {
type: 'array', type: 'array',
items: genBaseProp(type[0]), items: genBaseProp(type[0])
}; };
} }
} else if (type) { } else if (type) {
@ -68,11 +68,11 @@ export function ApiResult<TModel extends Type<any>>({
{ $ref: getSchemaPath(ResOp) }, { $ref: getSchemaPath(ResOp) },
{ {
properties: { properties: {
data: prop, data: prop
}, }
}, }
], ]
}, }
}) })
); );
} }

View File

@ -11,7 +11,7 @@ import {
Max, Max,
MaxLength, MaxLength,
Min, Min,
MinLength, MinLength
} from 'class-validator'; } from 'class-validator';
import { isNumber } from 'lodash'; import { isNumber } from 'lodash';
@ -22,7 +22,7 @@ import {
ToLowerCase, ToLowerCase,
ToNumber, ToNumber,
ToTrim, ToTrim,
ToUpperCase, ToUpperCase
} from './transform.decorator'; } from './transform.decorator';
interface IOptionalOptions { interface IOptionalOptions {

View File

@ -7,7 +7,7 @@ export function IdParam() {
errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE, errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE,
exceptionFactory: _error => { exceptionFactory: _error => {
throw new NotAcceptableException('id 格式不正确'); throw new NotAcceptableException('id 格式不正确');
}, }
}) })
); );
} }

View File

@ -9,7 +9,7 @@ export class CursorDto<T = any> {
@Expose() @Expose()
@IsOptional({ always: true }) @IsOptional({ always: true })
@Transform(({ value: val }) => (val ? Number.parseInt(val) : 0), { @Transform(({ value: val }) => (val ? Number.parseInt(val) : 0), {
toClassOnly: true, toClassOnly: true
}) })
cursor?: number; cursor?: number;
@ -20,7 +20,7 @@ export class CursorDto<T = any> {
@IsOptional({ always: true }) @IsOptional({ always: true })
@Expose() @Expose()
@Transform(({ value: val }) => (val ? Number.parseInt(val) : 10), { @Transform(({ value: val }) => (val ? Number.parseInt(val) : 10), {
toClassOnly: true, toClassOnly: true
}) })
limit?: number; limit?: number;
} }

View File

@ -4,7 +4,7 @@ import { Allow, IsEnum, IsInt, IsOptional, IsString, Max, Min } from 'class-vali
export enum Order { export enum Order {
ASC = 'ASC', ASC = 'ASC',
DESC = 'DESC', DESC = 'DESC'
} }
export class PagerDto<T = any> { export class PagerDto<T = any> {
@ -14,7 +14,7 @@ export class PagerDto<T = any> {
@Expose() @Expose()
@IsOptional({ always: true }) @IsOptional({ always: true })
@Transform(({ value: val }) => (val ? Number.parseInt(val) : 1), { @Transform(({ value: val }) => (val ? Number.parseInt(val) : 1), {
toClassOnly: true, toClassOnly: true
}) })
page?: number; page?: number;
@ -25,7 +25,7 @@ export class PagerDto<T = any> {
@IsOptional({ always: true }) @IsOptional({ always: true })
@Expose() @Expose()
@Transform(({ value: val }) => (val ? Number.parseInt(val) : 10), { @Transform(({ value: val }) => (val ? Number.parseInt(val) : 10), {
toClassOnly: true, toClassOnly: true
}) })
pageSize?: number; pageSize?: number;

View File

@ -6,7 +6,7 @@ import {
CreateDateColumn, CreateDateColumn,
PrimaryGeneratedColumn, PrimaryGeneratedColumn,
UpdateDateColumn, UpdateDateColumn,
VirtualColumn, VirtualColumn
} from 'typeorm'; } from 'typeorm';
// 如果觉得前端转换时间太麻烦并且不考虑通用性的话可以在服务端进行转换eg: @UpdateDateColumn({ name: 'updated_at', transformer }) // 如果觉得前端转换时间太麻烦并且不考虑通用性的话可以在服务端进行转换eg: @UpdateDateColumn({ name: 'updated_at', transformer })

View File

@ -12,7 +12,7 @@ export class BusinessException extends HttpException {
super( super(
HttpException.createBody({ HttpException.createBody({
code: RESPONSE_SUCCESS_CODE, code: RESPONSE_SUCCESS_CODE,
message: error, message: error
}), }),
HttpStatus.OK HttpStatus.OK
); );
@ -24,7 +24,7 @@ export class BusinessException extends HttpException {
super( super(
HttpException.createBody({ HttpException.createBody({
code, code,
message, message
}), }),
HttpStatus.OK HttpStatus.OK
); );

View File

@ -14,7 +14,7 @@ export class SocketException extends WsException {
super( super(
HttpException.createBody({ HttpException.createBody({
code: 0, code: 0,
message: error, message: error
}) })
); );
this.errorCode = 0; this.errorCode = 0;
@ -25,7 +25,7 @@ export class SocketException extends WsException {
super( super(
HttpException.createBody({ HttpException.createBody({
code, code,
message, message
}) })
); );

View File

@ -4,7 +4,7 @@ import {
ExceptionFilter, ExceptionFilter,
HttpException, HttpException,
HttpStatus, HttpStatus,
Logger, Logger
} from '@nestjs/common'; } from '@nestjs/common';
import { FastifyReply, FastifyRequest } from 'fastify'; import { FastifyReply, FastifyRequest } from 'fastify';
@ -62,7 +62,7 @@ export class AllExceptionsFilter implements ExceptionFilter {
const resBody: IBaseResponse = { const resBody: IBaseResponse = {
code: apiErrorCode, code: apiErrorCode,
message, message,
data: null, data: null
}; };
response.status(status).send(resBody); response.status(status).send(resBody);

View File

@ -12,7 +12,7 @@ import { getRedisKey } from '~/utils/redis.util';
import { import {
HTTP_IDEMPOTENCE_KEY, HTTP_IDEMPOTENCE_KEY,
HTTP_IDEMPOTENCE_OPTIONS, HTTP_IDEMPOTENCE_OPTIONS
} from '../decorators/idempotence.decorator'; } from '../decorators/idempotence.decorator';
const IdempotenceHeaderKey = 'x-idempotence'; const IdempotenceHeaderKey = 'x-idempotence';
@ -70,7 +70,7 @@ export class IdempotenceInterceptor implements NestInterceptor {
pendingMessage = '相同请求正在处理中...', pendingMessage = '相同请求正在处理中...',
handler: errorHandler, handler: errorHandler,
expired = 60, expired = 60,
disableGenerateKey = false, disableGenerateKey = false
} = options; } = options;
const redis = this.cacheService.getClient(); const redis = this.cacheService.getClient();
@ -93,7 +93,7 @@ export class IdempotenceInterceptor implements NestInterceptor {
const message = { const message = {
1: errorMessage, 1: errorMessage,
0: pendingMessage, 0: pendingMessage
}[resultValue]; }[resultValue];
throw new ConflictException(message); throw new ConflictException(message);
} else { } else {

View File

@ -3,7 +3,7 @@ import {
ExecutionContext, ExecutionContext,
Injectable, Injectable,
NestInterceptor, NestInterceptor,
RequestTimeoutException, RequestTimeoutException
} from '@nestjs/common'; } from '@nestjs/common';
import { Observable, TimeoutError, throwError } from 'rxjs'; import { Observable, TimeoutError, throwError } from 'rxjs';
import { catchError, timeout } from 'rxjs/operators'; import { catchError, timeout } from 'rxjs/operators';

View File

@ -3,7 +3,7 @@ import {
ExecutionContext, ExecutionContext,
HttpStatus, HttpStatus,
Injectable, Injectable,
NestInterceptor, NestInterceptor
} from '@nestjs/common'; } from '@nestjs/common';
import { Reflector } from '@nestjs/core'; import { Reflector } from '@nestjs/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';

View File

@ -13,8 +13,8 @@ export const AppConfig = registerAs(appRegToken, () => ({
logger: { logger: {
level: env('LOGGER_LEVEL'), level: env('LOGGER_LEVEL'),
maxFiles: envNumber('LOGGER_MAX_FILES'), maxFiles: envNumber('LOGGER_MAX_FILES')
}, }
})); }));
export type IAppConfig = ConfigType<typeof AppConfig>; export type IAppConfig = ConfigType<typeof AppConfig>;

View File

@ -24,7 +24,7 @@ const dataSourceOptions: DataSourceOptions = {
multipleStatements: currentScript === 'typeorm', multipleStatements: currentScript === 'typeorm',
entities: ['dist/modules/**/*.entity{.ts,.js}'], entities: ['dist/modules/**/*.entity{.ts,.js}'],
migrations: ['dist/migrations/*{.ts,.js}'], migrations: ['dist/migrations/*{.ts,.js}'],
subscribers: ['dist/modules/**/*.subscriber{.ts,.js}'], subscribers: ['dist/modules/**/*.subscriber{.ts,.js}']
}; };
export const dbRegToken = 'database'; export const dbRegToken = 'database';

View File

@ -33,5 +33,5 @@ export default {
OssConfig, OssConfig,
RedisConfig, RedisConfig,
SecurityConfig, SecurityConfig,
SwaggerConfig, SwaggerConfig
}; };

View File

@ -11,8 +11,8 @@ export const MailerConfig = registerAs(mailerRegToken, () => ({
secure: true, secure: true,
auth: { auth: {
user: env('SMTP_USER'), user: env('SMTP_USER'),
pass: env('SMTP_PASS'), pass: env('SMTP_PASS')
}, }
})); }));
export type IMailerConfig = ConfigType<typeof MailerConfig>; export type IMailerConfig = ConfigType<typeof MailerConfig>;

View File

@ -26,7 +26,7 @@ export const OssConfig = registerAs(ossRegToken, () => ({
domain: env('OSS_DOMAIN'), domain: env('OSS_DOMAIN'),
bucket: env('OSS_BUCKET'), bucket: env('OSS_BUCKET'),
zone: parseZone(env('OSS_ZONE') || 'Zone_z2'), zone: parseZone(env('OSS_ZONE') || 'Zone_z2'),
access: (env('OSS_ACCESS_TYPE') as any) || 'public', access: (env('OSS_ACCESS_TYPE') as any) || 'public'
})); }));
export type IOssConfig = ConfigType<typeof OssConfig>; export type IOssConfig = ConfigType<typeof OssConfig>;

View File

@ -8,7 +8,7 @@ export const RedisConfig = registerAs(redisRegToken, () => ({
host: env('REDIS_HOST', '127.0.0.1'), host: env('REDIS_HOST', '127.0.0.1'),
port: envNumber('REDIS_PORT', 6379), port: envNumber('REDIS_PORT', 6379),
password: env('REDIS_PASSWORD'), password: env('REDIS_PASSWORD'),
db: envNumber('REDIS_DB'), db: envNumber('REDIS_DB')
})); }));
export type IRedisConfig = ConfigType<typeof RedisConfig>; export type IRedisConfig = ConfigType<typeof RedisConfig>;

View File

@ -8,7 +8,7 @@ export const SecurityConfig = registerAs(securityRegToken, () => ({
jwtSecret: env('JWT_SECRET'), jwtSecret: env('JWT_SECRET'),
jwtExprire: envNumber('JWT_EXPIRE'), jwtExprire: envNumber('JWT_EXPIRE'),
refreshSecret: env('REFRESH_TOKEN_SECRET'), refreshSecret: env('REFRESH_TOKEN_SECRET'),
refreshExpire: envNumber('REFRESH_TOKEN_EXPIRE'), refreshExpire: envNumber('REFRESH_TOKEN_EXPIRE')
})); }));
export type ISecurityConfig = ConfigType<typeof SecurityConfig>; export type ISecurityConfig = ConfigType<typeof SecurityConfig>;

View File

@ -6,7 +6,7 @@ export const swaggerRegToken = 'swagger';
export const SwaggerConfig = registerAs(swaggerRegToken, () => ({ export const SwaggerConfig = registerAs(swaggerRegToken, () => ({
enable: envBoolean('SWAGGER_ENABLE'), enable: envBoolean('SWAGGER_ENABLE'),
path: env('SWAGGER_PATH'), path: env('SWAGGER_PATH')
})); }));
export type ISwaggerConfig = ConfigType<typeof SwaggerConfig>; export type ISwaggerConfig = ConfigType<typeof SwaggerConfig>;

View File

@ -3,6 +3,6 @@ export enum RedisKeys {
CAPTCHA_IMG_PREFIX = 'captcha:img:', CAPTCHA_IMG_PREFIX = 'captcha:img:',
AUTH_TOKEN_PREFIX = 'auth:token:', AUTH_TOKEN_PREFIX = 'auth:token:',
AUTH_PERM_PREFIX = 'auth:permission:', AUTH_PERM_PREFIX = 'auth:permission:',
AUTH_PASSWORD_V_PREFIX = 'auth:passwordVersion:', AUTH_PASSWORD_V_PREFIX = 'auth:passwordVersion:'
} }
export const API_CACHE_PREFIX = 'api-cache:'; export const API_CACHE_PREFIX = 'api-cache:';

View File

@ -45,5 +45,5 @@ export enum ErrorEnum {
// OSS相关 // OSS相关
OSS_FILE_OR_DIR_EXIST = '1401:当前创建的文件或目录已存在', OSS_FILE_OR_DIR_EXIST = '1401:当前创建的文件或目录已存在',
OSS_NO_OPERATION_REQUIRED = '1402:无需操作', OSS_NO_OPERATION_REQUIRED = '1402:无需操作',
OSS_EXCEE_MAXIMUM_QUANTITY = '1403:已超出支持的最大处理数量', OSS_EXCEE_MAXIMUM_QUANTITY = '1403:已超出支持的最大处理数量'
} }

View File

@ -1,4 +1,4 @@
export enum EventBusEvents { export enum EventBusEvents {
TokenExpired = 'token.expired', TokenExpired = 'token.expired',
SystemException = 'system.exception', SystemException = 'system.exception'
} }

View File

@ -11,5 +11,5 @@ export enum ContentTypeEnum {
// form-data qs // form-data qs
FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8', FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
// form-data upload // form-data upload
FORM_DATA = 'multipart/form-data;charset=UTF-8', FORM_DATA = 'multipart/form-data;charset=UTF-8'
} }

View File

@ -13,7 +13,7 @@ import { BaseService } from './base.service';
export function BaseCrudFactory<E extends new (...args: any[]) => any>({ export function BaseCrudFactory<E extends new (...args: any[]) => any>({
entity, entity,
dto, dto,
permissions, permissions
}: { }: {
entity: E; entity: E;
dto?: Type<any>; dto?: Type<any>;
@ -35,7 +35,7 @@ export function BaseCrudFactory<E extends new (...args: any[]) => any>({
CREATE: `${prefix}:create`, CREATE: `${prefix}:create`,
READ: `${prefix}:read`, READ: `${prefix}:read`,
UPDATE: `${prefix}:update`, UPDATE: `${prefix}:update`,
DELETE: `${prefix}:delete`, DELETE: `${prefix}:delete`
} as const); } as const);
@Controller(pluralizeName) @Controller(pluralizeName)

View File

@ -5,7 +5,7 @@ export function createPaginationObject<T>({
items, items,
totalItems, totalItems,
currentPage, currentPage,
limit, limit
}: { }: {
items: T[]; items: T[];
totalItems?: number; totalItems?: number;
@ -19,7 +19,7 @@ export function createPaginationObject<T>({
itemCount: items.length, itemCount: items.length,
itemsPerPage: limit, itemsPerPage: limit,
totalPages, totalPages,
currentPage, currentPage
}; };
return new Pagination<T>(items, meta); return new Pagination<T>(items, meta);

View File

@ -3,7 +3,7 @@ import {
FindOptionsWhere, FindOptionsWhere,
ObjectLiteral, ObjectLiteral,
Repository, Repository,
SelectQueryBuilder, SelectQueryBuilder
} from 'typeorm'; } from 'typeorm';
import { createPaginationObject } from './create-pagination'; import { createPaginationObject } from './create-pagination';
@ -19,7 +19,7 @@ function resolveOptions(options: IPaginationOptions): [number, number, Paginatio
return [ return [
page || DEFAULT_PAGE, page || DEFAULT_PAGE,
pageSize || DEFAULT_LIMIT, pageSize || DEFAULT_LIMIT,
paginationType || PaginationTypeEnum.TAKE_AND_SKIP, paginationType || PaginationTypeEnum.TAKE_AND_SKIP
]; ];
} }
@ -34,9 +34,9 @@ async function paginateRepository<T>(
repository.find({ repository.find({
skip: limit * (page - 1), skip: limit * (page - 1),
take: limit, take: limit,
...searchOptions, ...searchOptions
}), }),
undefined, undefined
]; ];
const [items, total] = await Promise.all(promises); const [items, total] = await Promise.all(promises);
@ -45,7 +45,7 @@ async function paginateRepository<T>(
items, items,
totalItems: total, totalItems: total,
currentPage: page, currentPage: page,
limit, limit
}); });
} }
@ -65,7 +65,7 @@ async function paginateQueryBuilder<T>(
items, items,
totalItems: total, totalItems: total,
currentPage: page, currentPage: page,
limit, limit
}); });
} }
@ -80,7 +80,7 @@ export async function paginateRaw<T>(
? queryBuilder.limit(limit).offset((page - 1) * limit) ? queryBuilder.limit(limit).offset((page - 1) * limit)
: queryBuilder.take(limit).skip((page - 1) * limit) : queryBuilder.take(limit).skip((page - 1) * limit)
).getRawMany<T>(), ).getRawMany<T>(),
queryBuilder.getCount(), queryBuilder.getCount()
]; ];
const [items, total] = await Promise.all(promises); const [items, total] = await Promise.all(promises);
@ -89,7 +89,7 @@ export async function paginateRaw<T>(
items, items,
totalItems: total, totalItems: total,
currentPage: page, currentPage: page,
limit, limit
}); });
} }
@ -104,7 +104,7 @@ export async function paginateRawAndEntities<T>(
? queryBuilder.limit(limit).offset((page - 1) * limit) ? queryBuilder.limit(limit).offset((page - 1) * limit)
: queryBuilder.take(limit).skip((page - 1) * limit) : queryBuilder.take(limit).skip((page - 1) * limit)
).getRawAndEntities<T>(), ).getRawAndEntities<T>(),
queryBuilder.getCount(), queryBuilder.getCount()
]; ];
const [itemObject, total] = await Promise.all(promises); const [itemObject, total] = await Promise.all(promises);
@ -114,9 +114,9 @@ export async function paginateRawAndEntities<T>(
items: itemObject.entities, items: itemObject.entities,
totalItems: total, totalItems: total,
currentPage: page, currentPage: page,
limit, limit
}), }),
itemObject.raw, itemObject.raw
]; ];
} }

View File

@ -2,7 +2,7 @@ import { ObjectLiteral } from 'typeorm';
export enum PaginationTypeEnum { export enum PaginationTypeEnum {
LIMIT_AND_OFFSET = 'limit', LIMIT_AND_OFFSET = 'limit',
TAKE_AND_SKIP = 'take', TAKE_AND_SKIP = 'take'
} }
export interface IPaginationOptions { export interface IPaginationOptions {

View File

@ -23,7 +23,7 @@ declare const module: any;
async function bootstrap() { async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(AppModule, fastifyApp, { const app = await NestFactory.create<NestFastifyApplication>(AppModule, fastifyApp, {
bufferLogs: true, bufferLogs: true,
snapshot: true, snapshot: true
// forceCloseConnections: true, // forceCloseConnections: true,
}); });
@ -57,7 +57,7 @@ async function bootstrap() {
const msg = e.constraints![rule]; const msg = e.constraints![rule];
return msg; return msg;
})[0] })[0]
), )
}) })
); );

View File

@ -14,12 +14,12 @@ export const AuthStrategy = {
JWT: 'jwt', JWT: 'jwt',
GITHUB: 'github', GITHUB: 'github',
GOOGLE: 'google', GOOGLE: 'google'
} as const; } as const;
export const Roles = { export const Roles = {
ADMIN: 'admin', ADMIN: 'admin',
USER: 'user', USER: 'user'
// GUEST: 'guest', // GUEST: 'guest',
} as const; } as const;

View File

@ -41,18 +41,18 @@ const strategies = [LocalStrategy, JwtStrategy];
return { return {
secret: jwtSecret, secret: jwtSecret,
expires: jwtExprire, expires: jwtExprire,
ignoreExpiration: isDev, ignoreExpiration: isDev
}; };
}, },
inject: [ConfigService], inject: [ConfigService]
}), }),
UserModule, UserModule,
RoleModule, RoleModule,
MenuModule, MenuModule,
LogModule, LogModule
], ],
controllers: [...controllers], controllers: [...controllers],
providers: [...providers, ...strategies], providers: [...providers, ...strategies],
exports: [TypeOrmModule, JwtModule, ...providers], exports: [TypeOrmModule, JwtModule, ...providers]
}) })
export class AuthModule {} export class AuthModule {}

View File

@ -35,11 +35,11 @@ export class CaptchaController {
noise: 4, noise: 4,
width: isEmpty(width) ? 100 : width, width: isEmpty(width) ? 100 : width,
height: isEmpty(height) ? 50 : height, height: isEmpty(height) ? 50 : height,
charPreset: '1234567890', charPreset: '1234567890'
}); });
const result = { const result = {
img: `data:image/svg+xml;base64,${Buffer.from(svg.data).toString('base64')}`, img: `data:image/svg+xml;base64,${Buffer.from(svg.data).toString('base64')}`,
id: generateUUID(), id: generateUUID()
}; };
// 5分钟过期时间 // 5分钟过期时间
await this.redis.set(genCaptchaImgKey(result.id), svg.text, 'EX', 60 * 5); await this.redis.set(genCaptchaImgKey(result.id), svg.text, 'EX', 60 * 5);

View File

@ -57,7 +57,7 @@ export class MenuMeta extends PartialType(
'id', 'id',
'roles', 'roles',
'path', 'path',
'name', 'name'
] as const) ] as const)
) { ) {
title: string; title: string;
@ -66,7 +66,7 @@ export class AccountMenus extends PickType(MenuEntity, [
'id', 'id',
'path', 'path',
'name', 'name',
'component', 'component'
] as const) { ] as const) {
meta: MenuMeta; meta: MenuMeta;
} }

View File

@ -6,7 +6,7 @@ export class ImageCaptchaDto {
@ApiProperty({ @ApiProperty({
required: false, required: false,
default: 100, default: 100,
description: '验证码宽度', description: '验证码宽度'
}) })
@Type(() => Number) @Type(() => Number)
@IsInt() @IsInt()
@ -16,7 +16,7 @@ export class ImageCaptchaDto {
@ApiProperty({ @ApiProperty({
required: false, required: false,
default: 50, default: 50,
description: '验证码宽度', description: '验证码宽度'
}) })
@Type(() => Number) @Type(() => Number)
@IsInt() @IsInt()

View File

@ -6,7 +6,7 @@ import {
JoinColumn, JoinColumn,
ManyToOne, ManyToOne,
OneToOne, OneToOne,
PrimaryGeneratedColumn, PrimaryGeneratedColumn
} from 'typeorm'; } from 'typeorm';
import { UserEntity } from '~/modules/user/user.entity'; import { UserEntity } from '~/modules/user/user.entity';
@ -28,12 +28,12 @@ export class AccessTokenEntity extends BaseEntity {
created_at!: Date; created_at!: Date;
@OneToOne(() => RefreshTokenEntity, refreshToken => refreshToken.accessToken, { @OneToOne(() => RefreshTokenEntity, refreshToken => refreshToken.accessToken, {
cascade: true, cascade: true
}) })
refreshToken!: RefreshTokenEntity; refreshToken!: RefreshTokenEntity;
@ManyToOne(() => UserEntity, user => user.accessTokens, { @ManyToOne(() => UserEntity, user => user.accessTokens, {
onDelete: 'CASCADE', onDelete: 'CASCADE'
}) })
@JoinColumn({ name: 'user_id' }) @JoinColumn({ name: 'user_id' })
user!: UserEntity; user!: UserEntity;

View File

@ -5,7 +5,7 @@ import {
Entity, Entity,
JoinColumn, JoinColumn,
OneToOne, OneToOne,
PrimaryGeneratedColumn, PrimaryGeneratedColumn
} from 'typeorm'; } from 'typeorm';
import { AccessTokenEntity } from './access-token.entity'; import { AccessTokenEntity } from './access-token.entity';
@ -25,7 +25,7 @@ export class RefreshTokenEntity extends BaseEntity {
created_at!: Date; created_at!: Date;
@OneToOne(() => AccessTokenEntity, accessToken => accessToken.refreshToken, { @OneToOne(() => AccessTokenEntity, accessToken => accessToken.refreshToken, {
onDelete: 'CASCADE', onDelete: 'CASCADE'
}) })
@JoinColumn() @JoinColumn()
accessToken!: AccessTokenEntity; accessToken!: AccessTokenEntity;

View File

@ -27,7 +27,7 @@ export class JwtAuthGuard extends AuthGuard(AuthStrategy.JWT) {
async canActivate(context: ExecutionContext): Promise<any> { async canActivate(context: ExecutionContext): Promise<any> {
const isPublic = this.reflector.getAllAndOverride<boolean>(PUBLIC_KEY, [ const isPublic = this.reflector.getAllAndOverride<boolean>(PUBLIC_KEY, [
context.getHandler(), context.getHandler(),
context.getClass(), context.getClass()
]); ]);
const request = context.switchToHttp().getRequest<FastifyRequest>(); const request = context.switchToHttp().getRequest<FastifyRequest>();
// const response = context.switchToHttp().getResponse<FastifyReply>() // const response = context.switchToHttp().getResponse<FastifyReply>()

View File

@ -18,7 +18,7 @@ export class RbacGuard implements CanActivate {
async canActivate(context: ExecutionContext): Promise<any> { async canActivate(context: ExecutionContext): Promise<any> {
const isPublic = this.reflector.getAllAndOverride<boolean>(PUBLIC_KEY, [ const isPublic = this.reflector.getAllAndOverride<boolean>(PUBLIC_KEY, [
context.getHandler(), context.getHandler(),
context.getClass(), context.getClass()
]); ]);
if (isPublic) return true; if (isPublic) return true;
@ -34,7 +34,7 @@ export class RbacGuard implements CanActivate {
const payloadPermission = this.reflector.getAllAndOverride<string | string[]>(PERMISSION_KEY, [ const payloadPermission = this.reflector.getAllAndOverride<string | string[]>(PERMISSION_KEY, [
context.getHandler(), context.getHandler(),
context.getClass(), context.getClass()
]); ]);
// 控制器没有设置接口权限,则默认通过 // 控制器没有设置接口权限,则默认通过

View File

@ -23,7 +23,7 @@ export class ResourceGuard implements CanActivate {
async canActivate(context: ExecutionContext): Promise<any> { async canActivate(context: ExecutionContext): Promise<any> {
const isPublic = this.reflector.getAllAndOverride<boolean>(PUBLIC_KEY, [ const isPublic = this.reflector.getAllAndOverride<boolean>(PUBLIC_KEY, [
context.getHandler(), context.getHandler(),
context.getClass(), context.getClass()
]); ]);
const request = context.switchToHttp().getRequest<FastifyRequest>(); const request = context.switchToHttp().getRequest<FastifyRequest>();
@ -66,9 +66,9 @@ export class ResourceGuard implements CanActivate {
const recordQuery = { const recordQuery = {
where: { where: {
id: In(items), id: In(items),
user: { id: user.uid }, user: { id: user.uid }
}, },
relations: ['user'], relations: ['user']
}; };
const records = await repo.find(recordQuery); const records = await repo.find(recordQuery);

View File

@ -56,7 +56,7 @@ export class TokenService {
const payload: IAuthUser = { const payload: IAuthUser = {
uid, uid,
pv: 1, pv: 1,
roles, roles
}; };
const jwtSign = this.jwtService.sign(payload); const jwtSign = this.jwtService.sign(payload);
@ -74,7 +74,7 @@ export class TokenService {
return { return {
accessToken: jwtSign, accessToken: jwtSign,
refreshToken, refreshToken
}; };
} }
@ -85,11 +85,11 @@ export class TokenService {
*/ */
async generateRefreshToken(accessToken: AccessTokenEntity, now: dayjs.Dayjs): Promise<string> { async generateRefreshToken(accessToken: AccessTokenEntity, now: dayjs.Dayjs): Promise<string> {
const refreshTokenPayload = { const refreshTokenPayload = {
uuid: generateUUID(), uuid: generateUUID()
}; };
const refreshTokenSign = this.jwtService.sign(refreshTokenPayload, { const refreshTokenSign = this.jwtService.sign(refreshTokenPayload, {
secret: this.securityConfig.refreshSecret, secret: this.securityConfig.refreshSecret
}); });
const refreshToken = new RefreshTokenEntity(); const refreshToken = new RefreshTokenEntity();
@ -110,7 +110,7 @@ export class TokenService {
return AccessTokenEntity.findOne({ return AccessTokenEntity.findOne({
where: { value }, where: { value },
relations: ['user', 'refreshToken'], relations: ['user', 'refreshToken'],
cache: true, cache: true
}); });
} }
@ -120,7 +120,7 @@ export class TokenService {
*/ */
async removeAccessToken(value: string) { async removeAccessToken(value: string) {
const accessToken = await AccessTokenEntity.findOne({ const accessToken = await AccessTokenEntity.findOne({
where: { value }, where: { value }
}); });
if (accessToken) await accessToken.remove(); if (accessToken) await accessToken.remove();
} }
@ -132,7 +132,7 @@ export class TokenService {
async removeRefreshToken(value: string) { async removeRefreshToken(value: string) {
const refreshToken = await RefreshTokenEntity.findOne({ const refreshToken = await RefreshTokenEntity.findOne({
where: { value }, where: { value },
relations: ['accessToken'], relations: ['accessToken']
}); });
if (refreshToken) { if (refreshToken) {
if (refreshToken.accessToken) await refreshToken.accessToken.remove(); if (refreshToken.accessToken) await refreshToken.accessToken.remove();

View File

@ -12,7 +12,7 @@ export class JwtStrategy extends PassportStrategy(Strategy, AuthStrategy.JWT) {
super({ super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false, ignoreExpiration: false,
secretOrKey: securityConfig.jwtSecret, secretOrKey: securityConfig.jwtSecret
}); });
} }

View File

@ -10,7 +10,7 @@ export class LocalStrategy extends PassportStrategy(Strategy, AuthStrategy.LOCAL
constructor(private authService: AuthService) { constructor(private authService: AuthService) {
super({ super({
usernameField: 'credential', usernameField: 'credential',
passwordField: 'password', passwordField: 'password'
}); });
} }

View File

@ -9,7 +9,7 @@ export const permissions = definePermission('app:contract', {
CREATE: 'create', CREATE: 'create',
READ: 'read', READ: 'read',
UPDATE: 'update', UPDATE: 'update',
DELETE: 'delete', DELETE: 'delete'
} as const); } as const);
@ApiTags('Contract - 合同') @ApiTags('Contract - 合同')

View File

@ -4,6 +4,6 @@ import { ContractService } from './contract.service';
@Module({ @Module({
controllers: [ContractController], controllers: [ContractController],
providers: [ContractService], providers: [ContractService]
}) })
export class ContractModule {} export class ContractModule {}

View File

@ -5,7 +5,7 @@ import {
HealthCheck, HealthCheck,
HttpHealthIndicator, HttpHealthIndicator,
MemoryHealthIndicator, MemoryHealthIndicator,
TypeOrmHealthIndicator, TypeOrmHealthIndicator
} from '@nestjs/terminus'; } from '@nestjs/terminus';
import { Perm, definePermission } from '../auth/decorators/permission.decorator'; import { Perm, definePermission } from '../auth/decorators/permission.decorator';
@ -15,7 +15,7 @@ export const PermissionHealth = definePermission('app:health', {
DB: 'database', DB: 'database',
MH: 'memory-heap', MH: 'memory-heap',
MR: 'memory-rss', MR: 'memory-rss',
DISK: 'disk', DISK: 'disk'
} as const); } as const);
@ApiTags('Health - 健康检查') @ApiTags('Health - 健康检查')
@ -65,7 +65,7 @@ export class HealthController {
return this.disk.checkStorage('disk', { return this.disk.checkStorage('disk', {
// The used disk storage should not exceed 75% of the full disk size // The used disk storage should not exceed 75% of the full disk size
thresholdPercent: 0.75, thresholdPercent: 0.75,
path: '/', path: '/'
}); });
} }
} }

View File

@ -6,6 +6,6 @@ import { HealthController } from './health.controller';
@Module({ @Module({
imports: [TerminusModule, HttpModule], imports: [TerminusModule, HttpModule],
controllers: [HealthController], controllers: [HealthController]
}) })
export class HealthModule {} export class HealthModule {}

View File

@ -49,7 +49,7 @@ export class SFileInfoDetail {
mimeType: string; mimeType: string;
@ApiProperty({ @ApiProperty({
description: '文件存储类型2 表示归档存储1 表示低频存储0表示普通存储。', description: '文件存储类型2 表示归档存储1 表示低频存储0表示普通存储。'
}) })
type: number; type: number;

View File

@ -17,7 +17,7 @@ import {
GetFileListDto, GetFileListDto,
MKDirDto, MKDirDto,
MarkFileDto, MarkFileDto,
RenameDto, RenameDto
} from './manage.dto'; } from './manage.dto';
import { NetDiskManageService } from './manage.service'; import { NetDiskManageService } from './manage.service';
@ -33,7 +33,7 @@ export const permissions = definePermission('netdisk:manage', {
DOWNLOAD: 'download', DOWNLOAD: 'download',
RENAME: 'rename', RENAME: 'rename',
CUT: 'cut', CUT: 'cut',
COPY: 'copy', COPY: 'copy'
} as const); } as const);
@ApiTags('NetDiskManage - 网盘管理模块') @ApiTags('NetDiskManage - 网盘管理模块')
@ -67,7 +67,7 @@ export class NetDiskManageController {
checkIsDemoMode(); checkIsDemoMode();
return { return {
token: this.manageService.createUploadToken(`${user.uid}`), token: this.manageService.createUploadToken(`${user.uid}`)
}; };
} }
@ -84,7 +84,7 @@ export class NetDiskManageController {
@Perm(permissions.MARK) @Perm(permissions.MARK)
async mark(@Body() dto: MarkFileDto): Promise<void> { async mark(@Body() dto: MarkFileDto): Promise<void> {
await this.manageService.changeFileHeaders(dto.name, dto.path, { await this.manageService.changeFileHeaders(dto.name, dto.path, {
mark: dto.mark, mark: dto.mark
}); });
} }

View File

@ -11,7 +11,7 @@ import {
ValidateNested, ValidateNested,
ValidationArguments, ValidationArguments,
ValidatorConstraint, ValidatorConstraint,
ValidatorConstraintInterface, ValidatorConstraintInterface
} from 'class-validator'; } from 'class-validator';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';

View File

@ -11,7 +11,7 @@ import {
NETDISK_COPY_SUFFIX, NETDISK_COPY_SUFFIX,
NETDISK_DELIMITER, NETDISK_DELIMITER,
NETDISK_HANDLE_MAX_ITEM, NETDISK_HANDLE_MAX_ITEM,
NETDISK_LIMIT, NETDISK_LIMIT
} from '~/constants/oss.constant'; } from '~/constants/oss.constant';
import { AccountInfo } from '~/modules/user/user.model'; import { AccountInfo } from '~/modules/user/user.model';
@ -38,7 +38,7 @@ export class NetDiskManageService {
) { ) {
this.mac = new qiniu.auth.digest.Mac(this.qiniuConfig.accessKey, this.qiniuConfig.secretKey); this.mac = new qiniu.auth.digest.Mac(this.qiniuConfig.accessKey, this.qiniuConfig.secretKey);
this.config = new qiniu.conf.Config({ this.config = new qiniu.conf.Config({
zone: this.qiniuConfig.zone, zone: this.qiniuConfig.zone
}); });
// bucket manager // bucket manager
this.bucketManager = new qiniu.rs.BucketManager(this.mac, this.config); this.bucketManager = new qiniu.rs.BucketManager(this.mac, this.config);
@ -60,7 +60,7 @@ export class NetDiskManageService {
prefix: searching ? '' : prefix, prefix: searching ? '' : prefix,
limit: NETDISK_LIMIT, limit: NETDISK_LIMIT,
delimiter: searching ? '' : NETDISK_DELIMITER, delimiter: searching ? '' : NETDISK_DELIMITER,
marker, marker
}, },
(err, respBody, respInfo) => { (err, respBody, respInfo) => {
if (err) { if (err) {
@ -80,7 +80,7 @@ export class NetDiskManageService {
fileList.push({ fileList.push({
name: (dirPath as string).substr(0, dirPath.length - 1).replace(prefix, ''), name: (dirPath as string).substr(0, dirPath.length - 1).replace(prefix, ''),
type: 'dir', type: 'dir',
id: generateRandomValue(10), id: generateRandomValue(10)
}); });
} }
} }
@ -104,7 +104,7 @@ export class NetDiskManageService {
id: generateRandomValue(10), id: generateRandomValue(10),
name: ditName, name: ditName,
type: 'dir', type: 'dir',
belongTo: pathList.join(NETDISK_DELIMITER), belongTo: pathList.join(NETDISK_DELIMITER)
}); });
} else if (name.includes(skey)) { } else if (name.includes(skey)) {
// 文件 // 文件
@ -115,7 +115,7 @@ export class NetDiskManageService {
fsize: item.fsize, fsize: item.fsize,
mimeType: item.mimeType, mimeType: item.mimeType,
putTime: new Date(Number.parseInt(item.putTime) / 10000), putTime: new Date(Number.parseInt(item.putTime) / 10000),
belongTo: pathList.join(NETDISK_DELIMITER), belongTo: pathList.join(NETDISK_DELIMITER)
}); });
} }
} else { } else {
@ -128,7 +128,7 @@ export class NetDiskManageService {
type: 'file', type: 'file',
fsize: item.fsize, fsize: item.fsize,
mimeType: item.mimeType, mimeType: item.mimeType,
putTime: new Date(Number.parseInt(item.putTime) / 10000), putTime: new Date(Number.parseInt(item.putTime) / 10000)
}); });
} }
} }
@ -136,7 +136,7 @@ export class NetDiskManageService {
} }
resolve({ resolve({
list: fileList, list: fileList,
marker: respBody.marker || null, marker: respBody.marker || null
}); });
} else { } else {
reject( reject(
@ -170,7 +170,7 @@ export class NetDiskManageService {
putTime: new Date(Number.parseInt(respBody.putTime) / 10000), putTime: new Date(Number.parseInt(respBody.putTime) / 10000),
type: respBody.type, type: respBody.type,
uploader: '', uploader: '',
mark: respBody?.['x-qn-meta']?.['!mark'] ?? '', mark: respBody?.['x-qn-meta']?.['!mark'] ?? ''
}; };
if (!respBody.endUser) { if (!respBody.endUser) {
resolve(detailInfo); resolve(detailInfo);
@ -295,7 +295,7 @@ export class NetDiskManageService {
scope: this.qiniuConfig.bucket, scope: this.qiniuConfig.bucket,
insertOnly: 1, insertOnly: 1,
fsizeLimit: 1024 ** 2 * 10, fsizeLimit: 1024 ** 2 * 10,
endUser, endUser
}); });
const uploadToken = policy.uploadToken(this.mac); const uploadToken = policy.uploadToken(this.mac);
return uploadToken; return uploadToken;
@ -310,7 +310,7 @@ export class NetDiskManageService {
const fileName = `${dir}${name}`; const fileName = `${dir}${name}`;
const toFileName = `${dir}${toName}`; const toFileName = `${dir}${toName}`;
const op = { const op = {
force: true, force: true
}; };
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.bucketManager.move( this.bucketManager.move(
@ -345,7 +345,7 @@ export class NetDiskManageService {
const fileName = `${dir}${name}`; const fileName = `${dir}${name}`;
const toFileName = `${toDir}${name}`; const toFileName = `${toDir}${name}`;
const op = { const op = {
force: true, force: true
}; };
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.bucketManager.move( this.bucketManager.move(
@ -383,7 +383,7 @@ export class NetDiskManageService {
const bn = basename(name, ext); const bn = basename(name, ext);
const toFileName = `${toDir}${bn}${NETDISK_COPY_SUFFIX}${ext}`; const toFileName = `${toDir}${bn}${NETDISK_COPY_SUFFIX}${ext}`;
const op = { const op = {
force: true, force: true
}; };
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.bucketManager.copy( this.bucketManager.copy(
@ -420,7 +420,7 @@ export class NetDiskManageService {
let hasFile = true; let hasFile = true;
let marker = ''; let marker = '';
const op = { const op = {
force: true, force: true
}; };
const bucketName = this.qiniuConfig.bucket; const bucketName = this.qiniuConfig.bucket;
while (hasFile) { while (hasFile) {
@ -431,7 +431,7 @@ export class NetDiskManageService {
{ {
prefix: dirName, prefix: dirName,
limit: NETDISK_HANDLE_MAX_ITEM, limit: NETDISK_HANDLE_MAX_ITEM,
marker, marker
}, },
(err, respBody, respInfo) => { (err, respBody, respInfo) => {
if (err) { if (err) {
@ -567,7 +567,7 @@ export class NetDiskManageService {
{ {
prefix: dirName, prefix: dirName,
limit: NETDISK_HANDLE_MAX_ITEM, limit: NETDISK_HANDLE_MAX_ITEM,
marker, marker
}, },
(err, respBody, respInfo) => { (err, respBody, respInfo) => {
if (err) { if (err) {
@ -618,7 +618,7 @@ export class NetDiskManageService {
async copyMultiFileOrDir(fileList: FileOpItem[], dir: string, toDir: string): Promise<void> { async copyMultiFileOrDir(fileList: FileOpItem[], dir: string, toDir: string): Promise<void> {
const files = fileList.filter(item => item.type === 'file'); const files = fileList.filter(item => item.type === 'file');
const op = { const op = {
force: true, force: true
}; };
if (files.length > 0) { if (files.length > 0) {
// 批处理文件 // 批处理文件
@ -671,7 +671,7 @@ export class NetDiskManageService {
{ {
prefix: dirName, prefix: dirName,
limit: NETDISK_HANDLE_MAX_ITEM, limit: NETDISK_HANDLE_MAX_ITEM,
marker, marker
}, },
(err, respBody, respInfo) => { (err, respBody, respInfo) => {
if (err) { if (err) {
@ -729,7 +729,7 @@ export class NetDiskManageService {
async moveMultiFileOrDir(fileList: FileOpItem[], dir: string, toDir: string): Promise<void> { async moveMultiFileOrDir(fileList: FileOpItem[], dir: string, toDir: string): Promise<void> {
const files = fileList.filter(item => item.type === 'file'); const files = fileList.filter(item => item.type === 'file');
const op = { const op = {
force: true, force: true
}; };
if (files.length > 0) { if (files.length > 0) {
// 批处理文件 // 批处理文件
@ -782,7 +782,7 @@ export class NetDiskManageService {
{ {
prefix: dirName, prefix: dirName,
limit: NETDISK_HANDLE_MAX_ITEM, limit: NETDISK_HANDLE_MAX_ITEM,
marker, marker
}, },
(err, respBody, respInfo) => { (err, respBody, respInfo) => {
if (err) { if (err) {

View File

@ -15,11 +15,11 @@ import { NetDiskOverviewService } from './overview/overview.service';
RouterModule.register([ RouterModule.register([
{ {
path: 'netdisk', path: 'netdisk',
module: NetdiskModule, module: NetdiskModule
}, }
]), ])
], ],
controllers: [NetDiskManageController, NetDiskOverviewController], controllers: [NetDiskManageController, NetDiskOverviewController],
providers: [NetDiskManageService, NetDiskOverviewService], providers: [NetDiskManageService, NetDiskOverviewService]
}) })
export class NetdiskModule {} export class NetdiskModule {}

View File

@ -8,7 +8,7 @@ import { OverviewSpaceInfo } from './overview.dto';
import { NetDiskOverviewService } from './overview.service'; import { NetDiskOverviewService } from './overview.service';
export const permissions = definePermission('netdisk:overview', { export const permissions = definePermission('netdisk:overview', {
DESC: 'desc', DESC: 'desc'
} as const); } as const);
@ApiTags('NetDiskOverview - 网盘概览模块') @ApiTags('NetDiskOverview - 网盘概览模块')
@ -35,7 +35,7 @@ export class NetDiskOverviewController {
hitSize: hit.datas[hit.datas.length - 1], hitSize: hit.datas[hit.datas.length - 1],
spaceSize: space.datas[space.datas.length - 1], spaceSize: space.datas[space.datas.length - 1],
flowTrend: flow, flowTrend: flow,
sizeTrend: space, sizeTrend: space
}; };
} }
} }

View File

@ -36,7 +36,7 @@ export class NetDiskOverviewService {
getStatisticUrl(type: string, queryParams = {}) { getStatisticUrl(type: string, queryParams = {}) {
const defaultParams = { const defaultParams = {
$bucket: this.qiniuConfig.bucket, $bucket: this.qiniuConfig.bucket,
g: 'day', g: 'day'
}; };
const searchParams = new URLSearchParams({ ...defaultParams, ...queryParams }); const searchParams = new URLSearchParams({ ...defaultParams, ...queryParams });
return decodeURIComponent(`${OSS_API}/v6/${type}?${searchParams}`); return decodeURIComponent(`${OSS_API}/v6/${type}?${searchParams}`);
@ -53,8 +53,8 @@ export class NetDiskOverviewService {
return this.httpService.axiosRef.get(url, { return this.httpService.axiosRef.get(url, {
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded', 'Content-Type': 'application/x-www-form-urlencoded',
Authorization: `${accessToken}`, Authorization: `${accessToken}`
}, }
}); });
} }
@ -89,7 +89,7 @@ export class NetDiskOverviewService {
datas: data.datas, datas: data.datas,
times: data.times.map(e => { times: data.times.map(e => {
return dayjs.unix(e).date(); return dayjs.unix(e).date();
}), })
}; };
} }
@ -105,7 +105,7 @@ export class NetDiskOverviewService {
times: data.times.map(e => { times: data.times.map(e => {
return dayjs.unix(e).date(); return dayjs.unix(e).date();
}), }),
datas: data.datas, datas: data.datas
}; };
} }
@ -121,7 +121,7 @@ export class NetDiskOverviewService {
end, end,
$ftype: 0, $ftype: 0,
$src: 'origin', $src: 'origin',
select: 'flow', select: 'flow'
}); });
const { data } = await this.getStatisticData(url); const { data } = await this.getStatisticData(url);
const times = []; const times = [];
@ -132,7 +132,7 @@ export class NetDiskOverviewService {
}); });
return { return {
times, times,
datas, datas
}; };
} }
@ -148,7 +148,7 @@ export class NetDiskOverviewService {
end, end,
$ftype: 0, $ftype: 0,
$src: 'inner', $src: 'inner',
select: 'hit', select: 'hit'
}); });
const { data } = await this.getStatisticData(url); const { data } = await this.getStatisticData(url);
const times = []; const times = [];
@ -159,7 +159,7 @@ export class NetDiskOverviewService {
}); });
return { return {
times, times,
datas, datas
}; };
} }
} }

View File

@ -5,7 +5,7 @@ import {
ParseIntPipe, ParseIntPipe,
Req, Req,
Res, Res,
Sse, Sse
} from '@nestjs/common'; } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { FastifyReply, FastifyRequest } from 'fastify'; import { FastifyReply, FastifyRequest } from 'fastify';
@ -26,7 +26,7 @@ export class SseController implements BeforeApplicationShutdown {
private closeAllConnect() { private closeAllConnect() {
this.sseService.sendToAll({ this.sseService.sendToAll({
type: 'close', type: 'close',
data: 'bye~', data: 'bye~'
}); });
this.replyMap.forEach(reply => { this.replyMap.forEach(reply => {
reply.raw.end().destroy(); reply.raw.end().destroy();

View File

@ -7,6 +7,6 @@ import { SseService } from './sse.service';
imports: [], imports: [],
controllers: [SseController], controllers: [SseController],
providers: [SseService], providers: [SseService],
exports: [SseService], exports: [SseService]
}) })
export class SseModule {} export class SseModule {}

View File

@ -58,9 +58,9 @@ export class SseService {
const roleMenus = await RoleEntity.find({ const roleMenus = await RoleEntity.find({
where: { where: {
menus: { menus: {
id: In(menuIds), id: In(menuIds)
}, }
}, }
}); });
const roleIds = roleMenus.map(n => n.id).concat(ROOT_ROLE_ID); const roleIds = roleMenus.map(n => n.id).concat(ROOT_ROLE_ID);
await this.noticeClientToUpdateMenusByRoleIds(roleIds); await this.noticeClientToUpdateMenusByRoleIds(roleIds);
@ -73,9 +73,9 @@ export class SseService {
const users = await UserEntity.find({ const users = await UserEntity.find({
where: { where: {
roles: { roles: {
id: In(roleIds), id: In(roleIds)
}, }
}, }
}); });
if (users) { if (users) {
const userIds = users.map(n => n.id); const userIds = users.map(n => n.id);

View File

@ -18,7 +18,7 @@ export const permissions = definePermission('system:dept', {
CREATE: 'create', CREATE: 'create',
READ: 'read', READ: 'read',
UPDATE: 'update', UPDATE: 'update',
DELETE: 'delete', DELETE: 'delete'
} as const); } as const);
@ApiSecurityAuth() @ApiSecurityAuth()

View File

@ -8,7 +8,7 @@ import {
IsString, IsString,
Min, Min,
MinLength, MinLength,
ValidateNested, ValidateNested
} from 'class-validator'; } from 'class-validator';
export class DeptDto { export class DeptDto {

View File

@ -14,6 +14,6 @@ const services = [DeptService];
imports: [TypeOrmModule.forFeature([DeptEntity]), UserModule, RoleModule], imports: [TypeOrmModule.forFeature([DeptEntity]), UserModule, RoleModule],
controllers: [DeptController], controllers: [DeptController],
providers: [...services], providers: [...services],
exports: [TypeOrmModule, ...services], exports: [TypeOrmModule, ...services]
}) })
export class DeptModule {} export class DeptModule {}

View File

@ -46,7 +46,7 @@ export class DeptService {
await this.deptRepository.save({ await this.deptRepository.save({
...data, ...data,
parent, parent
}); });
} }
@ -61,7 +61,7 @@ export class DeptService {
await this.deptRepository.save({ await this.deptRepository.save({
...item, ...item,
...data, ...data,
parent, parent
}); });
} }
@ -117,7 +117,7 @@ export class DeptService {
const deptTree = await this.deptRepository.findTrees({ const deptTree = await this.deptRepository.findTrees({
depth: 2, depth: 2,
relations: ['parent'], relations: ['parent']
}); });
deleteEmptyChildren(deptTree); deleteEmptyChildren(deptTree);

View File

@ -17,7 +17,7 @@ export const permissions = definePermission('system:dict-item', {
CREATE: 'create', CREATE: 'create',
READ: 'read', READ: 'read',
UPDATE: 'update', UPDATE: 'update',
DELETE: 'delete', DELETE: 'delete'
} as const); } as const);
@ApiTags('System - 字典项模块') @ApiTags('System - 字典项模块')

View File

@ -11,6 +11,6 @@ const services = [DictItemService];
imports: [TypeOrmModule.forFeature([DictItemEntity])], imports: [TypeOrmModule.forFeature([DictItemEntity])],
controllers: [DictItemController], controllers: [DictItemController],
providers: [...services], providers: [...services],
exports: [TypeOrmModule, ...services], exports: [TypeOrmModule, ...services]
}) })
export class DictItemModule {} export class DictItemModule {}

View File

@ -26,7 +26,7 @@ export class DictItemService {
pageSize, pageSize,
label, label,
value, value,
typeId, typeId
}: DictItemQueryDto): Promise<Pagination<DictItemEntity>> { }: DictItemQueryDto): Promise<Pagination<DictItemEntity>> {
const queryBuilder = this.dictItemRepository const queryBuilder = this.dictItemRepository
.createQueryBuilder('dict_item') .createQueryBuilder('dict_item')
@ -35,8 +35,8 @@ export class DictItemService {
...(label && { label: Like(`%${label}%`) }), ...(label && { label: Like(`%${label}%`) }),
...(value && { value: Like(`%${value}%`) }), ...(value && { value: Like(`%${value}%`) }),
type: { type: {
id: typeId, id: typeId
}, }
}); });
return paginate(queryBuilder, { page, pageSize }); return paginate(queryBuilder, { page, pageSize });
@ -57,8 +57,8 @@ export class DictItemService {
await this.dictItemRepository.insert({ await this.dictItemRepository.insert({
...rest, ...rest,
type: { type: {
id: typeId, id: typeId
}, }
}); });
} }
@ -70,8 +70,8 @@ export class DictItemService {
await this.dictItemRepository.update(id, { await this.dictItemRepository.update(id, {
...rest, ...rest,
type: { type: {
id: typeId, id: typeId
}, }
}); });
} }

View File

@ -17,7 +17,7 @@ export const permissions = definePermission('system:dict-type', {
CREATE: 'create', CREATE: 'create',
READ: 'read', READ: 'read',
UPDATE: 'update', UPDATE: 'update',
DELETE: 'delete', DELETE: 'delete'
} as const); } as const);
@ApiTags('System - 字典类型模块') @ApiTags('System - 字典类型模块')

View File

@ -11,6 +11,6 @@ const services = [DictTypeService];
imports: [TypeOrmModule.forFeature([DictTypeEntity])], imports: [TypeOrmModule.forFeature([DictTypeEntity])],
controllers: [DictTypeController], controllers: [DictTypeController],
providers: [...services], providers: [...services],
exports: [TypeOrmModule, ...services], exports: [TypeOrmModule, ...services]
}) })
export class DictTypeModule {} export class DictTypeModule {}

View File

@ -25,11 +25,11 @@ export class DictTypeService {
page, page,
pageSize, pageSize,
name, name,
code, code
}: DictTypeQueryDto): Promise<Pagination<DictTypeEntity>> { }: DictTypeQueryDto): Promise<Pagination<DictTypeEntity>> {
const queryBuilder = this.dictTypeRepository.createQueryBuilder('dict_type').where({ const queryBuilder = this.dictTypeRepository.createQueryBuilder('dict_type').where({
...(name && { name: Like(`%${name}%`) }), ...(name && { name: Like(`%${name}%`) }),
...(code && { code: Like(`%${code}%`) }), ...(code && { code: Like(`%${code}%`) })
}); });
return paginate(queryBuilder, { page, pageSize }); return paginate(queryBuilder, { page, pageSize });

View File

@ -17,7 +17,7 @@ import { TaskLogService } from './services/task-log.service';
export const permissions = definePermission('system:log', { export const permissions = definePermission('system:log', {
TaskList: 'task:list', TaskList: 'task:list',
LogList: 'login:list', LogList: 'login:list',
CaptchaList: 'captcha:list', CaptchaList: 'captcha:list'
} as const); } as const);
@ApiSecurityAuth() @ApiSecurityAuth()

View File

@ -16,10 +16,10 @@ const providers = [LoginLogService, TaskLogService, CaptchaLogService];
@Module({ @Module({
imports: [ imports: [
TypeOrmModule.forFeature([LoginLogEntity, CaptchaLogEntity, TaskLogEntity]), TypeOrmModule.forFeature([LoginLogEntity, CaptchaLogEntity, TaskLogEntity]),
UserModule, UserModule
], ],
controllers: [LogController], controllers: [LogController],
providers: [...providers], providers: [...providers],
exports: [TypeOrmModule, ...providers], exports: [TypeOrmModule, ...providers]
}) })
export class LogModule {} export class LogModule {}

View File

@ -25,7 +25,7 @@ export class CaptchaLogService {
account, account,
code, code,
provider, provider,
userId: uid, userId: uid
}); });
} }
@ -36,7 +36,7 @@ export class CaptchaLogService {
return paginate<CaptchaLogEntity>(queryBuilder, { return paginate<CaptchaLogEntity>(queryBuilder, {
page, page,
pageSize, pageSize
}); });
} }

View File

@ -23,7 +23,7 @@ async function parseLoginLog(e: any, parser: UAParser): Promise<LoginLogInfo> {
os: `${`${uaResult.os.name ?? ''} `}${uaResult.os.version}`, os: `${`${uaResult.os.name ?? ''} `}${uaResult.os.version}`,
browser: `${`${uaResult.browser.name ?? ''} `}${uaResult.browser.version}`, browser: `${`${uaResult.browser.name ?? ''} `}${uaResult.browser.version}`,
username: e.user_username, username: e.user_username,
time: e.login_log_created_at, time: e.login_log_created_at
}; };
} }
@ -42,7 +42,7 @@ export class LoginLogService {
ip, ip,
ua, ua,
address, address,
user: { id: uid }, user: { id: uid }
}); });
} catch (e) { } catch (e) {
console.error(e); console.error(e);
@ -59,15 +59,15 @@ export class LoginLogService {
...(time && { createdAt: Between(time[0], time[1]) }), ...(time && { createdAt: Between(time[0], time[1]) }),
...(username && { ...(username && {
user: { user: {
username: Like(`%${username}%`), username: Like(`%${username}%`)
}, }
}), })
}) })
.orderBy('login_log.created_at', 'DESC'); .orderBy('login_log.created_at', 'DESC');
const { items, ...rest } = await paginateRaw<LoginLogEntity>(queryBuilder, { const { items, ...rest } = await paginateRaw<LoginLogEntity>(queryBuilder, {
page, page,
pageSize, pageSize
}); });
const parser = new UAParser(); const parser = new UAParser();
@ -75,7 +75,7 @@ export class LoginLogService {
return { return {
items: loginLogInfos, items: loginLogInfos,
...rest, ...rest
}; };
} }

View File

@ -20,7 +20,7 @@ export class TaskLogService {
status, status,
detail: err, detail: err,
time, time,
task: { id: tid }, task: { id: tid }
}); });
return result.id; return result.id;
} }
@ -33,7 +33,7 @@ export class TaskLogService {
return paginate<TaskLogEntity>(queryBuilder, { return paginate<TaskLogEntity>(queryBuilder, {
page, page,
pageSize, pageSize
}); });
} }

View File

@ -6,7 +6,7 @@ import {
Get, Get,
Post, Post,
Put, Put,
Query, Query
} from '@nestjs/common'; } from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { flattenDeep } from 'lodash'; import { flattenDeep } from 'lodash';
@ -17,7 +17,7 @@ import { ApiSecurityAuth } from '~/common/decorators/swagger.decorator';
import { import {
Perm, Perm,
definePermission, definePermission,
getDefinePermissions, getDefinePermissions
} from '~/modules/auth/decorators/permission.decorator'; } from '~/modules/auth/decorators/permission.decorator';
import { MenuDto, MenuQueryDto, MenuUpdateDto } from './menu.dto'; import { MenuDto, MenuQueryDto, MenuUpdateDto } from './menu.dto';
@ -29,7 +29,7 @@ export const permissions = definePermission('system:menu', {
CREATE: 'create', CREATE: 'create',
READ: 'read', READ: 'read',
UPDATE: 'update', UPDATE: 'update',
DELETE: 'delete', DELETE: 'delete'
} as const); } as const);
@ApiTags('System - 菜单权限模块') @ApiTags('System - 菜单权限模块')

View File

@ -7,7 +7,7 @@ import {
IsString, IsString,
Min, Min,
MinLength, MinLength,
ValidateIf, ValidateIf
} from 'class-validator'; } from 'class-validator';
export class MenuDto { export class MenuDto {

View File

@ -49,7 +49,7 @@ export class MenuEntity extends CommonEntity {
status: number; status: number;
@ManyToMany(() => RoleEntity, role => role.menus, { @ManyToMany(() => RoleEntity, role => role.menus, {
onDelete: 'CASCADE', onDelete: 'CASCADE'
}) })
roles: Relation<RoleEntity[]>; roles: Relation<RoleEntity[]>;
} }

View File

@ -15,6 +15,6 @@ const providers = [MenuService, SseService];
imports: [TypeOrmModule.forFeature([MenuEntity]), forwardRef(() => RoleModule)], imports: [TypeOrmModule.forFeature([MenuEntity]), forwardRef(() => RoleModule)],
controllers: [MenuController], controllers: [MenuController],
providers: [...providers], providers: [...providers],
exports: [TypeOrmModule, ...providers], exports: [TypeOrmModule, ...providers]
}) })
export class MenuModule {} export class MenuModule {}

View File

@ -39,9 +39,9 @@ export class MenuService {
...(path && { path: Like(`%${path}%`) }), ...(path && { path: Like(`%${path}%`) }),
...(permission && { permission: Like(`%${permission}%`) }), ...(permission && { permission: Like(`%${permission}%`) }),
...(component && { component: Like(`%${component}%`) }), ...(component && { component: Like(`%${component}%`) }),
...(isNumber(status) ? { status } : null), ...(isNumber(status) ? { status } : null)
}, },
order: { orderNo: 'ASC' }, order: { orderNo: 'ASC' }
}); });
const menuList = generatorMenu(menus); const menuList = generatorMenu(menus);
@ -166,7 +166,7 @@ export class MenuService {
if (this.roleService.hasAdminRole(roleIds)) { if (this.roleService.hasAdminRole(roleIds)) {
result = await this.menuRepository.findBy({ result = await this.menuRepository.findBy({
permission: Not(IsNull()), permission: Not(IsNull()),
type: In([1, 2]), type: In([1, 2])
}); });
} else { } else {
if (isEmpty(roleIds)) return permission; if (isEmpty(roleIds)) return permission;
@ -237,9 +237,9 @@ export class MenuService {
return !!(await this.menuRepository.findOne({ return !!(await this.menuRepository.findOne({
where: { where: {
roles: { roles: {
id, id
}, }
}, }
})); }));
} }
} }

View File

@ -16,7 +16,7 @@ import { OnlineService } from './online.service';
export const permissions = definePermission('system:online', { export const permissions = definePermission('system:online', {
LIST: 'list', LIST: 'list',
KICK: 'kick', KICK: 'kick'
} as const); } as const);
@ApiTags('System - 在线用户模块') @ApiTags('System - 在线用户模块')

View File

@ -18,10 +18,10 @@ const providers = [OnlineService];
forwardRef(() => SocketModule), forwardRef(() => SocketModule),
AuthModule, AuthModule,
UserModule, UserModule,
RoleModule, RoleModule
], ],
controllers: [OnlineController], controllers: [OnlineController],
providers, providers,
exports: [...providers], exports: [...providers]
}) })
export class OnlineModule {} export class OnlineModule {}

View File

@ -90,7 +90,7 @@ export class OnlineService {
time: e.created_at, time: e.created_at,
os: `${u.os.name} ${u.os.version}`, os: `${u.os.name} ${u.os.version}`,
browser: `${u.browser.name} ${u.browser.version}`, browser: `${u.browser.name} ${u.browser.version}`,
disable: currentUid === e.id || e.id === rootUserId, disable: currentUid === e.id || e.id === rootUserId
}; };
}); });
} }

View File

@ -16,7 +16,7 @@ export const permissions = definePermission('system:param-config', {
CREATE: 'create', CREATE: 'create',
READ: 'read', READ: 'read',
UPDATE: 'update', UPDATE: 'update',
DELETE: 'delete', DELETE: 'delete'
} as const); } as const);
@ApiTags('System - 参数配置模块') @ApiTags('System - 参数配置模块')

View File

@ -11,6 +11,6 @@ const services = [ParamConfigService];
imports: [TypeOrmModule.forFeature([ParamConfigEntity])], imports: [TypeOrmModule.forFeature([ParamConfigEntity])],
controllers: [ParamConfigController], controllers: [ParamConfigController],
providers: [...services], providers: [...services],
exports: [TypeOrmModule, ...services], exports: [TypeOrmModule, ...services]
}) })
export class ParamConfigModule {} export class ParamConfigModule {}

View File

@ -24,13 +24,13 @@ export class ParamConfigService {
async page({ async page({
page, page,
pageSize, pageSize,
name, name
}: ParamConfigQueryDto): Promise<Pagination<ParamConfigEntity>> { }: ParamConfigQueryDto): Promise<Pagination<ParamConfigEntity>> {
const queryBuilder = this.paramConfigRepository.createQueryBuilder('config'); const queryBuilder = this.paramConfigRepository.createQueryBuilder('config');
if (name) { if (name) {
queryBuilder.where('config.name LIKE :name', { queryBuilder.where('config.name LIKE :name', {
name: `%${name}%`, name: `%${name}%`
}); });
} }
@ -80,7 +80,7 @@ export class ParamConfigService {
async findValueByKey(key: string): Promise<string | null> { async findValueByKey(key: string): Promise<string | null> {
const result = await this.paramConfigRepository.findOne({ const result = await this.paramConfigRepository.findOne({
where: { key }, where: { key },
select: ['value'], select: ['value']
}); });
if (result) return result.value; if (result) return result.value;

View File

@ -6,7 +6,7 @@ import {
Get, Get,
Post, Post,
Put, Put,
Query, Query
} from '@nestjs/common'; } from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiTags } from '@nestjs/swagger';
@ -28,7 +28,7 @@ export const permissions = definePermission('system:role', {
CREATE: 'create', CREATE: 'create',
READ: 'read', READ: 'read',
UPDATE: 'update', UPDATE: 'update',
DELETE: 'delete', DELETE: 'delete'
} as const); } as const);
@ApiTags('System - 角色模块') @ApiTags('System - 角色模块')

View File

@ -37,7 +37,7 @@ export class RoleEntity extends CommonEntity {
@JoinTable({ @JoinTable({
name: 'sys_role_menus', name: 'sys_role_menus',
joinColumn: { name: 'role_id', referencedColumnName: 'id' }, joinColumn: { name: 'role_id', referencedColumnName: 'id' },
inverseJoinColumn: { name: 'menu_id', referencedColumnName: 'id' }, inverseJoinColumn: { name: 'menu_id', referencedColumnName: 'id' }
}) })
menus: Relation<MenuEntity[]>; menus: Relation<MenuEntity[]>;
} }

View File

@ -15,6 +15,6 @@ const providers = [RoleService, SseService];
imports: [TypeOrmModule.forFeature([RoleEntity]), forwardRef(() => MenuModule)], imports: [TypeOrmModule.forFeature([RoleEntity]), forwardRef(() => MenuModule)],
controllers: [RoleController], controllers: [RoleController],
providers: [...providers], providers: [...providers],
exports: [TypeOrmModule, ...providers], exports: [TypeOrmModule, ...providers]
}) })
export class RoleModule {} export class RoleModule {}

View File

@ -32,17 +32,17 @@ export class RoleService {
pageSize, pageSize,
name, name,
value, value,
status, status
}: RoleQueryDto): Promise<Pagination<RoleEntity>> { }: RoleQueryDto): Promise<Pagination<RoleEntity>> {
const queryBuilder = this.roleRepository.createQueryBuilder('role').where({ const queryBuilder = this.roleRepository.createQueryBuilder('role').where({
...(name ? { name: Like(`%${name}%`) } : null), ...(name ? { name: Like(`%${name}%`) } : null),
...(value ? { value: Like(`%${value}%`) } : null), ...(value ? { value: Like(`%${value}%`) } : null),
...(isNumber(status) ? { status } : null), ...(isNumber(status) ? { status } : null)
}); });
return paginate<RoleEntity>(queryBuilder, { return paginate<RoleEntity>(queryBuilder, {
page, page,
pageSize, pageSize
}); });
} }
@ -53,13 +53,13 @@ export class RoleService {
const info = await this.roleRepository const info = await this.roleRepository
.createQueryBuilder('role') .createQueryBuilder('role')
.where({ .where({
id, id
}) })
.getOne(); .getOne();
const menus = await this.menuRepository.find({ const menus = await this.menuRepository.find({
where: { roles: { id } }, where: { roles: { id } },
select: ['id'], select: ['id']
}); });
return { ...info, menuIds: menus.map(m => m.id) }; return { ...info, menuIds: menus.map(m => m.id) };
@ -76,7 +76,7 @@ export class RoleService {
async create({ menuIds, ...data }: RoleDto): Promise<{ roleId: number }> { async create({ menuIds, ...data }: RoleDto): Promise<{ roleId: number }> {
const role = await this.roleRepository.save({ const role = await this.roleRepository.save({
...data, ...data,
menus: menuIds ? await this.menuRepository.findBy({ id: In(menuIds) }) : [], menus: menuIds ? await this.menuRepository.findBy({ id: In(menuIds) }) : []
}); });
return { roleId: role.id }; return { roleId: role.id };
@ -92,7 +92,7 @@ export class RoleService {
// using transaction // using transaction
await this.entityManager.transaction(async manager => { await this.entityManager.transaction(async manager => {
const menus = await this.menuRepository.find({ const menus = await this.menuRepository.find({
where: { id: In(menuIds) }, where: { id: In(menuIds) }
}); });
const role = await this.roleRepository.findOne({ where: { id } }); const role = await this.roleRepository.findOne({ where: { id } });
@ -108,8 +108,8 @@ export class RoleService {
async getRoleIdsByUser(id: number): Promise<number[]> { async getRoleIdsByUser(id: number): Promise<number[]> {
const roles = await this.roleRepository.find({ const roles = await this.roleRepository.find({
where: { where: {
users: { id }, users: { id }
}, }
}); });
if (!isEmpty(roles)) return roles.map(r => r.id); if (!isEmpty(roles)) return roles.map(r => r.id);
@ -120,7 +120,7 @@ export class RoleService {
async getRoleValues(ids: number[]): Promise<string[]> { async getRoleValues(ids: number[]): Promise<string[]> {
return ( return (
await this.roleRepository.findBy({ await this.roleRepository.findBy({
id: In(ids), id: In(ids)
}) })
).map(r => r.value); ).map(r => r.value);
} }
@ -128,8 +128,8 @@ export class RoleService {
async isAdminRoleByUser(uid: number): Promise<boolean> { async isAdminRoleByUser(uid: number): Promise<boolean> {
const roles = await this.roleRepository.find({ const roles = await this.roleRepository.find({
where: { where: {
users: { id: uid }, users: { id: uid }
}, }
}); });
if (!isEmpty(roles)) { if (!isEmpty(roles)) {
@ -149,9 +149,9 @@ export class RoleService {
return this.roleRepository.exist({ return this.roleRepository.exist({
where: { where: {
users: { users: {
roles: { id }, roles: { id }
}, }
}, }
}); });
} }
} }

View File

@ -11,6 +11,6 @@ const providers = [ServeService];
imports: [forwardRef(() => SystemModule)], imports: [forwardRef(() => SystemModule)],
controllers: [ServeController], controllers: [ServeController],
providers: [...providers], providers: [...providers],
exports: [...providers], exports: [...providers]
}) })
export class ServeModule {} export class ServeModule {}

View File

@ -15,7 +15,7 @@ export class ServeService {
si.osInfo(), si.osInfo(),
si.cpu(), si.cpu(),
si.currentLoad(), si.currentLoad(),
si.mem(), si.mem()
]) ])
).map((p: any) => p.value); ).map((p: any) => p.value);
@ -36,7 +36,7 @@ export class ServeService {
npmVersion: versions.npm, npmVersion: versions.npm,
nodeVersion: versions.node, nodeVersion: versions.node,
os: osinfo.platform, os: osinfo.platform,
arch: osinfo.arch, arch: osinfo.arch
}, },
cpu: { cpu: {
manufacturer: cpuinfo.manufacturer, manufacturer: cpuinfo.manufacturer,
@ -49,15 +49,15 @@ export class ServeService {
coresLoad: currentLoadinfo.cpus.map(e => { coresLoad: currentLoadinfo.cpus.map(e => {
return { return {
rawLoad: e.rawLoad, rawLoad: e.rawLoad,
rawLoadIdle: e.rawLoadIdle, rawLoadIdle: e.rawLoadIdle
}; };
}), })
}, },
disk: diskinfo, disk: diskinfo,
memory: { memory: {
total: meminfo.total, total: meminfo.total,
available: meminfo.available, available: meminfo.available
}, }
}; };
} }
} }

View File

@ -26,7 +26,7 @@ const modules = [
LogModule, LogModule,
TaskModule, TaskModule,
OnlineModule, OnlineModule,
ServeModule, ServeModule
]; ];
@Module({ @Module({
@ -36,10 +36,10 @@ const modules = [
{ {
path: 'system', path: 'system',
module: SystemModule, module: SystemModule,
children: [...modules], children: [...modules]
}, }
]), ])
], ],
exports: [...modules], exports: [...modules]
}) })
export class SystemModule {} export class SystemModule {}

View File

@ -1,11 +1,11 @@
export enum TaskStatus { export enum TaskStatus {
Disabled = 0, Disabled = 0,
Activited = 1, Activited = 1
} }
export enum TaskType { export enum TaskType {
Cron = 0, Cron = 0,
Interval = 1, Interval = 1
} }
export const SYS_TASK_QUEUE_NAME = 'system:sys-task'; export const SYS_TASK_QUEUE_NAME = 'system:sys-task';

View File

@ -20,7 +20,7 @@ export const permissions = definePermission('system:task', {
ONCE: 'once', ONCE: 'once',
START: 'start', START: 'start',
STOP: 'stop', STOP: 'stop'
} as const); } as const);
@ApiTags('System - 任务调度模块') @ApiTags('System - 任务调度模块')

View File

@ -13,7 +13,7 @@ import {
ValidateIf, ValidateIf,
ValidationArguments, ValidationArguments,
ValidatorConstraint, ValidatorConstraint,
ValidatorConstraintInterface, ValidatorConstraintInterface
} from 'class-validator'; } from 'class-validator';
import * as parser from 'cron-parser'; import * as parser from 'cron-parser';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
@ -70,7 +70,7 @@ export class TaskDto {
endTime: string; endTime: string;
@ApiPropertyOptional({ @ApiPropertyOptional({
description: '限制执行次数,负数则无限制', description: '限制执行次数,负数则无限制'
}) })
@IsOptional() @IsOptional()
@IsInt() @IsInt()

View File

@ -24,14 +24,14 @@ const providers = [TaskService, TaskConsumer];
name: SYS_TASK_QUEUE_NAME, name: SYS_TASK_QUEUE_NAME,
useFactory: (configService: ConfigService<ConfigKeyPaths>) => ({ useFactory: (configService: ConfigService<ConfigKeyPaths>) => ({
redis: configService.get<IRedisConfig>('redis'), redis: configService.get<IRedisConfig>('redis'),
prefix: SYS_TASK_QUEUE_PREFIX, prefix: SYS_TASK_QUEUE_PREFIX
}), }),
inject: [ConfigService], inject: [ConfigService]
}), }),
LogModule, LogModule
], ],
controllers: [TaskController], controllers: [TaskController],
providers: [...providers], providers: [...providers],
exports: [TypeOrmModule, ...providers], exports: [TypeOrmModule, ...providers]
}) })
export class TaskModule {} export class TaskModule {}

View File

@ -5,7 +5,7 @@ import {
Injectable, Injectable,
Logger, Logger,
NotFoundException, NotFoundException,
OnModuleInit, OnModuleInit
} from '@nestjs/common'; } from '@nestjs/common';
import { ModuleRef, Reflector } from '@nestjs/core'; import { ModuleRef, Reflector } from '@nestjs/core';
import { UnknownElementException } from '@nestjs/core/errors/exceptions/unknown-element.exception'; import { UnknownElementException } from '@nestjs/core/errors/exceptions/unknown-element.exception';
@ -69,7 +69,7 @@ export class TaskService implements OnModuleInit {
'failed', 'failed',
'paused', 'paused',
'waiting', 'waiting',
'completed', 'completed'
]); ]);
jobs.forEach(j => { jobs.forEach(j => {
j.remove(); j.remove();
@ -90,7 +90,7 @@ export class TaskService implements OnModuleInit {
name, name,
service, service,
type, type,
status, status
}: TaskQueryDto): Promise<Pagination<TaskEntity>> { }: TaskQueryDto): Promise<Pagination<TaskEntity>> {
const queryBuilder = this.taskRepository const queryBuilder = this.taskRepository
.createQueryBuilder('task') .createQueryBuilder('task')
@ -98,7 +98,7 @@ export class TaskService implements OnModuleInit {
...(name ? { name: Like(`%${name}%`) } : null), ...(name ? { name: Like(`%${name}%`) } : null),
...(service ? { service: Like(`%${service}%`) } : null), ...(service ? { service: Like(`%${service}%`) } : null),
...(type ? { type } : null), ...(type ? { type } : null),
...(isNumber(status) ? { status } : null), ...(isNumber(status) ? { status } : null)
}) })
.orderBy('task.id', 'ASC'); .orderBy('task.id', 'ASC');
@ -166,12 +166,12 @@ export class TaskService implements OnModuleInit {
if (task.type === 1) { if (task.type === 1) {
// 间隔 Repeat every millis (cron setting cannot be used together with this setting.) // 间隔 Repeat every millis (cron setting cannot be used together with this setting.)
repeat = { repeat = {
every: task.every, every: task.every
}; };
} else { } else {
// cron // cron
repeat = { repeat = {
cron: task.cron, cron: task.cron
}; };
// Start date when the repeat job should start repeating (only with cron). // Start date when the repeat job should start repeating (only with cron).
if (task.startTime) repeat.startDate = task.startTime; if (task.startTime) repeat.startDate = task.startTime;
@ -187,13 +187,13 @@ export class TaskService implements OnModuleInit {
if (job && job.opts) { if (job && job.opts) {
await this.taskRepository.update(task.id, { await this.taskRepository.update(task.id, {
jobOpts: JSON.stringify(job.opts.repeat), jobOpts: JSON.stringify(job.opts.repeat),
status: 1, status: 1
}); });
} else { } else {
// update status to 0标识暂停任务因为启动失败 // update status to 0标识暂停任务因为启动失败
await job?.remove(); await job?.remove();
await this.taskRepository.update(task.id, { await this.taskRepository.update(task.id, {
status: TaskStatus.Disabled, status: TaskStatus.Disabled
}); });
throw new BadRequestException('Task Start failed'); throw new BadRequestException('Task Start failed');
} }
@ -208,7 +208,7 @@ export class TaskService implements OnModuleInit {
const exist = await this.existJob(task.id.toString()); const exist = await this.existJob(task.id.toString());
if (!exist) { if (!exist) {
await this.taskRepository.update(task.id, { await this.taskRepository.update(task.id, {
status: TaskStatus.Disabled, status: TaskStatus.Disabled
}); });
return; return;
} }
@ -218,7 +218,7 @@ export class TaskService implements OnModuleInit {
'failed', 'failed',
'paused', 'paused',
'waiting', 'waiting',
'completed', 'completed'
]); ]);
jobs jobs
.filter(j => j.data.id === task.id) .filter(j => j.data.id === task.id)
@ -301,7 +301,7 @@ export class TaskService implements OnModuleInit {
if (!methodName) throw new BadRequestException('serviceName define BadRequestException'); if (!methodName) throw new BadRequestException('serviceName define BadRequestException');
const service = await this.moduleRef.get(serviceName, { const service = await this.moduleRef.get(serviceName, {
strict: false, strict: false
}); });
// 安全注解检查 // 安全注解检查

View File

@ -21,7 +21,7 @@ function createAliasProviders(): ExistingProvider[] {
for (const p of providers) { for (const p of providers) {
aliasProviders.push({ aliasProviders.push({
provide: p.name, provide: p.name,
useExisting: p, useExisting: p
}); });
} }
return aliasProviders; return aliasProviders;
@ -40,7 +40,7 @@ export class TasksModule {
module: TasksModule, module: TasksModule,
imports: [SystemModule, LogModule], imports: [SystemModule, LogModule],
providers: [...providers, ...aliasProviders], providers: [...providers, ...aliasProviders],
exports: aliasProviders, exports: aliasProviders
}; };
} }
} }

View File

@ -19,7 +19,7 @@ export const permissions = definePermission('todo', {
CREATE: 'create', CREATE: 'create',
READ: 'read', READ: 'read',
UPDATE: 'update', UPDATE: 'update',
DELETE: 'delete', DELETE: 'delete'
} as const); } as const);
@ApiTags('Business - Todo模块') @ApiTags('Business - Todo模块')

View File

@ -11,6 +11,6 @@ const services = [TodoService];
imports: [TypeOrmModule.forFeature([TodoEntity])], imports: [TypeOrmModule.forFeature([TodoEntity])],
controllers: [TodoController], controllers: [TodoController],
providers: [...services], providers: [...services],
exports: [TypeOrmModule, ...services], exports: [TypeOrmModule, ...services]
}) })
export class TodoModule {} export class TodoModule {}

Some files were not shown because too many files have changed in this diff Show More