import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { GlobalService } from './../../../../service/global.service';
import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
// export interface TreeNodeInterface {
// key: number;
// name: string;
// age?: number;
// level?: number;
// expand?: boolean;
// address?: string;
// children?: TreeNodeInterface[];
// parent?: TreeNodeInterface;
// }
//create by huang.l 2020.2.17 17.28
@Component({
selector: 'app-menu',
templateUrl: './menu.component.html',
styleUrls: ['./menu.component.less']
})
export class MenuComponent implements OnInit {
public pageSize: number = 15;
public page: number = 1;
public listOfMapData: any[];
public mapOfExpandedData: { [key: string]: any[] } = {};
public isVisible: boolean = false;
public codePrefix: string = '';
public rootId: string;
public parentMenu: any;
public currentArray: any[];
validateForm: FormGroup;
constructor(
private globalService: GlobalService,
private fb: FormBuilder,
) {
}
async collapse(array: any[], data: any, $event: boolean, rootId: string) {
if ($event === false) {
if (data.children) {
data.children.forEach(d => {
if (array) {
const target = array.find(a => a.id === d.id)!;
if (target) {//如果当前节点还存在
target.expand = false;
console.log(target.id);
this.collapse(array, target, false, rootId);
}
}
});
} else {
return;
}
} else {
if (data.children) {
return;
}
const submenus: any[] = await this.getChildren(data.id);
const submenuArray: any[] = [];
submenus.forEach(item => {
submenuArray.push({ ...item, level: data.level + 1, expand: false, haveChild: (item.haveChild > 0 ? true : false), parent: data });
});
let target: any = null;
const index = array.findIndex(item => item.id === data.id);
target = array[index];
if (target != null) {
target.children = submenuArray;
}
//顺序调整
// array = [...array, ...submenuArray];
array[index] = target;
array.splice(index + 1, 0, ...submenuArray);
// this.mapOfExpandedData[rootId] = array;
}
}
async ngOnInit() {
this.validateForm = this.fb.group({
id: [null],
parentId: [null],
parentName: [null],
name: [null, [Validators.required, Validators.maxLength(20)]],
code: [null, [Validators.required, Validators.maxLength(20), Validators.pattern('^[A-Za-z0-9]+$')]],
router: [null],
orderNum: [10, [Validators.required]],
icon: [null],
leaf: ['0'],
visible: ['1'],
openNewPage: ['0']
});
const menus: any[] = await this.getChildren(null);
this.listOfMapData = menus;
this.reload();
}
reload(): void {
this.listOfMapData.forEach(item => {
this.mapOfExpandedData[item.id] = this.convertTreeToList(item);
});
}
add(): void {
this.isVisible = true;
this.setParentWithRoot();
}
convertTreeToList(root: any): any[] {
const stack: any[] = [];
const array: any[] = [];
const hashMap = {};
stack.push({ ...root, level: 0, expand: false, haveChild: (root.haveChild > 0 ? true : false) });
while (stack.length !== 0) {
const node = stack.pop()!;
this.visitNode(node, hashMap, array);
if (node.children) {
for (let i = node.children.length - 1; i >= 0; i--) {
stack.push({ ...node.children[i], level: node.level! + 1, expand: false, parent: node });
}
}
}
return array;
}
visitNode(node: any, hashMap: { [id: string]: boolean }, array: any[]): void {
if (!hashMap[node.id]) {
hashMap[node.id] = true;
array.push(node);
}
}
async getChildren(parentId: string) {
let parentIdCondition: string;
if (parentId === '' || parentId === null || parentId === undefined) {
parentIdCondition = 'parentId=';
} else {
parentIdCondition = 'parentId=' + parentId;
this.page = 1;
this.pageSize = 9999;
}
const url = `api/menu/list/by/parentId?page=${this.page}&pageSize=${this.pageSize}&${parentIdCondition}`;
try {
const res: any = await this.globalService.axios.get(url);
return res.data.list;
} catch (e) {
alert(JSON.stringify(e));
}
}
async submitForm() {
for (const i in this.validateForm.controls) {
this.validateForm.controls[i].markAsDirty();
this.validateForm.controls[i].updateValueAndValidity();
}
if (this.validateForm.valid) {
let submitData: any = this.validateForm.getRawValue();
submitData = { ...submitData, code: (this.codePrefix + submitData.code) };
const res = await this.globalService.axios.post('api/menu/edit', submitData);
if (res.data.success === true) {
this.isVisible = false;
this.validateForm.reset();
//刷新表格数据
const parentId = submitData.parentId;
//新增根目录数据
let editMenu: any = res.data.item;
if (parentId === null || parentId === '' || parentId === undefined) {
this.listOfMapData = [editMenu, ...this.listOfMapData];
this.listOfMapData.forEach(item => {
if (!this.mapOfExpandedData[item.id]) {
this.mapOfExpandedData[item.id] = this.convertTreeToList(item);
}
});
} else {
//新增子目录数据
editMenu = { ...editMenu, haveChild: false, level: (this.parentMenu.level! + 1), expand: false, parent: this.parentMenu };
const index = this.currentArray.findIndex((item) => item.id === this.parentMenu.id);
//设置父节点包含子节点
//当节点未打开时,打开节点!!这句很重要
if(!this.parentMenu.expand){
this.parentMenu = { ...this.currentArray[index], haveChild: true, expand: true };
}
const chidlren: any[] = this.parentMenu['children'] ? this.parentMenu['children'] : [];
chidlren.push(editMenu);
this.parentMenu['children'] = chidlren;
editMenu = { ...editMenu, parent: this.parentMenu };
this.currentArray.splice(index + 1, 0, editMenu);
this.currentArray[index] = this.parentMenu;
// this.mapOfExpandedData[this.rootId] = array;
}
this.globalService.showSuccess();
} else {
this.globalService.showFail();
}
}
}
handleCancelMiddle(): any {
this.isVisible = false;
this.validateForm.reset();
}
getParent(): void {
return;
}
setParentWithRoot(): void {
this.validateForm.controls['parentId'].reset();
this.validateForm.controls['parentName'].setValue('/');
}
setCode(code): void {
this.validateForm.controls['code'].setValue(code);
}
addSubMenu(menu: any, array: any[], rootId: string): void {
this.isVisible = true;
this.validateForm.controls['parentName'].setValue(menu.name);
this.validateForm.controls['parentId'].setValue(menu.id);
this.codePrefix = menu.code + ':';
this.rootId = rootId;
this.parentMenu = menu;
this.currentArray = array;
}
async deleteMenu(menu, rootId) {
const res = await this.globalService.axios.get('api/menu/delete/' + menu.id);
if (res.data.success === true) {
//刷新表格
if (menu.id === rootId) {
delete this.mapOfExpandedData[rootId];
//
const rootIndex = this.listOfMapData.findIndex(item => item.id === rootId);
this.listOfMapData.splice(rootIndex, 1);//清除列表中的数据
} else {
const array = this.mapOfExpandedData[rootId];
const index = array.findIndex((item) => item.id === menu.id);
array.splice(index, 1);
const parentIndex: number = array.findIndex(item => item.id === menu.parentId);
let thizParent: any = array[parentIndex];
const parentChildrenIndex = thizParent.children.findIndex(item => item.id === menu.id);
thizParent.children.splice(parentChildrenIndex, 1);
if (thizParent.children.length <= 0) {//设置父节点的可删除条件
thizParent = { ...thizParent, haveChild: false };
}
array[parentIndex] = thizParent;
this.mapOfExpandedData[rootId] = array;
//当所有子节点删完之后,更改唯一父节点的是否有子节点状态,让其变得可以删除
// if (array.length === 1) {
// this.mapOfExpandedData[rootId] = [{ ...array[0], haveChild: false }];
// }
}
this.globalService.showSuccess();
} else {
this.globalService.showFail();
}
}
editMenu(menu): void {
const menuCode: string = menu.code;
this.codePrefix = menuCode.substr(0, menuCode.lastIndexOf(':'));
this.isVisible = true;
if (menu['parent']) {
this.validateForm.controls['parentName'].setValue(menu.parent.name);
this.validateForm.controls['parentId'].setValue(menu.parent.id);
} else {
this.validateForm.controls['parentName'].setValue('/');
}
const menuArray: string[] = menuCode.split(':');
menu = {
...menu, leaf: menu.leaf + '', visible: menu.visible + '',
openNewPage: menu['openNewPage'] ? menu.openNewPage + '' : '0',
code: menuArray[menuArray.length - 1]
};
this.validateForm.patchValue(menu);
}
}
1,以上是组件代码。
名称
编码
菜单图标
是否显示
排序
操作
{{ item.name }}
{{item.id}}
添加子菜单
编辑
删除
2,以上是html代码
3,环境版本
4,描述
整体思路在antd官方文档中map数据的格式,围绕着该格式修改数据即可。public mapOfExpandedData: { [key: string]: any[] } = {};
其他的可自由发挥。另ajax框架我用的是axios,以前搞react的时候用惯了。关于后面我业务上的模块会继续完成,框架调好后迫不及待的发个博客。
5,捣鼓这个完全是因为武汉肺炎期间闲的蛋疼。
6,效果视频__
https://v.youku.com/v_show/id_XNDU1MTc1NTYxMg==.html
Google Chrome 2020