import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Menu, User } from '@app/models';
import { Repository } from 'typeorm';
import { CreateMenuDto } from './dto/create-menu.dto';
import { UpdateMenuDto } from './dto/update-menu.dto';
import { I18nTranslations } from '../.generate/i18n.generated';
import { I18nContext, I18nService } from 'nestjs-i18n';
export interface ITreeNodeData {
id: number | string;
label: string;
children?: ITreeNodeData[];
url: string;
component: string;
customIcon: string;
menuType: string;
parentId: number;
order: number;
locale: string;
}
interface MenuMap {
[key: number]: Menu;
}
const toNode = (menu: Menu): ITreeNodeData => {
return {
label: menu.name,
id: menu.id,
children: [],
url: menu.path,
component: menu.component,
customIcon: menu.icon,
menuType: menu.menuType,
parentId: menu.parentId,
order: menu.order,
locale: menu.locale,
};
};
export const convertToTree = (
menus: Menu[],
parentId: number | null = null
) => {
const tree: ITreeNodeData[] = [];
for (let i = 0; i < menus.length; i++) {
const menu = menus[i];
if (menu.parentId === parentId) {
const children = convertToTree(menus, menu.id);
const node = toNode(menu);
node.children = children;
tree.push(node);
}
}
return tree;
};
@Injectable()
export class MenuService {
private menuId: number[] = [];
constructor(
@InjectRepository(User)
private user: Repository<User>,
@InjectRepository(Menu)
private menu: Repository<Menu>,
private readonly i18n: I18nService<I18nTranslations>
) {}
async findRoleMenu(email: string) {
const userInfo = await this.user
.createQueryBuilder('user')
.leftJoinAndSelect('user.role', 'role')
.leftJoinAndSelect('role.menus', 'menus')
.where({
email: email,
})
.orderBy('menus.order', 'ASC')
.getOne();
const menus = userInfo.role.flatMap((role) => role.menus);
const maps: MenuMap = {};
menus.forEach((menu) => {
maps[menu.id] = menu;
});
return convertToTree(menus);
}
async findAllMenu() {
const menu = this.menu.find();
return convertToTree(await menu);
}
async createMenu(dto: CreateMenuDto, isInit: boolean) {
const {
order,
menuType,
name,
path,
component,
icon,
parentId = null,
locale,
} = dto;
const menuInfo = this.menu.findOne({
where: { name, order, menuType, parentId, path, icon, component, locale },
});
if (isInit === true && (await menuInfo)) {
return menuInfo;
}
if ((await menuInfo) && isInit === false) {
throw new HttpException(
this.i18n.t('exception.menu.exists', {
args: { name },
lang: I18nContext.current().lang,
}),
HttpStatus.BAD_REQUEST
);
}
return this.menu.save({
name,
path,
component,
parentId,
menuType,
icon,
order,
locale,
});
}
async updateMenu(newData: UpdateMenuDto) {
await this.menu.update(newData.id, {
name: newData.name,
path: newData.path,
component: newData.component,
parentId: newData.parentId,
menuType: newData.menuType,
icon: newData.icon,
order: newData.order,
locale: newData.locale,
});
return true;
}
async deleteMenu(id: number, parentId: number) {
const menu = this.menu.findOne({
where: {
id: id,
},
});
const allMenu = await this.menu.find();
for (const tmp of allMenu) {
if (Number(tmp.parentId) === Number(id)) {
if (Number(parentId) === -1) {
tmp.parentId = null;
} else {
tmp.parentId = parentId;
}
await this.updateMenu(tmp);
}
}
return this.menu.remove(await menu);
}
}