diff --git a/src/application/app.module.ts b/src/application/app.module.ts index 1d92cc6..67d796d 100644 --- a/src/application/app.module.ts +++ b/src/application/app.module.ts @@ -15,6 +15,7 @@ import { GlobalModule } from '@app/global.module'; import { CoreEnvModule } from './core-env/core-env.module'; import { CoreMenuModule } from './core-menu/core-menu.module'; import { AuthRoleModule } from './auth-role/auth-role.module'; +import { AuthDeptModule } from './auth-dept/auth-dept.module'; @Module({ imports: [ @@ -29,6 +30,7 @@ import { AuthRoleModule } from './auth-role/auth-role.module'; CoreEnvModule, CoreMenuModule, AuthRoleModule, + AuthDeptModule, ], controllers: [AppController], providers: [ diff --git a/src/application/auth-dept/auth-dept.controller.ts b/src/application/auth-dept/auth-dept.controller.ts new file mode 100644 index 0000000..07ed7eb --- /dev/null +++ b/src/application/auth-dept/auth-dept.controller.ts @@ -0,0 +1,108 @@ +import { Controller, Get, Post, Body, Patch, Param, Delete, Query } from '@nestjs/common'; +import { AuthDeptService } from './auth-dept.service'; +import { CreateAuthDeptDto } from './dto/create-auth-dept.dto'; +import { UpdateAuthDeptDto } from './dto/update-auth-dept.dto'; +import { ApiOperation, ApiProduces, ApiTags } from '@nestjs/swagger'; +import { PacInfo } from '@common/decorator/pac-info/pac-info.decorator'; +import { PacInfoType } from '@utils/myType'; +import { GetAuthDeptDto } from '@app/auth-dept/dto/get-auth-dept.dto'; +import { + GetUserForAttDto +} from "@dto/GetUserForAtt.dto"; +import {DeptLinkUserDto} from "@dto/AttLinkUser.dto"; + +@ApiTags('部门服务') +@Controller('authDept') +export class AuthDeptController { + constructor(private readonly authDeptService: AuthDeptService) {} + + @ApiOperation({ + summary: '添加部门', + description: '部门', + }) + @ApiProduces('application/json') + @Post() + create(@Body() createAuthDeptDto: CreateAuthDeptDto, @PacInfo() pacInfo: PacInfoType) { + return this.authDeptService.create(createAuthDeptDto, pacInfo); + } + + @ApiOperation({ + summary: '获取部门列表', + description: '查询部门分页或者列表', + }) + @ApiProduces('application/json') + @Get() + findAll(@Query() getAuthDeptDto: GetAuthDeptDto) { + return this.authDeptService.findAll(getAuthDeptDto); + } + + @ApiOperation({ + summary: '获取部门详细信息', + description: '查询部门详细信息,目录菜单列表,数据权限范围', + }) + @ApiProduces('application/json') + @Get(':id') + findOne(@Param('id') id: string) { + return this.authDeptService.findOne(id); + } + + @ApiOperation({ + summary: '获取部门树', + description: '查询部门基本信息,树结构', + }) + @ApiProduces('application/json') + @Get('/tree/:pid') + findTree(@Param('pid') pid: string) { + return this.authDeptService.findTree(pid); + } + + @ApiOperation({ + summary: '更新部门信息', + description: '更新部门信息', + }) + @ApiProduces('application/json') + @Patch(':id') + update(@Param('id') id: string, @Body() updateAuthDeptDto: UpdateAuthDeptDto, @PacInfo() pacInfo: PacInfoType) { + return this.authDeptService.update(id, updateAuthDeptDto, pacInfo); + } + + @ApiOperation({ + summary: '删除目标部门', + description: '删除目标部门信息', + }) + @ApiProduces('application/json') + @Delete(':id') + remove(@Param('id') id: string, @PacInfo() pacInfo: PacInfoType) { + return this.authDeptService.remove(id, pacInfo); + } + + @ApiOperation({ + summary: '获取部门下的用户分页', + description: '获取部门下的用户分页', + }) + @ApiProduces('application/json') + @Get('/user/:pid') + findUser(@Param('pid') pid: string,@Query() getUserForAttDto: GetUserForAttDto) { + return this.authDeptService.findUser(pid, getUserForAttDto); + } + + @ApiOperation({ + summary: '给部门绑定账户', + description: '给部门关联上账户,最大200个', + }) + @ApiProduces('application/json') + @Post('/user') + linkUser(@Body() deptLinkUserDto: DeptLinkUserDto, @PacInfo() pacInfo: PacInfoType) { + return this.authDeptService.linkUser(deptLinkUserDto, pacInfo); + } + + @ApiOperation({ + summary: '给部门解绑账户', + description: '给部门取消关联上账户,最大200个', + }) + @ApiProduces('application/json') + @Delete('/user') + unlinkUser(@Body() deptLinkUserDto: DeptLinkUserDto) { + return this.authDeptService.unlinkUser(deptLinkUserDto); + } +} diff --git a/src/application/auth-dept/auth-dept.module.ts b/src/application/auth-dept/auth-dept.module.ts new file mode 100644 index 0000000..89a57e9 --- /dev/null +++ b/src/application/auth-dept/auth-dept.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { AuthDeptService } from './auth-dept.service'; +import { AuthDeptController } from './auth-dept.controller'; + +@Module({ + controllers: [AuthDeptController], + providers: [AuthDeptService], +}) +export class AuthDeptModule {} diff --git a/src/application/auth-dept/auth-dept.service.ts b/src/application/auth-dept/auth-dept.service.ts new file mode 100644 index 0000000..31a43c7 --- /dev/null +++ b/src/application/auth-dept/auth-dept.service.ts @@ -0,0 +1,560 @@ +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { CreateAuthDeptDto } from './dto/create-auth-dept.dto'; +import { UpdateAuthDeptDto } from './dto/update-auth-dept.dto'; +import { GetAuthDeptDto } from '@app/auth-dept/dto/get-auth-dept.dto'; +import { PacInfoType } from '@utils/myType'; +import { LoggerService } from '@service/logger/logger.service'; +import { MysqlService } from '@common/service/mysql/mysql.service'; +import { RedisService } from '@common/service/redis/redis.service'; +import { Snowflake } from '@service/snowflake/snowflake.service'; +import { ConfigService } from '@nestjs/config'; +import { pacAuthDept, pacAuthLinkUserDept, pacAuthRole, pacAuthUser, pacCoreDict } from '@entities/schema'; +import { and, asc, count, desc, eq, inArray, isNull, like, or, SQL, sql } from 'drizzle-orm'; +import { isExistKey, isTrueEnum } from '@utils/boolean.enum'; +import { likeQuery } from '@utils/likeQuery'; +import { alias, QueryBuilder } from 'drizzle-orm/mysql-core'; +import { customDrizzleRowWithRecursive } from '@utils/customDrizzleRowWithRecursive'; +import { GetUserForAttDto } from '@dto/GetUserForAtt.dto'; +import { + DeptLinkUserDto +} from "@dto/AttLinkUser.dto"; + +@Injectable() +export class AuthDeptService { + // 分页数据格式 + private readonly deptPageType = { + deptId: pacAuthDept.deptId, + pid: pacAuthDept.pid, + grade: pacAuthDept.grade, + deptName: pacAuthDept.deptName, + deptDesc: pacAuthDept.deptDesc, + deptType: pacAuthDept.deptType, + deptTypeKey: pacCoreDict.dictKey, + deptTypeName: pacCoreDict.dictName, + deptLeader: pacAuthDept.deptLeader, + deptLeaderName: pacAuthUser.nickname, + defaultRole: pacAuthDept.defaultRole, + defaultRoleKey: pacAuthRole.roleKey, + defaultRoleName: pacAuthRole.roleName, + haveChildren: pacAuthDept.haveChildren, + orderNum: pacAuthDept.orderNum, + status: pacAuthDept.status, + createby: pacAuthDept.createby, + createtime: pacAuthDept.createtime, + updateby: pacAuthDept.updateby, + updatetime: pacAuthDept.updatetime, + }; + + // 列表数据格式 + private readonly deptListType = { + deptId: pacAuthDept.deptId, + pid: pacAuthDept.pid, + grade: pacAuthDept.grade, + deptName: pacAuthDept.deptName, + deptType: pacAuthDept.deptType, + deptTypeKey: pacCoreDict.dictKey, + deptTypeName: pacCoreDict.dictName, + deptLeader: pacAuthDept.deptLeader, + deptLeaderName: pacAuthUser.nickname, + haveChildren: pacAuthDept.haveChildren, + orderNum: pacAuthDept.orderNum, + }; + constructor( + private readonly logger: LoggerService, + private readonly mysqlService: MysqlService, + private readonly redisService: RedisService, + private readonly snowflake: Snowflake, + private readonly config: ConfigService, + ) {} + + /** Service + * NAME: create + * DESC: 创建部门信息 + * DATE: 2024-06-25 15:53:04 - + * */ + public async create(createAuthDeptDto: CreateAuthDeptDto, pacInfo: PacInfoType) { + // ! 加目标锁,同级,而不是全局 + const lock = await this.redisService.distributedLock('DEPT' + createAuthDeptDto.pid + '-' + createAuthDeptDto.deptName, createAuthDeptDto.deptName); + + // ? 存在正在进行写入的部门 + if (!lock) throw new HttpException('服务繁忙,部门名称重复!', HttpStatus.CONFLICT); + + // @ 核心逻辑 + + try { + // ! 同级查重 + const result = await this.checkRepeatForDeptName(createAuthDeptDto.deptName, createAuthDeptDto.pid); + + // ? 是否存在重复的部门 + if (result.length > 0) throw new HttpException('部门标识重复!', HttpStatus.CONFLICT); + + // ! 获取上级信息 + let pGrade = 0; + if (createAuthDeptDto.pid != 0 as any) { + const pDept = await this.getDeptForDeptId(createAuthDeptDto.pid); + if (pDept.length == 0) throw new HttpException('上级部门不存在!', HttpStatus.BAD_REQUEST); + pGrade = pDept[0].grade; + } + + // ! 添加部门数据 + const newPacCoreDict = await this.addDeptData(createAuthDeptDto, pGrade + 1, pacInfo.userId); + + // ! 解锁 + lock(); + + // !更新父节点的子节点数量 + await this.haveChildrenSelfIncreasing(createAuthDeptDto.pid); + + // ! 返回结果 + return newPacCoreDict; + } catch (e) { + // ! 解锁 + lock(); + + // ! 抛出错误 + throw e; + } + } + + /** Service + * NAME: findAll + * DESC: 获取部门分页/列表 + * DATE: 2024-06-25 15:53:04 - + * */ + public async findAll(getAuthDeptDto: GetAuthDeptDto) { + if (isTrueEnum(getAuthDeptDto['isList'])) { + return await this.getList(getAuthDeptDto); + } else { + return await this.getPage(getAuthDeptDto); + } + } + + /** Service + * NAME: findOne + * DESC: 获取部门详细信息 + * DATE: 2024-06-28 11:30:43 - + * */ + public findOne(id: string) { + return this.getMore(id); + } + + /** Service + * NAME: findTree + * DESC: 获取部门树 + * DATE: 2024-06-28 11:30:47 - + * */ + public async findTree(pid: string) { + const [result] = await this.getRoleTree(pid ? pid : '0'); + return result; + } + + /** Service + * NAME: update + * DESC: 更新部门信息 + * DATE: 2024-06-28 11:30:50 - + * */ + public async update(id: string, updateAuthDeptDto: UpdateAuthDeptDto, pacInfo: PacInfoType) { + return this.updateDept(id, updateAuthDeptDto, pacInfo.userId); + } + + /** Service + * NAME: remove + * DESC: 删除部门信息 + * DATE: 2024-06-28 11:30:54 - + * */ + public async remove(id: string, pacInfo: PacInfoType) { + return await this.deleteDept(id, pacInfo.userId); + } + + /** Service + * NAME: findUser + * DESC: 查找部门下的用户分页 + * DATE: 2024-06-28 17:17:16 - + * */ + public async findUser(id: string, getUserForAttDto: GetUserForAttDto) { + return this.getDeptUser(id, getUserForAttDto); + } + + /** Service + * NAME: linkUser + * DESC: 关联账户给部门 + * DATE: 2024-06-28 17:17:16 - + * */ + public async linkUser(deptLinkUserDto: DeptLinkUserDto, pacInfo: PacInfoType) { + return this.linkUserForDept(deptLinkUserDto, pacInfo); + } + + /** Service + * NAME: unlinkUser + * DESC: 取消关联账户给部门 + * DATE: 2024-06-27 15:38:54 - + * */ + public async unlinkUser(deptLinkUserDto: DeptLinkUserDto) { + return this.unlinkUserForDept(deptLinkUserDto); + } + + // DB 同级查重 + private checkRepeatForDeptName(deptName: string, pid: string) { + return this.mysqlService.db + .select() + .from(pacAuthDept) + .where(and(isNull(pacAuthDept.deleteby), eq(pacAuthDept.pid, pid), eq(pacAuthDept.deptName, deptName))); + } + + // DB 根据id查部门信息 + private getDeptForDeptId(deptId: string) { + return this.mysqlService.db + .select() + .from(pacAuthDept) + .where(and(isNull(pacAuthDept.deleteby), eq(pacAuthDept.deptId, deptId))); + } + + // DB 更新父级子元素数量 + private async haveChildrenSelfIncreasing(id: string, isAdd = true) { + return this.mysqlService.db + .update(pacAuthDept) + .set({ + haveChildren: isAdd ? sql`${pacAuthDept.haveChildren} + 1` : sql`${pacAuthDept.haveChildren} - 1`, + }) + .where(eq(pacAuthDept.deptId as any, id)); + } + + // DB 添加部门数据 + private async addDeptData(createAuthDeptDto: CreateAuthDeptDto, grade, userId) { + // ! 生成雪花id,用于部门主键 + const id = await this.snowflake.generate(); + + // ! 定义写入的部门数据 + const newDeptData: typeof pacAuthDept.$inferInsert = { + pid: createAuthDeptDto.pid, + deptId: id as any, + grade: grade, + deptName: createAuthDeptDto.deptName, + deptDesc: createAuthDeptDto.deptDesc, + deptType: createAuthDeptDto.deptType, + deptLeader: createAuthDeptDto.deptLeader, + defaultRole: createAuthDeptDto.defaultRole, + orderNum: createAuthDeptDto.orderNum, + createby: userId, + createtime: sql`now()` as any, + }; + return await this.mysqlService.db.insert(pacAuthDept).values(newDeptData); + } + + // DB 差距查询构建器 + private queryBuilder(getAuthDeptDto: GetAuthDeptDto, selectData = undefined) { + // ! 定义基础查询函数 + // 启用动态查询模式 $dynamic + const query = this.mysqlService.db + .select(selectData) + .from(pacAuthDept) + .orderBy( + isTrueEnum(getAuthDeptDto.isAsc) ? asc(pacAuthDept.orderNum) : desc(pacAuthDept.orderNum), + isTrueEnum(getAuthDeptDto.isAsc) ? asc(pacAuthDept.deptId) : desc(pacAuthDept.deptId), + ) + .leftJoin(pacCoreDict, eq(pacAuthDept.deptType, pacCoreDict.dictId)) + .leftJoin(pacAuthUser, eq(pacAuthDept.deptLeader, pacAuthUser.userId)) + .$dynamic(); + + // 查询条件集合 + const wl = []; + + // ? 未删除 + wl.push(isNull(pacAuthDept.deleteby)); + + // ? 模糊查询 + wl.push( + or(like(pacAuthDept.deptName, likeQuery(getAuthDeptDto.deptInfo)), like(pacAuthDept.deptDesc, likeQuery(getAuthDeptDto.deptInfo))).if( + isExistKey(getAuthDeptDto, 'deptInfo'), + ), + ); + + // ? 按照层级查 + wl.push(eq(pacAuthDept.pid, getAuthDeptDto.hierarchy).if(isExistKey(getAuthDeptDto, 'hierarchy'))); + + // ? 是否查部门类型 + wl.push(eq(pacAuthDept.deptType, getAuthDeptDto.deptType).if(isExistKey(getAuthDeptDto, 'deptType'))); + + // ? 是否查字典状态 + wl.push(eq(pacAuthDept.status, getAuthDeptDto.status as any).if(isExistKey(getAuthDeptDto, 'status'))); + + query.where(and(...wl)); + return query; + } + + // DB 查分页 + private async getPage(getAuthDeptDto: GetAuthDeptDto) { + const offset = (getAuthDeptDto.pageNumber - 1) * getAuthDeptDto.pageSize; + + // ! 使用基础查询构建查询总记录数 + const totalCountQuery = this.queryBuilder(getAuthDeptDto, { + totalCount: sql`COUNT(*)`, + }); + + // ! 使用基础查询构建分页查询 + // 重命名表 + const userTable1 = alias(pacAuthUser, 'userTable1'); + const userTable2 = alias(pacAuthUser, 'userTable2'); + const paginatedQuery = this.queryBuilder(getAuthDeptDto, { + ...this.deptPageType, + updateName: userTable1.nickname, + createName: userTable2.nickname, + }) + .leftJoin(pacAuthRole, eq(pacAuthDept.defaultRole, pacAuthRole.roleId)) + .leftJoin(userTable2, eq(pacAuthDept.createby, userTable2.userId)) + .leftJoin(userTable1, eq(pacAuthDept.updateby, userTable1.userId)) + .limit(getAuthDeptDto.pageSize) + .offset(offset); + + return { + total: (await totalCountQuery)[0].totalCount, + rowData: await paginatedQuery, + searchData: getAuthDeptDto, + }; + } + + // DB 查列表 + private async getList(getAuthDeptDto: GetAuthDeptDto) { + return this.queryBuilder(getAuthDeptDto, this.deptListType); + } + + // DB 查树 + private getRoleTree(pid: string = '0') { + console.log(pid); + + // ! 基础层级 + const baseQueryBuilder = new QueryBuilder(); + const baseQuery = baseQueryBuilder + .select({ + ...this.deptListType, + level: sql`0`.as('level'), + }) + .from(pacAuthDept) + .leftJoin(pacCoreDict, eq(pacAuthDept.deptType, pacCoreDict.dictId)) + .leftJoin(pacAuthUser, eq(pacAuthDept.deptLeader, pacAuthUser.userId)) + .where(and(isNull(pacAuthDept.deleteby), eq(pacAuthDept.pid, pid))); + + // ! 递归层级 + const recursiveQueryBuilder = new QueryBuilder(); + const recursiveQuery = recursiveQueryBuilder + .select({ + ...this.deptListType, + level: sql`deptHierarchy.level + 1`.as('level'), + }) + .from(pacAuthDept) + .leftJoin(pacCoreDict, eq(pacAuthDept.deptType, pacCoreDict.dictId)) + .leftJoin(pacAuthUser, eq(pacAuthDept.deptLeader, pacAuthUser.userId)) + .where(isNull(pacAuthDept.deleteby)) + .innerJoin(sql`deptHierarchy`, sql`deptHierarchy.deptId = ${pacAuthDept.pid}`); + + const rowName: SQL = customDrizzleRowWithRecursive(this.deptListType); + + // ! 执行原始SQL查询 + return this.mysqlService.db.execute( + sql`WITH RECURSIVE deptHierarchy(${rowName}) AS(${baseQuery} UNION ALL ${recursiveQuery}) SELECT * FROM deptHierarchy`, + ); + } + + // DB 查详情 + private async getMore(id: string) { + const userTable1 = alias(pacAuthUser, 'userTable1'); + const userTable2 = alias(pacAuthUser, 'userTable2'); + + const result = await this.mysqlService.db + .select({ ...this.deptPageType, updateName: userTable1.nickname, createName: userTable2.nickname }) + .from(pacAuthDept) + .leftJoin(pacCoreDict, eq(pacAuthDept.deptType, pacCoreDict.dictId)) + .leftJoin(pacAuthUser, eq(pacAuthDept.deptLeader, pacAuthUser.userId)) + .leftJoin(pacAuthRole, eq(pacAuthDept.defaultRole, pacAuthRole.roleId)) + .leftJoin(userTable2, eq(pacAuthDept.createby, userTable2.userId)) + .leftJoin(userTable1, eq(pacAuthDept.updateby, userTable1.userId)) + .where(and(isNull(pacAuthDept.deleteby), eq(pacAuthDept.deptId, id))); + + if (result.length === 0) { + throw new HttpException('未找到目标部门信息!', HttpStatus.BAD_REQUEST); + } + const [{ userCount }] = await this.mysqlService.db + .select({ userCount: count(pacAuthUser.userId) }) + .from(pacAuthUser) + .leftJoin(pacAuthLinkUserDept, eq(pacAuthLinkUserDept.userId, pacAuthUser.userId)) + .where(and(isNull(pacAuthUser.deleteby), eq(pacAuthLinkUserDept.deptId, id))); + + return { + ...result[0], + userCount, + }; + } + + // DB 删除 + private async deleteDept(id: string, userId) { + // ! 查找部门信息 + const deptData = await this.mysqlService.db + .select() + .from(pacAuthDept) + .where(and(isNull(pacAuthDept.deleteby), eq(pacAuthDept.deptId, id))); + + if (deptData.length === 0) throw new HttpException('未找到目标部门信息,无法删除!', HttpStatus.BAD_REQUEST); + + // ? 判断是否存在子项 + if (deptData[0].haveChildren != 0) throw new HttpException('该部门存在子项!', HttpStatus.BAD_REQUEST); + + // ! 判断父节点是否存在 + if (deptData[0].pid != 0) { + // ! 减少父级子节点数量 + await this.haveChildrenSelfIncreasing(deptData[0].pid, false); + } + + // ! 删除部门数据 + return await this.mysqlService.db + .update(pacAuthDept) + .set({ + deletetime: sql`now()`, + deleteby: userId, + }) + .where(eq(pacAuthDept.deptId, id)); + } + + // DB 修改 + private updateDept(id, updateAuthDeptDto: UpdateAuthDeptDto, userId) { + return this.mysqlService.db + .update(pacAuthDept) + .set({ + deptName: updateAuthDeptDto.deptName, + deptDesc: updateAuthDeptDto.deptDesc, + deptType: updateAuthDeptDto.deptType, + deptLeader: updateAuthDeptDto.deptLeader, + defaultRole: updateAuthDeptDto.defaultRole, + orderNum: updateAuthDeptDto.orderNum, + status: updateAuthDeptDto.status, + updateby: userId, + updatetime: sql`now()`, + }) + .where(eq(pacAuthDept.deptId, id)); + } + + // DB 查找部门下的账户查询构建 + private getDeptUserQuery(roleId: string, getUserForRoleDto: GetUserForAttDto, selectData = null) { + const query = this.mysqlService.db + .select(selectData) + .from(pacAuthUser) + .orderBy(isTrueEnum(getUserForRoleDto.isAsc) ? asc(pacAuthUser.userId) : desc(pacAuthUser.userId)) + .leftJoin(pacCoreDict, eq(pacAuthUser.userType, pacCoreDict.dictId)) + .leftJoin(pacAuthLinkUserDept, eq(pacAuthLinkUserDept.userId, pacAuthUser.userId)) + .$dynamic(); + const wl = []; + + // ? 未删除 + wl.push(isNull(pacAuthUser.deleteby)); + + // ? 模糊查询 + wl.push( + or( + like(pacAuthUser.nickname, likeQuery(getUserForRoleDto.userInfo)), + like(pacAuthUser.userDesc, likeQuery(getUserForRoleDto.userInfo)), + like(pacAuthUser.userEmail, likeQuery(getUserForRoleDto.userInfo)), + like(pacAuthUser.userPhone, likeQuery(getUserForRoleDto.userInfo)), + like(pacAuthUser.username, likeQuery(getUserForRoleDto.userInfo)), + ).if(isExistKey(getUserForRoleDto, 'userInfo')), + ); + + // ? 目标roleId + wl.push(eq(pacAuthLinkUserDept.deptId, roleId)); + + // ? 用户类型 + wl.push(eq(pacAuthUser.userType, getUserForRoleDto.userType).if(isExistKey(getUserForRoleDto, 'userType'))); + query.where(and(...wl)); + return query; + } + + // DB 查找部门下的账户 + private async getDeptUser(deptId: string, getUserForAttDto: GetUserForAttDto) { + console.log(getUserForAttDto); + const offset = (getUserForAttDto.pageNumber - 1) * getUserForAttDto.pageSize; + + // ! 使用基础查询构建查询总记录数 + const totalCountQuery = this.getDeptUserQuery(deptId, getUserForAttDto, { + totalCount: sql`COUNT(*)`, + }); + + // ! 使用基础查询构建分页查询 + // 重命名表 + const userTable1 = alias(pacAuthUser, 'userTable1'); + const userTable2 = alias(pacAuthUser, 'userTable2'); + const paginatedQuery = this.getDeptUserQuery(deptId, getUserForAttDto, { + userId: pacAuthUser.userId, + username: pacAuthUser.username, + nickname: pacAuthUser.nickname, + userType: pacAuthUser.userType, + userTypeName: pacCoreDict.dictName, + userTypeKey: pacCoreDict.dictKey, + userEmail: pacAuthUser.userEmail, + avatar: pacAuthUser.avatar, + userPhone: pacAuthUser.userPhone, + userDesc: pacAuthUser.userDesc, + haveChildren: pacAuthUser.haveChildren, + createby: pacAuthUser.createby, + createName: userTable2.nickname, + createtime: pacAuthUser.createtime, + updateName: userTable1.nickname, + }) + .leftJoin(userTable2, eq(pacAuthUser.createby, userTable2.userId)) + .leftJoin(userTable1, eq(pacAuthUser.updateby, userTable1.userId)) + .limit(getUserForAttDto.pageSize) + .offset(offset); + + return { + total: (await totalCountQuery)[0].totalCount, + rowData: await paginatedQuery, + searchData: getUserForAttDto, + }; + } + + // DB 查找部门账户关联数据 + private async getDeptLinkUser(deptId: string, userIdList: string[]) { + return this.mysqlService.db + .select({ + id: pacAuthLinkUserDept.userId, + index: pacAuthLinkUserDept.index, + }) + .from(pacAuthLinkUserDept) + .where(and(eq(pacAuthLinkUserDept.deptId, deptId), inArray(pacAuthLinkUserDept.userId, userIdList))); + } + + // DB 给部门关联上账户 + private async linkUserForDept(deptLinkUserDto: DeptLinkUserDto, pacInfo: PacInfoType) { + // ! 去重账户ID + const deduplicateUserId = Array.from(new Set(deptLinkUserDto.userIdList)); + + // ! 查找部门是否存在这些账户 + const existUser = await this.getDeptLinkUser(deptLinkUserDto.deptId, deduplicateUserId); + + // ! 获取已存在的账户Id + const existUserIdList = existUser.map((user) => user.id); + + // ! 过滤已经存在的账户 + const userIdList = deptLinkUserDto.userIdList.filter((i) => !existUserIdList.includes(i)); + + return await this.mysqlService.db.insert(pacAuthLinkUserDept).values( + userIdList.map((i) => ({ + deptId: deptLinkUserDto.deptId, + userId: i, + createby: pacInfo.userId, + createtime: sql`now()` as any, + })), + ); + } + + // DB 取消部门关联的账户 + private async unlinkUserForDept(deptLinkUserDto: DeptLinkUserDto) { + // ! 去重账户ID + const deduplicateUserId = Array.from(new Set(deptLinkUserDto.userIdList)); + + // ! 查找部门是否存在这些账户 + const existUser = await this.getDeptLinkUser(deptLinkUserDto.deptId, deduplicateUserId); + + // ! 获取已存在的账户Id + const existUserIndexList = existUser.map((user) => user.index); + + return await this.mysqlService.db.delete(pacAuthLinkUserDept).where(inArray(pacAuthLinkUserDept.index, existUserIndexList)); + } +} diff --git a/src/application/auth-dept/dto/create-auth-dept.dto.ts b/src/application/auth-dept/dto/create-auth-dept.dto.ts new file mode 100644 index 0000000..60e6f21 --- /dev/null +++ b/src/application/auth-dept/dto/create-auth-dept.dto.ts @@ -0,0 +1,107 @@ +import { ApiProperty } from '@nestjs/swagger'; +import Trim from '@common/decorator/trim/trim.decorator'; +import { IsInt, IsOptional, IsString, Length, Max, Min } from 'class-validator'; + +export class CreateAuthDeptDto { + @ApiProperty({ + description: '部门父ID', + type: String, + example: '0', + required: false, + minLength: 1, + maxLength: 32, + }) + @Trim() + @IsString({ message: '部门关联属性应为字符串格式!' }) + @IsOptional() + readonly pid?: string = '0'; + + @ApiProperty({ + description: '部门名称', + type: String, + example: '研发部', + required: true, + minLength: 1, + maxLength: 32, + }) + @Trim() + @IsString({ message: '部门名称应为字符串格式!' }) + @Length(1, 32, { message: '部门名称长度控制在1到32位之间!' }) + deptName: string; + + @ApiProperty({ + description: '部门描述', + type: String, + example: '0', + required: false, + minLength: 1, + maxLength: 255, + }) + @Trim() + @IsString({ message: '部门描述应为字符串格式!' }) + @Length(1, 255, { message: '请将部门描述长度控制在1到255位之间!' }) + @IsOptional() + deptDesc: string; + + @ApiProperty({ + description: '部门类型,来自于字典', + type: String, + example: '0', + required: false, + minLength: 19, + maxLength: 19, + }) + @Trim() + @IsString({ message: '部门类型格式不正确!' }) + @Length(19, 19, { message: '部门类型格式不正确!' }) + @IsOptional() + deptType: string; + + @ApiProperty({ + description: '部门负责人,来自于用户', + type: String, + example: '0', + required: false, + minLength: 19, + maxLength: 19, + }) + @Trim() + @IsString({ message: '部门负责人格式不正确!' }) + @Length(1, 19, { message: '部门负责人格式不正确!' }) + @IsOptional() + deptLeader: string; + + @ApiProperty({ + description: '部门默认角色,来自于角色', + type: String, + example: '0', + required: false, + minLength: 19, + maxLength: 19, + }) + @Trim() + @IsString({ message: '部门默认角色格式不正确!' }) + @Length(19, 19, { message: '部门默认角色格式不正确!' }) + @IsOptional() + defaultRole: string; + + @ApiProperty({ + description: '排序', + type: Number, + example: 10, + required: false, + minimum: -1000, + maximum: 1000, + }) + @IsOptional() + @IsInt({ + message: '排序必须是整数!', + }) + @Min(-1000, { + message: '排序不能小于-1000!', + }) + @Max(1000, { + message: '排序不能超过1000', + }) + orderNum: number; +} diff --git a/src/application/auth-dept/dto/get-auth-dept.dto.ts b/src/application/auth-dept/dto/get-auth-dept.dto.ts new file mode 100644 index 0000000..eb1aec0 --- /dev/null +++ b/src/application/auth-dept/dto/get-auth-dept.dto.ts @@ -0,0 +1,85 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: pac-auth +// | @文件描述: get-auth-dept.dto.ts - +// | @创建时间: 2024-06-28 11:20 +// | @更新时间: 2024-06-28 11:20 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import { GetDto } from '@dto/get.dto'; +import { ApiProperty } from '@nestjs/swagger'; +import Trim from '@common/decorator/trim/trim.decorator'; +import { IsEnum, IsInt, IsOptional, IsString, Length, Max, Min } from 'class-validator'; +import { BooleanEnum } from '@utils/boolean.enum'; +import Int from '@common/decorator/int/int.descrator'; + +export class GetAuthDeptDto extends GetDto { + @ApiProperty({ + description: '角色', + type: String, + example: '管理员', + required: false, + minLength: 1, + maxLength: 128, + }) + @Trim() + @IsString({ message: '角色信息应为字符串格式!' }) + @Length(0, 128, { message: '请将角色信息长度控制在1到128位之间!' }) + @IsOptional() + readonly deptInfo?: string; + + @ApiProperty({ + description: '角色类型,来自于字典', + type: String, + example: '0', + required: false, + minLength: 19, + maxLength: 19, + }) + @Trim() + @IsString({ message: '角色类型格式不正确!' }) + @Length(19, 19, { message: '角色类型格式不正确!' }) + @IsOptional() + readonly deptType: string; + + @ApiProperty({ + description: '角色状态', + type: Number, + example: 0, + required: false, + minimum: -100, + maximum: 100, + }) + @Trim() + @Int() + @IsInt({ + message: '角色状态必须是整数!', + }) + @Min(-100, { + message: '角色状态需要大于-100!', + }) + @Max(100, { + message: '角色状态不能超过100', + }) + @IsOptional() + readonly status?: string; + + @ApiProperty({ + description: '角色层级id', + type: Number, + example: 0, + required: false, + minimum: 0, + maximum: 100, + }) + @Trim() + @IsString({ message: '角色层级id应为字符串格式!' }) + @Length(1, 20, { message: '角色层级id格式错误!' }) + @IsOptional() + readonly hierarchy?: string; +} diff --git a/src/application/auth-dept/dto/update-auth-dept.dto.ts b/src/application/auth-dept/dto/update-auth-dept.dto.ts new file mode 100644 index 0000000..ac4f9c6 --- /dev/null +++ b/src/application/auth-dept/dto/update-auth-dept.dto.ts @@ -0,0 +1,25 @@ +import { ApiProperty, PartialType } from '@nestjs/swagger'; +import { CreateAuthDeptDto } from './create-auth-dept.dto'; +import { IsInt, IsOptional, Max, Min } from 'class-validator'; + +export class UpdateAuthDeptDto extends PartialType(CreateAuthDeptDto) { + @ApiProperty({ + description: '状态', + type: Number, + example: 10, + required: false, + minimum: -100, + maximum: 100, + }) + @IsOptional() + @IsInt({ + message: '状态必须是整数!', + }) + @Min(-1000, { + message: '状态不能小于-100!', + }) + @Max(1000, { + message: '状态不能超过100', + }) + readonly status: number; +} diff --git a/src/application/auth-role/auth-role.controller.ts b/src/application/auth-role/auth-role.controller.ts index 4c272f4..08e64e4 100644 --- a/src/application/auth-role/auth-role.controller.ts +++ b/src/application/auth-role/auth-role.controller.ts @@ -6,13 +6,9 @@ import { ApiOperation, ApiProduces, ApiTags } from '@nestjs/swagger'; import { PacInfo } from '@common/decorator/pac-info/pac-info.decorator'; import { PacInfoType } from '@utils/myType'; import { query } from 'express'; -import { - GetPacAuthRoleAllDto, - GetUserForRoleDto -} from "@app/auth-role/dto/get-auth-role.dto"; -import { - RoleLinkUserDto -} from "@app/auth-role/dto/roleLinkUser.dto"; +import { GetPacAuthRoleAllDto } from '@app/auth-role/dto/get-auth-role.dto'; +import {GetUserForAttDto} from "@dto/GetUserForAtt.dto"; +import { RoleLinkUserDto } from '@dto/AttLinkUser.dto'; @ApiTags('角色服务') @Controller('authRole') @@ -85,7 +81,7 @@ export class AuthRoleController { }) @ApiProduces('application/json') @Get('/user/:roleId') - findUserByRoleId(@Param('roleId') roleId: string, @Query() getUserForRoleDto: GetUserForRoleDto) { + findUserByRoleId(@Param('roleId') roleId: string, @Query() getUserForRoleDto: GetUserForAttDto) { return this.authRoleService.findUserByRoleId(roleId, getUserForRoleDto); } @@ -106,7 +102,6 @@ export class AuthRoleController { @ApiProduces('application/json') @Delete('/user') unlinkUser(@Body() roleLinkUserDto: RoleLinkUserDto) { - console.log(roleLinkUserDto); return this.authRoleService.unlinkUser(roleLinkUserDto); } } diff --git a/src/application/auth-role/auth-role.module.ts b/src/application/auth-role/auth-role.module.ts index b71d4a5..1a309a9 100644 --- a/src/application/auth-role/auth-role.module.ts +++ b/src/application/auth-role/auth-role.module.ts @@ -3,7 +3,7 @@ import { AuthRoleService } from './auth-role.service'; import { AuthRoleController } from './auth-role.controller'; @Module({ - controllers: [AuthRoleController], - providers: [AuthRoleService], + controllers: [AuthRoleController], + providers: [AuthRoleService], }) export class AuthRoleModule {} diff --git a/src/application/auth-role/auth-role.service.ts b/src/application/auth-role/auth-role.service.ts index aab1e9f..3a73f0a 100644 --- a/src/application/auth-role/auth-role.service.ts +++ b/src/application/auth-role/auth-role.service.ts @@ -19,11 +19,12 @@ import { pacCoreMenu, } from '@entities/schema'; import { and, asc, desc, eq, inArray, isNull, like, or, SQL, sql } from 'drizzle-orm'; -import { GetPacAuthRoleAllDto, GetUserForRoleDto } from '@app/auth-role/dto/get-auth-role.dto'; +import { GetPacAuthRoleAllDto } from '@app/auth-role/dto/get-auth-role.dto'; +import { GetUserForAttDto } from '@dto/GetUserForAtt.dto'; import { likeQuery } from '@utils/likeQuery'; import { alias, QueryBuilder } from 'drizzle-orm/mysql-core'; import { customDrizzleRowWithRecursive } from '@utils/customDrizzleRowWithRecursive'; -import { RoleLinkUserDto } from '@app/auth-role/dto/roleLinkUser.dto'; +import {RoleLinkUserDto} from "@dto/AttLinkUser.dto"; @Injectable() export class AuthRoleService { @@ -80,7 +81,7 @@ export class AuthRoleService { } // ! 加目标锁 - const lock = await this.redisService.distributedLock('DICT' + createAuthRoleDto.roleKey, createAuthRoleDto.roleKey); + const lock = await this.redisService.distributedLock('ROLE' + createAuthRoleDto.roleKey, createAuthRoleDto.roleKey); // ? 存在正在进行写入的角色 if (!lock) throw new HttpException('服务繁忙,角色标识重复!', HttpStatus.CONFLICT); @@ -158,7 +159,7 @@ export class AuthRoleService { * DATE: 2024-06-27 14:23:36 - * */ public async findTree(pid: string) { - const [result] = await this.getRoleTree(pid); + const [result] = await this.getRoleTree(pid ? pid : '0'); return result; } @@ -167,7 +168,7 @@ export class AuthRoleService { * DESC: 获取角色下的关联账户 * DATE: 2024-06-27 14:49:42 - * */ - public async findUserByRoleId(roleId: string, getUserForRoleDto: GetUserForRoleDto) { + public async findUserByRoleId(roleId: string, getUserForRoleDto: GetUserForAttDto) { return await this.getRoleUser(roleId, getUserForRoleDto); } @@ -186,7 +187,7 @@ export class AuthRoleService { } // ! 加目标锁 - const lock = await this.redisService.distributedLock('DICT' + updateAuthRoleDto.roleKey, updateAuthRoleDto.roleKey); + const lock = await this.redisService.distributedLock('ROLE' + updateAuthRoleDto.roleKey, updateAuthRoleDto.roleKey); // ? 存在正在进行写入的角色 if (!lock) throw new HttpException('服务繁忙,角色标识重复!', HttpStatus.CONFLICT); @@ -396,7 +397,7 @@ export class AuthRoleService { updateName: userTable1.nickname, }) .leftJoin(pacAuthUser, eq(pacAuthRole.createby, pacAuthUser.userId)) - .leftJoin(userTable1, eq(pacAuthRole.updateby, pacAuthUser.userId)) + .leftJoin(userTable1, eq(pacAuthRole.updateby, userTable1.userId)) .limit(getPacAuthRoleAllDto.pageSize) .offset(offset); @@ -459,7 +460,7 @@ export class AuthRoleService { .from(pacAuthRole) .leftJoin(pacCoreDict, eq(pacAuthRole.roleType, pacCoreDict.dictId)) .leftJoin(pacAuthUser, eq(pacAuthRole.createby, pacAuthUser.userId)) - .leftJoin(userTable1, eq(pacAuthRole.updateby, pacAuthUser.userId)) + .leftJoin(userTable1, eq(pacAuthRole.updateby, userTable1.userId)) .where(and(isNull(pacAuthRole.deleteby), eq(pacAuthRole.roleId, roleId))); // ! 如果不存在角色信息直接报错 @@ -572,11 +573,11 @@ export class AuthRoleService { } // DB 查找角色下的账户查询构建 - private getRoleUserQuery(roleId: string, getUserForRoleDto: GetUserForRoleDto, selectData = null) { + private getRoleUserQuery(roleId: string, getUserForAttDto: GetUserForAttDto, selectData = null) { const query = this.mysqlService.db .select(selectData) .from(pacAuthUser) - .orderBy(isTrueEnum(getUserForRoleDto.isAsc) ? asc(pacAuthUser.userId) : desc(pacAuthUser.userId)) + .orderBy(isTrueEnum(getUserForAttDto.isAsc) ? asc(pacAuthUser.userId) : desc(pacAuthUser.userId)) .leftJoin(pacCoreDict, eq(pacAuthUser.userType, pacCoreDict.dictId)) .leftJoin(pacAuthLinkUserRole, eq(pacAuthLinkUserRole.userId, pacAuthUser.userId)) .$dynamic(); @@ -588,29 +589,29 @@ export class AuthRoleService { // ? 模糊查询 wl.push( or( - like(pacAuthUser.nickname, likeQuery(getUserForRoleDto.userInfo)), - like(pacAuthUser.userDesc, likeQuery(getUserForRoleDto.userInfo)), - like(pacAuthUser.userEmail, likeQuery(getUserForRoleDto.userInfo)), - like(pacAuthUser.userPhone, likeQuery(getUserForRoleDto.userInfo)), - like(pacAuthUser.username, likeQuery(getUserForRoleDto.userInfo)), - ).if(isExistKey(getUserForRoleDto, 'userInfo')), + like(pacAuthUser.nickname, likeQuery(getUserForAttDto.userInfo)), + like(pacAuthUser.userDesc, likeQuery(getUserForAttDto.userInfo)), + like(pacAuthUser.userEmail, likeQuery(getUserForAttDto.userInfo)), + like(pacAuthUser.userPhone, likeQuery(getUserForAttDto.userInfo)), + like(pacAuthUser.username, likeQuery(getUserForAttDto.userInfo)), + ).if(isExistKey(getUserForAttDto, 'userInfo')), ); // ? 目标roleId wl.push(eq(pacAuthLinkUserRole.roleId, roleId)); // ? 用户类型 - wl.push(eq(pacAuthUser.userType, getUserForRoleDto.userType).if(isExistKey(getUserForRoleDto, 'userType'))); + wl.push(eq(pacAuthUser.userType, getUserForAttDto.userType).if(isExistKey(getUserForAttDto, 'userType'))); query.where(and(...wl)); return query; } // DB 查找角色下的账户 - private async getRoleUser(roleId: string, getUserForRoleDto: GetUserForRoleDto) { - const offset = (getUserForRoleDto.pageNumber - 1) * getUserForRoleDto.pageSize; + private async getRoleUser(roleId: string, getUserForAttDto: GetUserForAttDto) { + const offset = (getUserForAttDto.pageNumber - 1) * getUserForAttDto.pageSize; // ! 使用基础查询构建查询总记录数 - const totalCountQuery = this.getRoleData(getUserForRoleDto, { + const totalCountQuery = this.getRoleUserQuery(roleId, getUserForAttDto, { totalCount: sql`COUNT(*)`, }); @@ -618,7 +619,7 @@ export class AuthRoleService { // 重命名表 const userTable1 = alias(pacAuthUser, 'userTable1'); const userTable2 = alias(pacAuthUser, 'userTable2'); - const paginatedQuery = this.getRoleUserQuery(roleId, getUserForRoleDto, { + const paginatedQuery = this.getRoleUserQuery(roleId, getUserForAttDto, { userId: pacAuthUser.userId, username: pacAuthUser.username, nickname: pacAuthUser.nickname, @@ -637,13 +638,13 @@ export class AuthRoleService { }) .leftJoin(userTable2, eq(pacAuthUser.createby, userTable2.userId)) .leftJoin(userTable1, eq(pacAuthUser.updateby, userTable1.userId)) - .limit(getUserForRoleDto.pageSize) + .limit(getUserForAttDto.pageSize) .offset(offset); return { total: (await totalCountQuery)[0].totalCount, rowData: await paginatedQuery, - searchData: getUserForRoleDto, + searchData: getUserForAttDto, }; } diff --git a/src/application/auth-role/dto/create-auth-role.dto.ts b/src/application/auth-role/dto/create-auth-role.dto.ts index a6f6638..e1339ad 100644 --- a/src/application/auth-role/dto/create-auth-role.dto.ts +++ b/src/application/auth-role/dto/create-auth-role.dto.ts @@ -2,9 +2,7 @@ import { ApiProperty } from '@nestjs/swagger'; import Trim from '@common/decorator/trim/trim.decorator'; import { ArrayMinSize, IsEnum, IsInt, IsOptional, IsString, Length, Max, MaxLength, Min, MinLength } from 'class-validator'; import { BooleanEnum } from '@utils/boolean.enum'; -import ChangeCase, { - CaseType -} from "@common/decorator/change-case/change-case.decorator"; +import ChangeCase, { CaseType } from '@common/decorator/change-case/change-case.decorator'; export class CreateAuthRoleDto { @ApiProperty({ diff --git a/src/application/auth-role/dto/get-auth-role.dto.ts b/src/application/auth-role/dto/get-auth-role.dto.ts index 9a0ce0e..d3afeab 100644 --- a/src/application/auth-role/dto/get-auth-role.dto.ts +++ b/src/application/auth-role/dto/get-auth-role.dto.ts @@ -96,33 +96,3 @@ export class GetPacAuthRoleAllDto extends GetDto { @IsOptional() readonly hierarchy?: string; } - -export class GetUserForRoleDto extends GetDto { - @ApiProperty({ - description: '用户信息', - type: String, - example: '哈哈', - required: false, - minLength: 1, - maxLength: 128, - }) - @Trim() - @IsString({ message: '用户信息应为字符串格式!' }) - @Length(0, 128, { message: '请将用户信息长度控制在1到128位之间!' }) - @IsOptional() - readonly userInfo?: string; - - @ApiProperty({ - description: '用户类型,来自于字典', - type: String, - example: '0', - required: false, - minLength: 19, - maxLength: 19, - }) - @Trim() - @IsString({ message: '用户类型格式不正确!' }) - @Length(19, 19, { message: '用户类型格式不正确!' }) - @IsOptional() - readonly userType: string; -} diff --git a/src/application/core-dict/dto/create-core-dict.dto.ts b/src/application/core-dict/dto/create-core-dict.dto.ts index 5805765..b553017 100644 --- a/src/application/core-dict/dto/create-core-dict.dto.ts +++ b/src/application/core-dict/dto/create-core-dict.dto.ts @@ -2,9 +2,7 @@ import { ApiProperty } from '@nestjs/swagger'; import { IsEnum, IsInt, IsOptional, IsString, Length, Max, Min } from 'class-validator'; import Trim from '@common/decorator/trim/trim.decorator'; import { BooleanEnum } from '@utils/boolean.enum'; -import ChangeCase, { - CaseType -} from "@common/decorator/change-case/change-case.decorator"; +import ChangeCase, { CaseType } from '@common/decorator/change-case/change-case.decorator'; export class CreateCoreDictDto { @ApiProperty({ diff --git a/src/application/core-dict/dto/get-core-dict.dto.ts b/src/application/core-dict/dto/get-core-dict.dto.ts index 54f602b..86030d9 100644 --- a/src/application/core-dict/dto/get-core-dict.dto.ts +++ b/src/application/core-dict/dto/get-core-dict.dto.ts @@ -34,7 +34,6 @@ export class GetPacCoreDictAllDto extends GetDto { @IsOptional() readonly dictInfo?: string; - @ApiProperty({ description: '字典类型', type: String, diff --git a/src/application/core-menu/dto/create-core-menu.dto.ts b/src/application/core-menu/dto/create-core-menu.dto.ts index 1e5c972..82d3c16 100644 --- a/src/application/core-menu/dto/create-core-menu.dto.ts +++ b/src/application/core-menu/dto/create-core-menu.dto.ts @@ -2,9 +2,7 @@ import { ApiProperty } from '@nestjs/swagger'; import Trim from '@common/decorator/trim/trim.decorator'; import { IsEnum, IsInt, IsOptional, IsString, Length, Max, Min } from 'class-validator'; import { BooleanEnum } from '@utils/boolean.enum'; -import ChangeCase, { - CaseType -} from "@common/decorator/change-case/change-case.decorator"; +import ChangeCase, { CaseType } from '@common/decorator/change-case/change-case.decorator'; export class CreateCoreMenuDto { @ApiProperty({ diff --git a/src/application/core-menu/dto/get-core-menu.dto.ts b/src/application/core-menu/dto/get-core-menu.dto.ts index 6f12f1a..5ab59bb 100644 --- a/src/application/core-menu/dto/get-core-menu.dto.ts +++ b/src/application/core-menu/dto/get-core-menu.dto.ts @@ -17,9 +17,7 @@ import Trim from '@common/decorator/trim/trim.decorator'; import { IsEnum, IsInt, IsOptional, IsString, Length, Max, Min } from 'class-validator'; import { BooleanEnum } from '@utils/boolean.enum'; import Int from '@common/decorator/int/int.descrator'; -import ChangeCase, { - CaseType -} from "@common/decorator/change-case/change-case.decorator"; +import ChangeCase, { CaseType } from '@common/decorator/change-case/change-case.decorator'; export class GetPacCoreMenuAllDto extends GetDto { @ApiProperty({ diff --git a/src/application/core-service/dto/create-core-service.dto.ts b/src/application/core-service/dto/create-core-service.dto.ts index 5c79ed6..83bdd1a 100644 --- a/src/application/core-service/dto/create-core-service.dto.ts +++ b/src/application/core-service/dto/create-core-service.dto.ts @@ -1,9 +1,7 @@ import { IsOptional, IsString, Length } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; import Trim from '@common/decorator/trim/trim.decorator'; -import ChangeCase, { - CaseType -} from "@common/decorator/change-case/change-case.decorator"; +import ChangeCase, { CaseType } from '@common/decorator/change-case/change-case.decorator'; export class CreateCoreServiceDto { @ApiProperty({ diff --git a/src/application/auth-role/dto/roleLinkUser.dto.ts b/src/dto/AttLinkUser.dto.ts similarity index 63% rename from src/application/auth-role/dto/roleLinkUser.dto.ts rename to src/dto/AttLinkUser.dto.ts index 344ca67..5b98ebc 100644 --- a/src/application/auth-role/dto/roleLinkUser.dto.ts +++ b/src/dto/AttLinkUser.dto.ts @@ -42,3 +42,32 @@ export class RoleLinkUserDto { @Length(19, 19, { each: true, message: '账户Id格式错误' }) readonly userIdList?: string[]; } + + +export class DeptLinkUserDto { + @ApiProperty({ + description: '角色ID', + type: String, + example: '0', + required: true, + minLength: 19, + maxLength: 19, + }) + @Trim() + @IsString({ message: '角色属性格式不正确!' }) + @Length(19, 19, { message: '角色属性格式不正确!' }) + readonly deptId: string; + + @ApiProperty({ + description: '账户Id列表', + type: [String], + example: ['a'], + required: true, + minItems: 1, + }) + @IsString({ each: true, message: '账户Id格式错误' }) + @ArrayMinSize(1, { message: '至少需要选择一个需要绑定的账户' }) + @ArrayMaxSize(200, { message: '需要绑定的账户账户超过限制' }) + @Length(19, 19, { each: true, message: '账户Id格式错误' }) + readonly userIdList?: string[]; +} diff --git a/src/dto/GetUserForAtt.dto.ts b/src/dto/GetUserForAtt.dto.ts new file mode 100644 index 0000000..ef2f73e --- /dev/null +++ b/src/dto/GetUserForAtt.dto.ts @@ -0,0 +1,47 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: pac-auth +// | @文件描述: GetUserForAtt.dto.ts - +// | @创建时间: 2024-06-28 16:55 +// | @更新时间: 2024-06-28 16:55 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import { GetDto } from '@dto/get.dto'; +import { ApiProperty } from '@nestjs/swagger'; +import Trim from '@common/decorator/trim/trim.decorator'; +import { IsOptional, IsString, Length } from 'class-validator'; + +export class GetUserForAttDto extends GetDto { + @ApiProperty({ + description: '用户信息', + type: String, + example: '哈哈', + required: false, + minLength: 1, + maxLength: 128, + }) + @Trim() + @IsString({ message: '用户信息应为字符串格式!' }) + @Length(0, 128, { message: '请将用户信息长度控制在1到128位之间!' }) + @IsOptional() + readonly userInfo?: string; + + @ApiProperty({ + description: '用户类型,来自于字典', + type: String, + example: '0', + required: false, + minLength: 19, + maxLength: 19, + }) + @Trim() + @IsString({ message: '用户类型格式不正确!' }) + @Length(19, 19, { message: '用户类型格式不正确!' }) + @IsOptional() + readonly userType: string; +} diff --git a/src/entities/relations.ts b/src/entities/relations.ts index 80768e2..34c5368 100644 --- a/src/entities/relations.ts +++ b/src/entities/relations.ts @@ -1,3 +1,2 @@ -import { relations } from "drizzle-orm/relations"; -import { } from "./schema"; - +import { relations } from 'drizzle-orm/relations'; +import {} from './schema';