kt-template-online-api/src/modules/admin/identity/role/admin-role.service.ts

135 lines
3.8 KiB
TypeScript

import { HttpStatus, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { throwVbenError } from '@/common';
import { AdminMenu } from '../menu/admin-menu.entity';
import { AdminRole } from './admin-role.entity';
import type { AdminRoleInput, AdminRoleListQuery } from '../../contract/admin.types';
@Injectable()
export class AdminRoleService {
constructor(
@InjectRepository(AdminRole)
private readonly roleRepository: Repository<AdminRole>,
@InjectRepository(AdminMenu)
private readonly menuRepository: Repository<AdminMenu>,
) {}
async getRoleList(query: AdminRoleListQuery) {
const page = Number(query.page || 1);
const pageSize = Number(query.pageSize || 20);
const builder = this.roleRepository
.createQueryBuilder('role')
.leftJoinAndSelect('role.menus', 'menu')
.where('role.isDeleted = :isDeleted', { isDeleted: false });
if (query.id) builder.andWhere('role.id LIKE :id', { id: `%${query.id}%` });
if (query.name) {
builder.andWhere('role.name LIKE :name', { name: `%${query.name}%` });
}
if (query.remark) {
builder.andWhere('role.remark LIKE :remark', {
remark: `%${query.remark}%`,
});
}
if (['0', '1'].includes(String(query.status))) {
builder.andWhere('role.status = :status', {
status: Number(query.status),
});
}
if (query.startTime) {
builder.andWhere('role.createTime >= :startTime', {
startTime: query.startTime,
});
}
if (query.endTime) {
builder.andWhere('role.createTime <= :endTime', {
endTime: query.endTime,
});
}
const [roles, total] = await builder
.orderBy('role.createTime', 'ASC')
.skip((page - 1) * pageSize)
.take(pageSize)
.getManyAndCount();
return {
items: roles.map((role) => this.serializeRole(role)),
total,
};
}
async createRole(data: AdminRoleInput) {
const role = this.roleRepository.create({
name: data.name,
remark: data.remark || '',
roleCode: this.createRoleCode(data.name),
status: data.status ?? 1,
});
role.menus = await this.findMenusByIds(data.permissions || []);
await this.roleRepository.save(role);
return null;
}
async updateRole(id: string, data: AdminRoleInput) {
const role = await this.roleRepository.findOne({
relations: ['menus'],
where: {
id,
isDeleted: false,
},
});
if (!role) throwVbenError('角色不存在', HttpStatus.BAD_REQUEST);
if (data.name !== undefined) role.name = data.name;
if (data.remark !== undefined) role.remark = data.remark;
if (data.status !== undefined) role.status = data.status;
if (data.permissions)
role.menus = await this.findMenusByIds(data.permissions);
await this.roleRepository.save(role);
return null;
}
async deleteRole(id: string) {
await this.roleRepository.update(
{ id },
{
isDeleted: true,
},
);
return null;
}
private serializeRole(role: AdminRole) {
return {
createTime: role.createTime,
id: role.id,
name: role.name,
permissions: (role.menus || []).map((menu) => menu.id),
remark: role.remark,
status: role.status,
};
}
private async findMenusByIds(ids: string[]) {
const normalizedIds = ids.map((id) => String(id)).filter(Boolean);
if (!normalizedIds.length) return [];
return this.menuRepository.find({
where: normalizedIds.map((id) => ({
id,
isDeleted: false,
})),
});
}
private createRoleCode(name?: string) {
const slug = (name || 'role')
.toLowerCase()
.replace(/[^a-z0-9]+/g, '_')
.replace(/^_+|_+$/g, '');
return `${slug || 'role'}_${Date.now()}`;
}
}