From 3a29108da1f2d40911e32830f9709d36dd1c3bc5 Mon Sep 17 00:00:00 2001 From: luoer <952222@163.com> Date: Fri, 27 Oct 2023 17:33:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=AD=97=E5=85=B8?= =?UTF-8?q?=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content/data/db.sqlite | Bin 180224 -> 184320 bytes .../dto/find-{{fileName name}}.dto.ts.hbs | 2 +- .../{{fileName name}}.controller.ts.hbs | 12 ++-- src/app.module.ts | 8 +-- src/common/mail/index.ts | 1 - src/common/mail/mail.controller.ts | 7 -- src/common/mail/mail.module.ts | 4 +- .../entities/{base.ts => base.entity.ts} | 0 src/database/index.ts | 2 +- src/monitor/logger/logger.interceptor.ts | 4 +- src/storage/file/entities/file.entity.ts | 11 ++- src/storage/file/file.controller.ts | 6 +- src/storage/file/file.module.ts | 4 +- src/storage/file/file.service.ts | 44 ++++++------ src/system/auth/auth.controller.ts | 2 +- src/system/auth/auth.module.ts | 3 +- src/system/auth/index.ts | 4 +- src/system/auth/jwt/index.ts | 3 - src/system/auth/vo/logined-user.vo.ts | 14 ---- src/system/dict/data/dict.controller.ts | 49 +++++++++++++ src/system/dict/data/dict.module.ts | 14 ++++ src/system/dict/data/dict.service.ts | 65 ++++++++++++++++++ src/system/dict/data/dto/create-dict.dto.ts | 32 +++++++++ src/system/dict/data/dto/find-dict.dto.ts | 14 ++++ src/system/dict/data/dto/update-dict.dto.ts | 8 +++ src/system/dict/data/entities/dict.entity.ts | 48 +++++++++++++ src/system/dict/data/index.ts | 4 ++ .../dict/dictType/dictType.controller.ts | 49 +++++++++++++ src/system/dict/dictType/dictType.module.ts | 13 ++++ src/system/dict/dictType/dictType.service.ts | 55 +++++++++++++++ .../dict/dictType/dto/create-dictType.dto.ts | 25 +++++++ .../dict/dictType/dto/find-dictType.dto.ts | 13 ++++ .../dict/dictType/dto/update-dictType.dto.ts | 8 +++ .../dict/dictType/entities/dictType.entity.ts | 40 +++++++++++ src/system/dict/dictType/index.ts | 4 ++ src/system/dict/index.ts | 2 + src/system/menu/dto/update-menu.dto.ts | 1 - src/system/menu/entities/menu.entity.ts | 13 +++- .../permission/dto/create-permission.dto.ts | 22 ------ .../permission/dto/update-permission.dto.ts | 8 --- .../permission/entities/permission.entity.ts | 46 ------------- src/system/permission/index.ts | 8 --- .../permission/permission.controller.ts | 43 ------------ src/system/permission/permission.decorator.ts | 34 --------- src/system/permission/permission.guard.ts | 28 -------- src/system/permission/permission.module.ts | 21 ------ src/system/permission/permission.service.ts | 33 --------- src/system/role/dto/create-role.dto.ts | 21 +++++- src/system/role/dto/update-role.dto.ts | 7 +- src/system/role/entities/role.entity.ts | 22 +++--- src/system/role/role.service.ts | 8 --- src/system/user/entities/user.entity.ts | 6 +- src/system/user/user.service.ts | 6 +- 53 files changed, 549 insertions(+), 352 deletions(-) delete mode 100644 src/common/mail/mail.controller.ts rename src/database/entities/{base.ts => base.entity.ts} (100%) delete mode 100644 src/system/auth/jwt/index.ts delete mode 100644 src/system/auth/vo/logined-user.vo.ts create mode 100644 src/system/dict/data/dict.controller.ts create mode 100644 src/system/dict/data/dict.module.ts create mode 100644 src/system/dict/data/dict.service.ts create mode 100644 src/system/dict/data/dto/create-dict.dto.ts create mode 100644 src/system/dict/data/dto/find-dict.dto.ts create mode 100644 src/system/dict/data/dto/update-dict.dto.ts create mode 100644 src/system/dict/data/entities/dict.entity.ts create mode 100644 src/system/dict/data/index.ts create mode 100644 src/system/dict/dictType/dictType.controller.ts create mode 100644 src/system/dict/dictType/dictType.module.ts create mode 100644 src/system/dict/dictType/dictType.service.ts create mode 100644 src/system/dict/dictType/dto/create-dictType.dto.ts create mode 100644 src/system/dict/dictType/dto/find-dictType.dto.ts create mode 100644 src/system/dict/dictType/dto/update-dictType.dto.ts create mode 100644 src/system/dict/dictType/entities/dictType.entity.ts create mode 100644 src/system/dict/dictType/index.ts create mode 100644 src/system/dict/index.ts delete mode 100644 src/system/permission/dto/create-permission.dto.ts delete mode 100644 src/system/permission/dto/update-permission.dto.ts delete mode 100644 src/system/permission/entities/permission.entity.ts delete mode 100644 src/system/permission/index.ts delete mode 100644 src/system/permission/permission.controller.ts delete mode 100644 src/system/permission/permission.decorator.ts delete mode 100644 src/system/permission/permission.guard.ts delete mode 100644 src/system/permission/permission.module.ts delete mode 100644 src/system/permission/permission.service.ts diff --git a/content/data/db.sqlite b/content/data/db.sqlite index 44f31358a3d533c6a5bbb86bc36b52167401d71e..6276aa96398be40ee3dddcaaf74fccdc6ab2664a 100644 GIT binary patch delta 5585 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 delta 1184 zcmaKrU2GIp6vyv9v!C7Fxij6a-RT$GLO+($c6MjkwrhwOTQD@F)CbWRA|>n+lwF#- zHL1o}Y&R@M6U%7kL2Fh(j2bBHww*#-X`;p$12*x2R30=$L8=cJj4!-+X15d5#5j{P zx%YR^J?DSU+&h+Yjg7h9sTM~FA=}XGXdK$)OE%(R4gHbbNSlc=Y*X zJT+3LW;>ebuEKQ3fb2J7;{#~rXf8A>y~$m~-PdU0=AdBFZ)e~oDnzV|DEOijDbu`L z(i11)6DsVmn7C2OD2VG$!6hneL7D#hup^FM9>@~P1 zD)kESNzW0l_S+1+!d|OIXyhlAwT=B=?Z^xav0rA_qk)hdQ$n#w zr*=IL-E6e7!h(EjvIu)KRH!+^!Uc`w-_>Rs6s3pgV zTg354*_ZaGtpns1M?90*h9B_A^am|#mBAoA)tVkWbS%E{@@<@HH@*f*HZEmDprzsH z;fBD`R62enju*1i2$9{4qqgFRr3W#-1C8h>Zc_ { + get{{upcaseName name}}(@Param('id') id: number): Promise<{{upcaseName name}}> { return this.{{lowcaseName name}}Service.findOne(id); } @Patch(':id') @ApiOperation({ description: '更新{{cnName}}', operationId: 'set{{upcaseName name}}' }) - update{{upcaseName name}}(id: number, @Body() update{{upcaseName name}}Dto: Update{{upcaseName name}}Dto) { + update{{upcaseName name}}(@Param('id') id: number, @Body() update{{upcaseName name}}Dto: Update{{upcaseName name}}Dto) { return this.{{lowcaseName name}}Service.update(+id, update{{upcaseName name}}Dto); } @Delete(':id') @ApiOperation({ description: '删除{{cnName}}', operationId: 'del{{upcaseName name}}' }) - del{{upcaseName name}}(id: number) { + del{{upcaseName name}}(@Param('id') id: number) { return this.{{lowcaseName name}}Service.remove(+id); } } diff --git a/src/app.module.ts b/src/app.module.ts index 9eabc58..57b5995 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -10,12 +10,12 @@ import { LoggerModule } from '@/monitor/logger'; import { CacheModule } from '@/storage/cache'; import { UploadModule } from '@/storage/file'; import { AuthModule } from '@/system/auth'; -import { PermissionModule } from '@/system/permission'; import { RoleModule } from '@/system/role'; import { UserModule } from '@/system/user'; import { ScanModule } from '@/utils/scan.module'; import { Module } from '@nestjs/common'; import { MenuModule } from './system/menu'; +import { DictModule, DictTypeModule } from './system/dict'; @Module({ imports: [ @@ -76,10 +76,6 @@ import { MenuModule } from './system/menu'; * 角色模块 */ RoleModule, - /** - * 权限模块 - */ - PermissionModule, /** * 上传模块 @@ -91,6 +87,8 @@ import { MenuModule } from './system/menu'; PostModule, ContentModule, MenuModule, + DictTypeModule, + DictModule, ], }) export class AppModule {} diff --git a/src/common/mail/index.ts b/src/common/mail/index.ts index 91fd6cb..a70a91e 100644 --- a/src/common/mail/index.ts +++ b/src/common/mail/index.ts @@ -1,3 +1,2 @@ -export * from './mail.controller'; export * from './mail.module'; export * from './mail.service'; diff --git a/src/common/mail/mail.controller.ts b/src/common/mail/mail.controller.ts deleted file mode 100644 index 51f7f83..0000000 --- a/src/common/mail/mail.controller.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Controller } from '@nestjs/common'; -import { MailService } from './mail.service'; - -@Controller('mail') -export class MailController { - constructor(private readonly mailService: MailService) {} -} diff --git a/src/common/mail/mail.module.ts b/src/common/mail/mail.module.ts index fdab9e9..ebbfa5b 100644 --- a/src/common/mail/mail.module.ts +++ b/src/common/mail/mail.module.ts @@ -1,9 +1,9 @@ import { Module } from '@nestjs/common'; import { MailService } from './mail.service'; -import { MailController } from './mail.controller'; @Module({ - controllers: [MailController], + controllers: [], providers: [MailService], + exports: [MailService], }) export class MailModule {} diff --git a/src/database/entities/base.ts b/src/database/entities/base.entity.ts similarity index 100% rename from src/database/entities/base.ts rename to src/database/entities/base.entity.ts diff --git a/src/database/index.ts b/src/database/index.ts index f345e6e..eb60697 100644 --- a/src/database/index.ts +++ b/src/database/index.ts @@ -1,3 +1,3 @@ export * from './datasource'; -export * from './entities/base'; +export * from './entities/base.entity'; export * from './database.module'; diff --git a/src/monitor/logger/logger.interceptor.ts b/src/monitor/logger/logger.interceptor.ts index 608e21d..968bcba 100644 --- a/src/monitor/logger/logger.interceptor.ts +++ b/src/monitor/logger/logger.interceptor.ts @@ -15,11 +15,11 @@ export class LoggerInterceptor implements NestInterceptor { tap({ next: () => { const ms = Date.now() - now; - this.logger.log(`[Suuccess] ${method} ${url}(${ms} ms) +1`, scope); + this.logger.log(`[成功] ${method} ${url}(${ms} ms) +1`, scope); }, error: () => { const ms = Date.now() - now; - this.logger.log(`[Fail] ${method} ${url}(${ms} ms) +1`, scope); + this.logger.error(`[失败] ${method} ${url}(${ms} ms) +1`, scope); }, }), ); diff --git a/src/storage/file/entities/file.entity.ts b/src/storage/file/entities/file.entity.ts index 4c87464..f170eb7 100644 --- a/src/storage/file/entities/file.entity.ts +++ b/src/storage/file/entities/file.entity.ts @@ -2,14 +2,21 @@ import { BaseEntity } from '@/database'; import { Column, Entity } from 'typeorm'; @Entity({ orderBy: { id: 'DESC' } }) -export class Upload extends BaseEntity { +export class File extends BaseEntity { /** * 文件名 - * @example "xxx.jpg" + * @example "头像.jpg" */ @Column({ comment: '文件名' }) name: string; + /** + * 描述 + * @example '一段很长的描述' + */ + @Column({ comment: '描述' }) + description: string; + /** * 文件大小 * @example 1024 diff --git a/src/storage/file/file.controller.ts b/src/storage/file/file.controller.ts index 3989c18..66469f6 100644 --- a/src/storage/file/file.controller.ts +++ b/src/storage/file/file.controller.ts @@ -34,9 +34,9 @@ export class UploadController { } @Get('hash/:hash') - @ApiOperation({ description: '查询文件是否已存在', operationId: 'getFileByHash' }) - isHashExists(@Param('hash') hash: string) { - return this.uploadService.isHashExists(hash); + @ApiOperation({ description: '根据哈希查询', operationId: 'getFileByHash' }) + getByHash(@Param('hash') hash: string) { + return this.uploadService.getByHash(hash); } @Patch(':id') diff --git a/src/storage/file/file.module.ts b/src/storage/file/file.module.ts index 5327548..b99df31 100644 --- a/src/storage/file/file.module.ts +++ b/src/storage/file/file.module.ts @@ -5,7 +5,7 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { existsSync, mkdirSync } from 'fs'; import { diskStorage } from 'multer'; import { extname, join } from 'path'; -import { Upload } from './entities/file.entity'; +import { File } from './entities/file.entity'; import { UploadController } from './file.controller'; import { UploadService } from './file.service'; import { dayjs } from '@/libraries'; @@ -31,7 +31,7 @@ const MulteredModule = MulterModule.registerAsync({ }); @Module({ - imports: [TypeOrmModule.forFeature([Upload]), MulteredModule], + imports: [TypeOrmModule.forFeature([File]), MulteredModule], controllers: [UploadController], providers: [UploadService], }) diff --git a/src/storage/file/file.service.ts b/src/storage/file/file.service.ts index d06850e..65c71de 100644 --- a/src/storage/file/file.service.ts +++ b/src/storage/file/file.service.ts @@ -3,41 +3,42 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { extname, relative, sep } from 'path'; import { Repository } from 'typeorm'; -import { Upload } from './entities/file.entity'; +import { File } from './entities/file.entity'; @Injectable() export class UploadService extends BaseService { - constructor(@InjectRepository(Upload) private readonly uploadRepository: Repository) { + constructor(@InjectRepository(File) private readonly repository: Repository) { super(); } /** * 保存文件信息 - * @param file 文件信息 + * @param uploadFile 文件信息 * @returns */ - async create(file: Express.Multer.File) { - const path = relative(this.config.uploadDir, file.path).split(sep).join('/'); - const uploadPrefix = this.config.uploadPrefix; - const uploadUrl = `${uploadPrefix}/${path}`; - const upload = this.uploadRepository.create({ - name: file.originalname, - mimetype: file.mimetype, - size: file.size, - hash: file.filename, - path: uploadUrl, - extension: extname(file.originalname), + async create(uploadFile: Express.Multer.File) { + const { originalname: name, mimetype, size, path: hash } = uploadFile; + const relativePath = relative(this.config.uploadDir, uploadFile.path).split(sep).join('/'); + const path = `${this.config.uploadPrefix}/${relativePath}`; + const extension = extname(uploadFile.originalname); + const file = this.repository.create({ + name, + mimetype, + size, + hash, + path, + extension, }); - await this.uploadRepository.save(upload); - return upload; + await this.repository.save(file); + return file.id; } findAll() { - return this.uploadRepository.findAndCount(); + return this.repository.findAndCount(); } findOne(id: number) { - return this.uploadRepository.findOne({ where: { id } }); + return this.repository.findOne({ where: { id } }); } update() { @@ -49,12 +50,11 @@ export class UploadService extends BaseService { * @param hash 哈希 * @returns */ - async isHashExists(hash: string) { - const count = await this.uploadRepository.count({ where: { hash } }); - return count > 0; + async getByHash(hash: string) { + return this.repository.findOneBy({ hash }); } remove(id: number) { - return this.uploadRepository.softDelete(id); + return this.repository.softDelete(id); } } diff --git a/src/system/auth/auth.controller.ts b/src/system/auth/auth.controller.ts index 284a267..1fc4269 100644 --- a/src/system/auth/auth.controller.ts +++ b/src/system/auth/auth.controller.ts @@ -11,7 +11,7 @@ import { import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { AuthService } from './auth.service'; import { AuthUserDto } from './dto/auth-user.dto'; -import { Public } from './jwt'; +import { Public } from './jwt/jwt-decorator'; import { LoginLogInterceptor } from '@/monitor/log'; import { Request } from 'express'; diff --git a/src/system/auth/auth.module.ts b/src/system/auth/auth.module.ts index bf3ef4e..3437fa2 100644 --- a/src/system/auth/auth.module.ts +++ b/src/system/auth/auth.module.ts @@ -2,9 +2,10 @@ import { Module } from '@nestjs/common'; import { UserModule } from '../user'; import { AuthController } from './auth.controller'; import { AuthService } from './auth.service'; -import { JwtGuard, JwtModule } from './jwt'; +import { JwtModule } from './jwt/jwt-module'; import { APP_GUARD } from '@nestjs/core'; import { LogModule } from '@/monitor/log'; +import { JwtGuard } from './jwt/jwt-guard'; @Module({ imports: [UserModule, JwtModule, LogModule], diff --git a/src/system/auth/index.ts b/src/system/auth/index.ts index 3fb27d6..9e4be1e 100644 --- a/src/system/auth/index.ts +++ b/src/system/auth/index.ts @@ -1,5 +1,7 @@ export * from './auth.controller'; export * from './auth.module'; export * from './auth.service'; -export * from './jwt'; +export * from './jwt/jwt-decorator'; +export * from './jwt/jwt-guard'; +export * from './jwt/jwt-module'; export * from './dto/auth-user.dto'; diff --git a/src/system/auth/jwt/index.ts b/src/system/auth/jwt/index.ts deleted file mode 100644 index 5b9517e..0000000 --- a/src/system/auth/jwt/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './jwt-decorator'; -export * from './jwt-guard'; -export * from './jwt-module'; diff --git a/src/system/auth/vo/logined-user.vo.ts b/src/system/auth/vo/logined-user.vo.ts deleted file mode 100644 index b168eb4..0000000 --- a/src/system/auth/vo/logined-user.vo.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { User } from '@/system/user'; -import { OmitType } from '@nestjs/swagger'; - -export class LoginedUserVo extends OmitType(User, ['password', 'id'] as const) { - /** - * 用户ID - */ - id: number; - /** - * 访问令牌 - * @example 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjIsInVzZXJuYW1lIjoianVldGFuIiwiaWF0IjoxNjkxMTM5MjI3LCJleHAiOjE2OTExOTkyMjd9.6z7f-xfsHABbsyg401o2boKeqNQ1epPDYfEdavIcfYc' - */ - token: string; -} diff --git a/src/system/dict/data/dict.controller.ts b/src/system/dict/data/dict.controller.ts new file mode 100644 index 0000000..9b84fba --- /dev/null +++ b/src/system/dict/data/dict.controller.ts @@ -0,0 +1,49 @@ +import { BaseController } from '@/common/base'; +import { Respond, RespondType } from '@/middlewares/response'; +import { Body, Controller, Delete, Get, Param, Patch, Post, Query } from '@nestjs/common'; +import { ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger'; +import { CreateDictDto } from './dto/create-dict.dto'; +import { FindDictDto } from './dto/find-dict.dto'; +import { UpdateDictDto } from './dto/update-dict.dto'; +import { Dict } from './entities/dict.entity'; +import { DictService } from './dict.service'; + +@ApiTags('dict') +@Controller('dicts') +export class DictController extends BaseController { + constructor(private dictService: DictService) { + super(); + } + + @Post() + @ApiOperation({ description: '新增字典', operationId: 'addDict' }) + addDict(@Body() createDictDto: CreateDictDto) { + return this.dictService.create(createDictDto); + } + + @Get() + @Respond(RespondType.PAGINATION) + @ApiOkResponse({ isArray: true, type: Dict }) + @ApiOperation({ description: '查询字典', operationId: 'getDicts' }) + getDicts(@Query() query: FindDictDto) { + return this.dictService.findMany(query); + } + + @Get(':id') + @ApiOperation({ description: '获取字典', operationId: 'getDict' }) + getDict(@Param('id') id: number): Promise { + return this.dictService.findOne(id); + } + + @Patch(':id') + @ApiOperation({ description: '更新字典', operationId: 'setDict' }) + updateDict(@Param('id') id: number, @Body() updateDictDto: UpdateDictDto) { + return this.dictService.update(+id, updateDictDto); + } + + @Delete(':id') + @ApiOperation({ description: '删除字典', operationId: 'delDict' }) + delDict(@Param('id') id: number) { + return this.dictService.remove(+id); + } +} diff --git a/src/system/dict/data/dict.module.ts b/src/system/dict/data/dict.module.ts new file mode 100644 index 0000000..5ed2cf5 --- /dev/null +++ b/src/system/dict/data/dict.module.ts @@ -0,0 +1,14 @@ +import { Module, forwardRef } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { Dict } from './entities/dict.entity'; +import { DictController } from './dict.controller'; +import { DictService } from './dict.service'; +import { DictTypeModule } from '../dictType'; + +@Module({ + imports: [TypeOrmModule.forFeature([Dict]), forwardRef(() => DictTypeModule)], + controllers: [DictController], + providers: [DictService], + exports: [DictService], +}) +export class DictModule {} diff --git a/src/system/dict/data/dict.service.ts b/src/system/dict/data/dict.service.ts new file mode 100644 index 0000000..5df3234 --- /dev/null +++ b/src/system/dict/data/dict.service.ts @@ -0,0 +1,65 @@ +import { BaseService } from '@/common/base'; +import { Inject, Injectable, NotFoundException, forwardRef } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Like, Repository } from 'typeorm'; +import { CreateDictDto } from './dto/create-dict.dto'; +import { FindDictDto } from './dto/find-dict.dto'; +import { UpdateDictDto } from './dto/update-dict.dto'; +import { Dict } from './entities/dict.entity'; +import { DictTypeService } from '../dictType'; + +@Injectable() +export class DictService extends BaseService { + constructor( + @InjectRepository(Dict) private dictRepository: Repository, + @Inject(forwardRef(() => DictTypeService)) private dictTypeService: DictTypeService, + ) { + super(); + } + + /** + * 新增字典 + */ + async create(createDictDto: CreateDictDto) { + const dict = this.dictRepository.create(createDictDto); + const { typeId } = createDictDto; + const type = await this.dictTypeService.findOne(typeId); + if (!type) { + throw new NotFoundException('字典类型不存在'); + } + dict.type = type; + await this.dictRepository.save(dict); + return dict.id; + } + + /** + * 条件/分页查询 + */ + async findMany(findDictdto: FindDictDto) { + const { page, size, typeId } = findDictdto; + const { skip, take } = this.formatPagination(page, size, true); + return this.dictRepository.findAndCount({ skip, take, where: { typeId } }); + } + + /** + * 根据ID查询 + */ + findOne(idOrOptions: number | Partial) { + const where = typeof idOrOptions === 'number' ? { id: idOrOptions } : (idOrOptions as any); + return this.dictRepository.findOne({ where }); + } + + /** + * 根据ID更新 + */ + update(id: number, updateDictDto: UpdateDictDto) { + return this.dictRepository.update(id, updateDictDto); + } + + /** + * 根据ID删除(软删除) + */ + remove(id: number) { + return this.dictRepository.softDelete(id); + } +} diff --git a/src/system/dict/data/dto/create-dict.dto.ts b/src/system/dict/data/dto/create-dict.dto.ts new file mode 100644 index 0000000..ca51d29 --- /dev/null +++ b/src/system/dict/data/dto/create-dict.dto.ts @@ -0,0 +1,32 @@ +import { IsBoolean, IsNumber, IsOptional, IsString } from 'class-validator'; + +export class CreateDictDto { + /** + * 字典类型 + * @example 1 + */ + @IsNumber() + typeId: number; + + /** + * 类型名称 + * @example '性别' + */ + @IsString() + name: string; + + /** + * 标识 + * @example 'gender' + */ + @IsString() + code: string; + + /** + * 描述 + * @examle '一段很长的描述' + */ + @IsOptional() + @IsString() + description: string; +} diff --git a/src/system/dict/data/dto/find-dict.dto.ts b/src/system/dict/data/dto/find-dict.dto.ts new file mode 100644 index 0000000..39b0266 --- /dev/null +++ b/src/system/dict/data/dto/find-dict.dto.ts @@ -0,0 +1,14 @@ +import { PaginationDto } from '@/middlewares/response'; +import { IntersectionType } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; +import { IsInt, IsNumber, IsOptional, IsString } from 'class-validator'; + +export class FindDictDto extends IntersectionType(PaginationDto) { + /** + * 类型ID + * @example 1 + */ + @IsInt() + @Transform(({ value }) => Number(value)) + typeId: number; +} diff --git a/src/system/dict/data/dto/update-dict.dto.ts b/src/system/dict/data/dto/update-dict.dto.ts new file mode 100644 index 0000000..4d5d3be --- /dev/null +++ b/src/system/dict/data/dto/update-dict.dto.ts @@ -0,0 +1,8 @@ +import { PartialType } from '@nestjs/swagger'; +import { IsNumber } from 'class-validator'; +import { CreateDictDto } from './create-dict.dto'; + +export class UpdateDictDto extends PartialType(CreateDictDto) { + @IsNumber() + id: number; +} diff --git a/src/system/dict/data/entities/dict.entity.ts b/src/system/dict/data/entities/dict.entity.ts new file mode 100644 index 0000000..e510a36 --- /dev/null +++ b/src/system/dict/data/entities/dict.entity.ts @@ -0,0 +1,48 @@ +import { BaseEntity } from '@/database'; +import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm'; +import { DictType } from '../../dictType'; + +@Entity({ orderBy: { id: 'DESC' } }) +export class Dict extends BaseEntity { + /** + * 类型名称 + * @example '性别' + */ + @Column({ comment: '名称' }) + name: string; + + /** + * 标识 + * @example 'gender' + */ + @Column({ comment: '标识' }) + code: string; + + /** + * 状态 + * @example true + */ + @Column({ comment: '状态', default: true }) + status: boolean; + + /** + * 描述 + * @examle '一段很长的描述' + */ + @Column({ comment: '描述' }) + description: string; + + /** + * 字段类型 + */ + @ManyToOne(() => DictType, (dictType) => dictType.dicts) + @JoinColumn() + type: DictType; + + /** + * 类型ID + * @example 1 + */ + @Column() + typeId: number; +} diff --git a/src/system/dict/data/index.ts b/src/system/dict/data/index.ts new file mode 100644 index 0000000..c1dd700 --- /dev/null +++ b/src/system/dict/data/index.ts @@ -0,0 +1,4 @@ +export * from './entities/dict.entity'; +export * from './dict.controller'; +export * from './dict.module'; +export * from './dict.service'; diff --git a/src/system/dict/dictType/dictType.controller.ts b/src/system/dict/dictType/dictType.controller.ts new file mode 100644 index 0000000..48122ec --- /dev/null +++ b/src/system/dict/dictType/dictType.controller.ts @@ -0,0 +1,49 @@ +import { BaseController } from '@/common/base'; +import { Respond, RespondType } from '@/middlewares/response'; +import { Body, Controller, Delete, Get, Param, Patch, Post, Query } from '@nestjs/common'; +import { ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger'; +import { CreateDictTypeDto } from './dto/create-dictType.dto'; +import { FindDictTypeDto } from './dto/find-dictType.dto'; +import { UpdateDictTypeDto } from './dto/update-dictType.dto'; +import { DictType } from './entities/dictType.entity'; +import { DictTypeService } from './dictType.service'; + +@ApiTags('dictType') +@Controller('dictTypes') +export class DictTypeController extends BaseController { + constructor(private dictTypeService: DictTypeService) { + super(); + } + + @Post() + @ApiOperation({ description: '新增字典类型', operationId: 'addDictType' }) + addDictType(@Body() createDictTypeDto: CreateDictTypeDto) { + return this.dictTypeService.create(createDictTypeDto); + } + + @Get() + @Respond(RespondType.PAGINATION) + @ApiOkResponse({ isArray: true, type: DictType }) + @ApiOperation({ description: '查询字典类型', operationId: 'getDictTypes' }) + getDictTypes(@Query() query: FindDictTypeDto) { + return this.dictTypeService.findMany(query); + } + + @Get(':id') + @ApiOperation({ description: '获取字典类型', operationId: 'getDictType' }) + getDictType(@Param('id') id: number): Promise { + return this.dictTypeService.findOne(id); + } + + @Patch(':id') + @ApiOperation({ description: '更新字典类型', operationId: 'setDictType' }) + updateDictType(@Param('id') id: number, @Body() updateDictTypeDto: UpdateDictTypeDto) { + return this.dictTypeService.update(+id, updateDictTypeDto); + } + + @Delete(':id') + @ApiOperation({ description: '删除字典类型', operationId: 'delDictType' }) + delDictType(@Param('id') id: number) { + return this.dictTypeService.remove(+id); + } +} diff --git a/src/system/dict/dictType/dictType.module.ts b/src/system/dict/dictType/dictType.module.ts new file mode 100644 index 0000000..7111189 --- /dev/null +++ b/src/system/dict/dictType/dictType.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { DictType } from './entities/dictType.entity'; +import { DictTypeController } from './dictType.controller'; +import { DictTypeService } from './dictType.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([DictType])], + controllers: [DictTypeController], + providers: [DictTypeService], + exports: [DictTypeService], +}) +export class DictTypeModule {} diff --git a/src/system/dict/dictType/dictType.service.ts b/src/system/dict/dictType/dictType.service.ts new file mode 100644 index 0000000..c0695ed --- /dev/null +++ b/src/system/dict/dictType/dictType.service.ts @@ -0,0 +1,55 @@ +import { BaseService } from '@/common/base'; +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Like, Repository } from 'typeorm'; +import { CreateDictTypeDto } from './dto/create-dictType.dto'; +import { FindDictTypeDto } from './dto/find-dictType.dto'; +import { UpdateDictTypeDto } from './dto/update-dictType.dto'; +import { DictType } from './entities/dictType.entity'; + +@Injectable() +export class DictTypeService extends BaseService { + constructor(@InjectRepository(DictType) private dictTypeRepository: Repository) { + super(); + } + + /** + * 新增字典类型 + */ + async create(createDictTypeDto: CreateDictTypeDto) { + const dictType = this.dictTypeRepository.create(createDictTypeDto); + await this.dictTypeRepository.save(dictType); + return dictType.id; + } + + /** + * 条件/分页查询 + */ + async findMany(findDictTypedto: FindDictTypeDto) { + const { page, size } = findDictTypedto; + const { skip, take } = this.formatPagination(page, size, true); + return this.dictTypeRepository.findAndCount({ skip, take }); + } + + /** + * 根据ID查询 + */ + findOne(idOrOptions: number | Partial) { + const where = typeof idOrOptions === 'number' ? { id: idOrOptions } : (idOrOptions as any); + return this.dictTypeRepository.findOne({ where }); + } + + /** + * 根据ID更新 + */ + update(id: number, updateDictTypeDto: UpdateDictTypeDto) { + return this.dictTypeRepository.update(id, updateDictTypeDto); + } + + /** + * 根据ID删除(软删除) + */ + remove(id: number) { + return this.dictTypeRepository.softDelete(id); + } +} diff --git a/src/system/dict/dictType/dto/create-dictType.dto.ts b/src/system/dict/dictType/dto/create-dictType.dto.ts new file mode 100644 index 0000000..7fa38ec --- /dev/null +++ b/src/system/dict/dictType/dto/create-dictType.dto.ts @@ -0,0 +1,25 @@ +import { IsOptional, IsString } from 'class-validator'; + +export class CreateDictTypeDto { + /** + * 类型名称 + * @example '性别' + */ + @IsString() + name: string; + + /** + * 标识 + * @example 'gender' + */ + @IsString() + code: string; + + /** + * 描述 + * @examle '一段很长的描述' + */ + @IsOptional() + @IsString() + description: string; +} diff --git a/src/system/dict/dictType/dto/find-dictType.dto.ts b/src/system/dict/dictType/dto/find-dictType.dto.ts new file mode 100644 index 0000000..560b410 --- /dev/null +++ b/src/system/dict/dictType/dto/find-dictType.dto.ts @@ -0,0 +1,13 @@ +import { PaginationDto } from '@/middlewares/response'; +import { IntersectionType } from '@nestjs/swagger'; +import { IsOptional, IsString } from 'class-validator'; + +export class FindDictTypeDto extends IntersectionType(PaginationDto) { + /** + * 字段描述(Swagger用途) + * @example '示例值' + */ + @IsOptional() + @IsString() + demo?: string; +} diff --git a/src/system/dict/dictType/dto/update-dictType.dto.ts b/src/system/dict/dictType/dto/update-dictType.dto.ts new file mode 100644 index 0000000..cdfd716 --- /dev/null +++ b/src/system/dict/dictType/dto/update-dictType.dto.ts @@ -0,0 +1,8 @@ +import { PartialType } from '@nestjs/swagger'; +import { IsNumber } from 'class-validator'; +import { CreateDictTypeDto } from './create-dictType.dto'; + +export class UpdateDictTypeDto extends PartialType(CreateDictTypeDto) { + @IsNumber() + id: number; +} diff --git a/src/system/dict/dictType/entities/dictType.entity.ts b/src/system/dict/dictType/entities/dictType.entity.ts new file mode 100644 index 0000000..2885a72 --- /dev/null +++ b/src/system/dict/dictType/entities/dictType.entity.ts @@ -0,0 +1,40 @@ +import { BaseEntity } from '@/database'; +import { Column, Entity, OneToMany } from 'typeorm'; +import { Dict } from '../../data'; + +@Entity({ orderBy: { id: 'DESC' } }) +export class DictType extends BaseEntity { + /** + * 类型名称 + * @example '性别' + */ + @Column({ comment: '名称' }) + name: string; + + /** + * 标识 + * @example 'gender' + */ + @Column({ comment: '标识' }) + code: string; + + /** + * 状态 + * @example true + */ + @Column({ comment: '状态', default: true }) + status: boolean; + + /** + * 描述 + * @examle '一段很长的描述' + */ + @Column({ comment: '描述' }) + description: string; + + /** + * 字典数组 + */ + @OneToMany(() => Dict, (dict) => dict.type) + dicts: Dict[]; +} diff --git a/src/system/dict/dictType/index.ts b/src/system/dict/dictType/index.ts new file mode 100644 index 0000000..7f07843 --- /dev/null +++ b/src/system/dict/dictType/index.ts @@ -0,0 +1,4 @@ +export * from './entities/dictType.entity'; +export * from './dictType.controller'; +export * from './dictType.module'; +export * from './dictType.service'; diff --git a/src/system/dict/index.ts b/src/system/dict/index.ts new file mode 100644 index 0000000..8fbb260 --- /dev/null +++ b/src/system/dict/index.ts @@ -0,0 +1,2 @@ +export * from './dictType'; +export * from './data'; diff --git a/src/system/menu/dto/update-menu.dto.ts b/src/system/menu/dto/update-menu.dto.ts index ec2def7..6bea590 100644 --- a/src/system/menu/dto/update-menu.dto.ts +++ b/src/system/menu/dto/update-menu.dto.ts @@ -1,5 +1,4 @@ import { PartialType } from '@nestjs/swagger'; -import { IsNumber } from 'class-validator'; import { CreateMenuDto } from './create-menu.dto'; export class UpdateMenuDto extends PartialType(CreateMenuDto) {} diff --git a/src/system/menu/entities/menu.entity.ts b/src/system/menu/entities/menu.entity.ts index c56e2aa..73a85fb 100644 --- a/src/system/menu/entities/menu.entity.ts +++ b/src/system/menu/entities/menu.entity.ts @@ -42,17 +42,28 @@ export class Menu extends BaseEntity { @Column({ comment: '类型(1: 目录, 2: 页面, 3: 按钮)' }) type: number; + /** + * 父级菜单 + */ @ApiHideProperty() @TreeParent() parent: Menu; + /** + * 父级ID + */ @Column({ comment: '父级ID', nullable: true }) parentId: number; - @ApiHideProperty() + /** + * 子项数组 + */ @TreeChildren() children: Menu[]; + /** + * 关联角色 + */ @ApiHideProperty() @ManyToMany(() => Role, (role) => role.menus) roles: Role[]; diff --git a/src/system/permission/dto/create-permission.dto.ts b/src/system/permission/dto/create-permission.dto.ts deleted file mode 100644 index 21bc64b..0000000 --- a/src/system/permission/dto/create-permission.dto.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { IsOptional, IsString } from 'class-validator'; - -export class CreatePermissionDto { - /** - * 权限名称 - * @example 权限名称 - */ - @IsString() - name: string; - /** - * 权限标识 - * @example permission:permission - */ - @IsString() - slug: string; - /** - * 权限描述 - */ - @IsOptional() - @IsString() - description?: string; -} diff --git a/src/system/permission/dto/update-permission.dto.ts b/src/system/permission/dto/update-permission.dto.ts deleted file mode 100644 index e483e4e..0000000 --- a/src/system/permission/dto/update-permission.dto.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { PartialType } from '@nestjs/swagger'; -import { IsNumber } from 'class-validator'; -import { CreatePermissionDto } from './create-permission.dto'; - -export class UpdatePermissionDto extends PartialType(CreatePermissionDto) { - @IsNumber() - id: number; -} diff --git a/src/system/permission/entities/permission.entity.ts b/src/system/permission/entities/permission.entity.ts deleted file mode 100644 index 60a4656..0000000 --- a/src/system/permission/entities/permission.entity.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { BaseEntity } from '@/database'; -import { Role } from '@/system/role/entities/role.entity'; -import { Column, Entity, ManyToMany } from 'typeorm'; - -enum PermissionType { - Menu = 'menu', - Api = 'api', -} - -@Entity({ orderBy: { id: 'DESC' } }) -export class Permission extends BaseEntity { - /** - * 权限名称 - * @example '文章列表' - */ - @Column({ comment: '权限名称' }) - name: string; - - /** - * 权限标识 - * @example 'post:list' - */ - @Column({ comment: '权限标识' }) - slug: string; - - /** - * 权限类型 - * @example 'menu' - */ - @Column({ nullable: true }) - type: PermissionType; - - /** - * 权限描述 - * @example '文章列表' - */ - @Column({ comment: '权限描述', nullable: true }) - description: string; - - /** - * 权限角色 - * @example {} - */ - @ManyToMany(() => Role, (role) => role.permissions) - roles: Role[]; -} diff --git a/src/system/permission/index.ts b/src/system/permission/index.ts deleted file mode 100644 index da68c36..0000000 --- a/src/system/permission/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -export * from './dto/create-permission.dto'; -export * from './dto/update-permission.dto'; -export * from './entities/permission.entity'; -export * from './permission.controller'; -export * from './permission.module'; -export * from './permission.service'; -export * from './permission.decorator'; -export * from './permission.guard'; diff --git a/src/system/permission/permission.controller.ts b/src/system/permission/permission.controller.ts deleted file mode 100644 index 53f0659..0000000 --- a/src/system/permission/permission.controller.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Respond, RespondType } from '@/middlewares/response'; -import { Body, Controller, Delete, Get, Param, Patch, Post } from '@nestjs/common'; -import { ApiOperation, ApiTags } from '@nestjs/swagger'; -import { CreatePermissionDto } from './dto/create-permission.dto'; -import { UpdatePermissionDto } from './dto/update-permission.dto'; -import { PermissionService } from './permission.service'; - -@ApiTags('permission') -@Controller('permissions') -export class PermissionController { - constructor(private readonly permissionService: PermissionService) {} - - @Post() - @ApiOperation({ description: '创建权限', operationId: 'addPermission' }) - create(@Body() createPermissionDto: CreatePermissionDto) { - return this.permissionService.create(createPermissionDto); - } - - @Get() - @Respond(RespondType.PAGINATION) - @ApiOperation({ description: '批量查询权限', operationId: 'getPermissions' }) - findAll() { - return this.permissionService.findAll(); - } - - @Get(':id') - @ApiOperation({ description: '查询权限', operationId: 'getPermission' }) - findOne(@Param('id') id: string) { - return this.permissionService.findOne(+id); - } - - @Patch(':id') - @ApiOperation({ description: '更新权限', operationId: 'setPermission' }) - update(@Param('id') id: string, @Body() updatePermissionDto: UpdatePermissionDto) { - return this.permissionService.update(+id, updatePermissionDto); - } - - @Delete(':id') - @ApiOperation({ description: '删除权限', operationId: 'delPermission' }) - remove(@Param('id') id: string) { - return this.permissionService.remove(+id); - } -} diff --git a/src/system/permission/permission.decorator.ts b/src/system/permission/permission.decorator.ts deleted file mode 100644 index ea15822..0000000 --- a/src/system/permission/permission.decorator.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { SetMetadata } from '@nestjs/common'; - -export const PERMISSION_KEY = 'APP:PERMISSION'; - -/** - * 权限枚举 - */ -export const enum PermissionEnum { - /** - * 新增 - */ - CREATE = 'create', - /** - * 查询 - */ - READ = 'read', - /** - * 更新 - */ - UPDATE = 'update', - /** - * 删除 - */ - DELETE = 'delete', -} - -/** - * 指定所需的权限 - * @param permissions - * @returns - */ -export function PermissionWith(...permissions: string[]) { - return SetMetadata(PERMISSION_KEY, permissions); -} diff --git a/src/system/permission/permission.guard.ts b/src/system/permission/permission.guard.ts deleted file mode 100644 index 856a214..0000000 --- a/src/system/permission/permission.guard.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { CanActivate, ExecutionContext, Inject, Injectable, UnauthorizedException, forwardRef } from '@nestjs/common'; -import { Reflector } from '@nestjs/core'; -import { PERMISSION_KEY } from './permission.decorator'; -import { UserService } from '@/system/user'; - -@Injectable() -export class PermissionGuard implements CanActivate { - constructor(private reflector: Reflector, @Inject(forwardRef(() => UserService)) private userService: UserService) {} - - async canActivate(context: ExecutionContext): Promise { - const controller = context.getClass(); - const handler = context.getHandler(); - const permissions = this.reflector.getAllAndMerge(PERMISSION_KEY, [controller, handler]); - if (!permissions || !permissions.length) { - return true; - } - const user = context.switchToHttp().getRequest().user; - if (!user) { - throw new UnauthorizedException('用户未登录'); - } - const userPermissions = await this.userService.findUserPermissions(user.id); - const hasPermission = permissions.every((permission) => userPermissions.includes(permission)); - if (!hasPermission) { - throw new UnauthorizedException('权限不足'); - } - return true; - } -} diff --git a/src/system/permission/permission.module.ts b/src/system/permission/permission.module.ts deleted file mode 100644 index e9af880..0000000 --- a/src/system/permission/permission.module.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Module, forwardRef } from '@nestjs/common'; -import { PermissionService } from './permission.service'; -import { PermissionController } from './permission.controller'; -import { TypeOrmModule } from '@nestjs/typeorm'; -import { Permission } from './entities/permission.entity'; -import { APP_GUARD } from '@nestjs/core'; -import { PermissionGuard } from './permission.guard'; -import { UserModule } from '../user'; - -@Module({ - imports: [TypeOrmModule.forFeature([Permission]), forwardRef(() => UserModule)], - controllers: [PermissionController], - providers: [ - PermissionService, - { - provide: APP_GUARD, - useClass: PermissionGuard, - }, - ], -}) -export class PermissionModule {} diff --git a/src/system/permission/permission.service.ts b/src/system/permission/permission.service.ts deleted file mode 100644 index 362fa1c..0000000 --- a/src/system/permission/permission.service.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; -import { CreatePermissionDto } from './dto/create-permission.dto'; -import { UpdatePermissionDto } from './dto/update-permission.dto'; -import { Permission } from './entities/permission.entity'; - -@Injectable() -export class PermissionService { - constructor(@InjectRepository(Permission) private readonly permissionRepository: Repository) {} - - async create(createPermissionDto: CreatePermissionDto) { - const permission = this.permissionRepository.create(createPermissionDto); - await this.permissionRepository.save(permission); - return permission.id; - } - - findAll() { - return this.permissionRepository.findAndCount(); - } - - findOne(id: number) { - return `This action returns a #${id} permission`; - } - - update(id: number, updatePermissionDto: UpdatePermissionDto) { - return this.permissionRepository.update(id, updatePermissionDto); - } - - remove(id: number) { - return `This action removes a #${id} permission`; - } -} diff --git a/src/system/role/dto/create-role.dto.ts b/src/system/role/dto/create-role.dto.ts index 6b70ccf..bed72b3 100644 --- a/src/system/role/dto/create-role.dto.ts +++ b/src/system/role/dto/create-role.dto.ts @@ -1,18 +1,33 @@ -import { Permission } from '@/system/permission/entities/permission.entity'; import { IsInt, IsOptional, IsString } from 'class-validator'; export class CreateRoleDto { + /** + * 角色名称 + * @example '管理员' + */ @IsString() name: string; + /** + * 角色标识 + * @example 'admin' + */ @IsString() slug: string; - @IsString() + /** + * 角色描述 + * @example '一段很长的描述' + */ @IsOptional() + @IsString() description?: string; + /** + * 角色ID数组 + * @example [1] + */ @IsOptional() @IsInt({ each: true }) - permissions?: Permission[]; + menuIds: number[]; } diff --git a/src/system/role/dto/update-role.dto.ts b/src/system/role/dto/update-role.dto.ts index 8db879c..450134d 100644 --- a/src/system/role/dto/update-role.dto.ts +++ b/src/system/role/dto/update-role.dto.ts @@ -1,9 +1,4 @@ import { PartialType } from '@nestjs/swagger'; import { CreateRoleDto } from './create-role.dto'; -import { IsInt, IsOptional } from 'class-validator'; -export class UpdateRoleDto extends PartialType(CreateRoleDto) { - @IsOptional() - @IsInt({ each: true }) - permissionIds?: number[]; -} +export class UpdateRoleDto extends PartialType(CreateRoleDto) {} diff --git a/src/system/role/entities/role.entity.ts b/src/system/role/entities/role.entity.ts index ea0fa67..ab190ae 100644 --- a/src/system/role/entities/role.entity.ts +++ b/src/system/role/entities/role.entity.ts @@ -1,6 +1,5 @@ import { BaseEntity } from '@/database'; import { Menu } from '@/system/menu'; -import { Permission } from '@/system/permission/entities/permission.entity'; import { User } from '@/system/user'; import { ApiHideProperty } from '@nestjs/swagger'; import { Column, Entity, JoinTable, ManyToMany, RelationId } from 'typeorm'; @@ -28,20 +27,23 @@ export class Role extends BaseEntity { @Column({ comment: '角色描述', nullable: true }) description: string; + /** + * 关联用户 + */ @ApiHideProperty() @ManyToMany(() => User, (user) => user.roles) user: User; - @ApiHideProperty() - @JoinTable() - @ManyToMany(() => Permission, (permission) => permission.roles) - permissions: Permission[]; - - @ApiHideProperty() - @RelationId('permissions') - permissionIds: number[]; - + /** + * 关联菜单 + */ @ApiHideProperty() @ManyToMany(() => Menu, (menu) => menu.roles) menus: Menu[]; + + /** + * 菜单ID数组 + */ + @RelationId('menus') + menuIds: number[]; } diff --git a/src/system/role/role.service.ts b/src/system/role/role.service.ts index cbd39ab..3516d63 100644 --- a/src/system/role/role.service.ts +++ b/src/system/role/role.service.ts @@ -11,9 +11,6 @@ export class RoleService { async create(createRoleDto: CreateRoleDto) { const role = this.roleRepository.create(createRoleDto); - if (createRoleDto.permissions) { - role.permissions = createRoleDto.permissions.map((id) => ({ id })) as any; - } await this.roleRepository.save(role); return role.id; } @@ -31,11 +28,6 @@ export class RoleService { if (!role) { throw new NotFoundException('角色不存在'); } - if (updateRoleDto.permissionIds) { - const permissions = updateRoleDto.permissionIds.map((id) => ({ id })); - await this.roleRepository.save({ id, permissions }); - delete updateRoleDto.permissionIds; - } return this.roleRepository.update(id, updateRoleDto); } diff --git a/src/system/user/entities/user.entity.ts b/src/system/user/entities/user.entity.ts index 0f1dc99..f35a75e 100644 --- a/src/system/user/entities/user.entity.ts +++ b/src/system/user/entities/user.entity.ts @@ -60,7 +60,7 @@ export class User extends BaseEntity { email: string; /** - * 用户文章 + * 关联文章 */ @ApiHideProperty() @ManyToMany(() => Post, (post) => post.author) @@ -68,7 +68,7 @@ export class User extends BaseEntity { posts: Post[]; /** - * 用户角色 + * 关联角色 */ @ApiHideProperty() @ManyToMany(() => Role, (role) => role.user, { cascade: true }) @@ -76,7 +76,7 @@ export class User extends BaseEntity { roles: Role[]; /** - * 用户角色ID + * 角色ID数组 */ @RelationId('roles') roleIds: number[]; diff --git a/src/system/user/user.service.ts b/src/system/user/user.service.ts index 1fb6e1b..506e5b6 100644 --- a/src/system/user/user.service.ts +++ b/src/system/user/user.service.ts @@ -88,11 +88,11 @@ export class UserService extends BaseService { async findUserPermissions(id: number) { const user = await this.userRepository.findOne({ where: { id }, - relations: ['roles', 'roles.permissions'], + relations: ['roles'], }); if (user) { - const permissions = user.roles.flatMap((role) => role.permissions); - return [...new Set(permissions.map((i) => i.slug))]; + const permissions = user.roles.flatMap((role) => role.menuIds); + return [...new Set(permissions.map((i) => i))]; } return []; }