import { Component, OnInit, OnDestroy, Input, ElementRef, Output, EventEmitter, ViewChild } from '@angular/core'; import { CmMenuTreeService } from './cmMenuTree.service'; import { Subscription } from 'rxjs/Subscription'; import { RadioValue } from './menuView/radio'; import { CmMessageService } from '../../../components/cosmos.module'; import { NzNotificationService } from 'ng-zorro-antd'; import { Subject } from 'rxjs/Subject'; @Component({ selector: 'cm-menu-tree', templateUrl: './cmMenuTree.component.html', styleUrls: ['./cmMenuTree.component.less'] }) export class cmMenuTreeComponent implements OnInit { _cmHasChecked: boolean = true;//是否有多选框 _cmHasShow: boolean = true;//是否有下拉菜单 noData: boolean = false;//数据是否为空 isVisible: boolean = false;//控制modal显示隐藏 subscription: Subscription;//监听事件 _cmHasRadio: boolean = false;//是否是单选框 _cmHasEllips: boolean = true;//是否有省略号 _cmHasMenu: boolean = true;//是否菜单项 moveThisFile: any;//要移动的文件 radioThisFile: any;//单选选中的文件 fatherFile: any; //移动文件的父级容器 radioFather: any;//选中单选框的父级容器 private treeData: any[] = null;//存放菜单数据 private treeMenu: any[] = null;//存放菜单项数据 check: boolean = true; _hasSelect:boolean = true; title: any; // 树状菜单数据 _cmData: any = [ { "id": "1", "content": "总目录", "show": true,//默认展开 "ellipsisShow": false, "menuShow": false, "checked": false, "radio": false, "readonly": true, "select": true, "children": [ { "id": "2", "content": "文件夹1", "show": true, "ellipsisShow": false, "menuShow": false, "checked": false, "radio": false, "readonly": true, "select": false, "children": [ { "id": "4", "content": "文件1", "show": true, "ellipsisShow": false, "menuShow": false, "checked": false, "radio": false, "readonly": true, "select": false, "children": [], }, { "id": "5", "content": "文件2", "show": true, "ellipsisShow": false, "menuShow": false, "checked": false, "radio": false, "readonly": true, "select": false, "children": [], } ] }, { "id": "3", "content": "文件夹2", "show": true, "ellipsisShow": false, "checked": false, "radio": false, "readonly": true, "select": false, "children": [ { "id": "6", "content": "文件1", "show": true, "ellipsisShow": false, "menuShow": false, "checked": false, "radio": false, "readonly": true, "select": false, "children": [], }, { "id": "7", "content": "文件2", "show": true, "ellipsisShow": false, "menuShow": false, "checked": false, "radio": false, "readonly": true, "select": false, "children": [], } ] } ] } ] // 右键菜单项数据 _cmMenu: any = [ { value: '新增文件', label: 'create', disabled: false }, { value: '删除文件', label: 'delete', disabled: false }, { value: '编辑文件', label: 'update', disabled: false }, { value: '移动文件', label: 'move', disabled: false } ] @Input() set cmHasChecked(cmHasChecked: any) { this._cmHasChecked = cmHasChecked; }; @Input() set cmHasEllips(cmHasEllips: any) { this._cmHasEllips = cmHasEllips; }; @Input() set cmHasMenu(cmHasMenu: any) { this._cmHasMenu = cmHasMenu; }; @Input() set cmHasShow(cmHasShow: any) { this._cmHasShow = cmHasShow; }; @Input() set cmData(cmData: any) { this._cmData = cmData; }; @Input() set cmMenu(cmMenu: any) { this._cmMenu = cmMenu; }; @Output() ondataChange = new EventEmitter(); @Output() createMenu = new EventEmitter(); @Output() clickItems = new EventEmitter(); // 改变数据 vote(data: any) { this.ondataChange.emit(data) } // 增加菜单项 vote1(obj: any) { this.createMenu.emit(obj) } // 点击树状 vote2(select: any) { this.clickItems.emit(select) } constructor( private cmMenuTreeService: CmMenuTreeService, private _notification: NzNotificationService ) { this.treeData = this.deepCopy(this._cmData); this.subscription = this.cmMenuTreeService.missiondisabled$.subscribe((value: any) => { this.check = value; // console.log(this.check); }); this.subscription = this.cmMenuTreeService.missionGrabble$.subscribe((obj: any) => { this.moveThisFile = obj.select; this.radioThisFile = obj.select; this.fatherFile = obj.data; this.moveFile(obj.select, this._cmData) }); this.subscription = this.cmMenuTreeService.missiongetRadio$.subscribe((radio: any) => { this.getRadio(radio, this._cmData); }); this.subscription = this.cmMenuTreeService.missiondataChange$.subscribe((obj: any) => { obj["data"] = this._cmData; this.treeData = this.deepCopy(this._cmData); this.vote(obj); }); this.subscription = this.cmMenuTreeService.missionclickItems$.subscribe((select: any) => { let obj = {}; obj['type'] = 'click'; obj['select'] = select; obj['data'] = this._cmData; this.clickItem(select, this._cmData) this.vote2(obj); }); this.subscription = this.cmMenuTreeService.missioncreateMenu$.subscribe((obj: any) => { obj["data"] = this._cmData; this.vote1(obj); }); } // 点击树状 clickItem(select: any, data: any) { for (var i = 0; i < data.length; i++) { if (data[i].id == select.id) { data[i].select = true; } else { data[i].select = false; } if (data[i].children.length > 0) { this.clickItem(select, data[i].children) } } } ngOnInit() { // this.initSelect(this._cmData) // 过滤菜单项 let arr = []; for (var i = 0, len = this._cmMenu.length; i < len; i++) { if (this._cmMenu[i].disabled == true) { arr.push(i) } } for (let j = 0; j < arr.length; j++) { this._cmMenu.splice(j, 1) } // 空数据处理 if (this._cmData == []) { this.noData = true; } } // 查询 public search(value: string) { let searchText: string = value; this._cmData = this.deepCopy(this.treeData); if (this._cmData && this._cmData.length > 0) { this._cmData.forEach((n: any, i: any, a: any) => { this.searchEach(n, searchText); }); // 没有叶子节点的根节点也要清理掉 let length = this._cmData.length; for (let i = length - 1; i >= 0; i--) { let e2 = this._cmData[i]; if (!this.isHaschildren(e2) && e2.content.indexOf(searchText) <= -1) { this._cmData.splice(i, 1); } } } } // 对子节点进行搜索。 private searchEach(node: any, value: string) { let depth = this.getTreeDepth(node); for (let i = 0; i < depth - 1; i++) { // 记录【删除不匹配搜索内容的叶子节点】操作的次数。 // 如果这个变量记录的操作次数为0,表示树形结构中,所有的 // 叶子节点(不包含只有根节点的情况)都匹配搜索内容。那么就没有必要再 // 在循环体里面遍历树了. let spliceCounter = 0; // 遍历树形结构 this.traverseTree(node, (n: any) => { if (this.isHaschildren(n)) { let children = n.children; let length = children.length; // 找到不匹配搜索内容的叶子节点并删除。为了避免要删除的元素在数组中的索引改变,从后向前循环, // 找到匹配的元素就删除。 for (let j = length - 1; j >= 0; j--) { let e3 = children[j]; if (!this.isHaschildren(e3) && e3.content.indexOf(value) <= -1) { children.splice(j, 1); spliceCounter++; } } // end for (let j = length - 1; j >= 0; j--) } }); // end this.traverseTree(node, n=>{ // 所有的叶子节点都匹配搜索内容,没必要再执行循环体了。 if (spliceCounter == 0) { break; } } } // 判断树形结构中的一个节点是否具有孩子节点 private isHaschildren(node: any) { let flag = false; if (node.children.length > 0) { flag = true; } return flag; } // 通过传入根节点获得树的深度,是 calDepth 的调用者。 private getTreeDepth(node: any) { if (undefined == node || null == node) { return 0; } // 返回结果 let r = 0; // 树中当前层节点的集合。 let currentLevelNodes = [node]; // 判断当前层是否有节点 while (currentLevelNodes.length > 0) { // 当前层有节点,深度可以加一。 r++; // 下一层节点的集合。 let nextLevelNodes = new Array(); // 找到树中所有的下一层节点,并把这些节点放到 nextLevelNodes 中。 for (let i = 0; i < currentLevelNodes.length; i++) { let e = currentLevelNodes[i]; if (this.isHaschildren(e)) { nextLevelNodes = nextLevelNodes.concat(e.children); } } // 令当前层节点集合的引用指向下一层节点的集合。 currentLevelNodes = nextLevelNodes; } return r; } private traverseTree(node: any, callback: Function) { if (!node) { return; } let stack = []; stack.push(node); let tmpNode; while (stack.length > 0) { tmpNode = stack.pop(); callback(tmpNode); if (tmpNode.children.length > 0) { for (let i: number = tmpNode.children.length - 1; i >= 0; i--) { stack.push(tmpNode.children[i]); } } } } //深拷贝 private deepCopy(data: any): any { let json = JSON.stringify(data); return JSON.parse(json); } moveThisFileId: any; // 移动文件 moveFile(select: any, data: any) { let radio = RadioValue.getRadio().getRadioValue(select.id); this.cmMenuTreeService.getRadio(radio) this.isVisible = true; this.title = `请选择把"${select.content}"移动到位置下` for (let i = 0; i < this.fatherFile.length; i++) { if (this.fatherFile[i].id == this.moveThisFile.id) { this.moveThisFileId = i; this.fatherFile.splice(i, 1) } } } // 确认移动 handleOk() { this.radioThisFile.select = false; this.isVisible = false; this.cmMenuTreeService.disabledChange(true); for (let i = 0; i < this.fatherFile.length; i++) { if (this.fatherFile[i].id == this.moveThisFile.id) { this.moveThisFileId = i; this.fatherFile.splice(i, 1); } } if (this.radioThisFile.children.length > 0) { let hasFile = false; for (var i = 0; i < this.radioThisFile.children.length; i++) { if (this.radioThisFile.children[i] == this.moveThisFile) { hasFile = true; } } if (hasFile == false) { this.radioThisFile.children.push(this.moveThisFile) this.cmMenuTreeService.dataChange('move', this.moveThisFile); } } else { for (let i = 0; i < this.radioFather.length; i++) { if (this.radioFather[i].id == this.radioThisFile.id) { this.radioFather.splice(i + 1, 0, this.moveThisFile); this.cmMenuTreeService.dataChange('move', this.moveThisFile); return 0; } } } } // 取消移动 handleCancel() { this.radioThisFile.select = false; this.isVisible = false; this.fatherFile.splice(this.moveThisFileId, 0, this.moveThisFile); } // 选中单选框 getRadio(value: any, data: any) { for (var i = 0; i < data.length; i++) { if (data[i].id == value) { data[i].radio = true; this.radioThisFile = data[i]; this.radioFather = data; } else { data[i].radio = false; } if (data[i].children.length > 0) { this.getRadio(value, data[i].children) } } } }