<div class="tree-content">
<ng-container *ngIf="nodes && nodes.length">
<tree-root #tree (initialized)="onInitialized(tree)" (activate)="onActivate($event)" [nodes]="nodes"
[options]="options" [focused]="false">
<ng-template #treeNodeTemplate let-node let-index>
<div class="has-border tree-item title-row"
[ngClass]="{'click-item-show':node.isChooseStyle == 'show'}">
<div class="flex-1 title-content">
<div *ngIf="!node.data.isEditing" class="title-field" [matTooltipClass]="'toolTip'"
[matTooltip]="node.data.name">
<ng-container *ngIf="node.data.subDirectories && node.data.subDirectories.length">
<img *ngIf="node.isExpanded" src="../../../../../assets/images/kb/dakaiwenjian.png"
class="icon-img" />
<img *ngIf="!node.isExpanded" src="../../../../../assets/images/kb/wenjianji.png"
class="icon-img" />
<span class="p-l-3">{{node.data.name}}</span>
</ng-container>
<ng-container *ngIf="!node.data.subDirectories || !node.data.subDirectories.length">
<span class="p-l-8">{{node.data.name}}</span>
</ng-container>
</div>
<input *ngIf="node.data.isEditing" nz-input [(ngModel)]="node.data.tempalteName"
placeholder="请输入名称后回车确定..." (keyup)="saveCurrentNode(node, $event)"
style="width: 150px;" (blur)="inputBlur(node, $event)">
</div>
<div class="d-flex align-items-center icon-content" *ngIf="!node.data.isEditing" [ngClass]="{
'icon-content-shown': node.data.isEditing == true}">
<i class="show-opt iconfont icon-edit" [matTooltipClass]="'toolTip'" matTooltip="编辑"
(click)="editNode($event, node)">
</i>
<i class="show-opt iconfont icon-delete1" [matTooltipClass]="'toolTip'" matTooltip="删除"
nzType="delete" (click)="handleWithAction('delete', node, index, $event)">
</i>
<a nz-dropdown [nzDropdownMenu]="menu">
<i class="show-opt iconfont icon-plus" *ngIf="node.level < 5"
[matTooltipClass]="'toolTip'" matTooltip="添加子目录" nzType="plus">
</i>
</a>
<nz-dropdown-menu #menu="nzDropdownMenu">
<ul nz-menu nzSelectable>
<li nz-menu-item (click)="handleWithAction('addLevel', node, index, $event)">同级目录
</li>
<li nz-menu-item (click)="handleWithAction('addChild', node, index, $event)">子集目录
</li>
</ul>
</nz-dropdown-menu>
</div>
</div>
</ng-template>
</tree-root>
</ng-container>
<div *ngIf="!nodes || !nodes.length" class="position-relative h-100">
<app-no-data></app-no-data>
</div>
</div>
import { Component, OnInit, Input, Output, EventEmitter, ElementRef, ViewChild } from '@angular/core';
import { ITreeOptions, KEYS, TreeComponent, TreeModel, TreeNode } from '@circlon/angular-tree-component';
import { SnackBarService } from '@core/services/snackbar.service';
import { PersonalKnowledgeService } from '@routes/personal-knowledge/personal-knowledge.service';
import { appUtil } from '@utils';
@Component({
selector: 'app-directory-select',
templateUrl: './directory-select.component.html',
styleUrls: ['./directory-select.component.less'],
})
export class DirectorySelectComponent implements OnInit {
@Input() nodes: any = []; // 数据源级联数组
@Input() selfKbId: any; // 可变化的参数
@Output() clickNode = new EventEmitter(); // 点击节点
@Output() refreshTree = new EventEmitter(); // 点击节点
@ViewChild(TreeComponent, { static: false })
public tree: TreeComponent;
defaultOptions: ITreeOptions = {
displayField: 'name',
isExpandedField: 'expanded',
idField: 'id',
childrenField: 'subDirectories',
actionMapping: {
mouse: {
click: (tree, node, $event) => {
this.clickCurrentNode(tree, node, $event);
},
},
keys: {
[KEYS.ENTER]: (tree, node, $event) => {
if (node) {
node.expandAll();
}
},
},
},
nodeHeight: 30,
allowDrop: (node) => {
return false;
},
allowDrag: (node) => {
return false;
},
animateExpand: true,
scrollOnActivate: true,
animateSpeed: 30,
animateAcceleration: 1.2,
};
options: ITreeOptions;
// 当前是否有文件正在编辑
isNodeEditing: any = false;
preNode; // 上一个选中的节点
currentSelectNode = {
isChooseStyle: 'no',
};
constructor(private snackBar: SnackBarService, private service: PersonalKnowledgeService) {}
ngOnInit() {
this.options = Object.assign({}, this.defaultOptions);
}
/**
* @desc 操作
* @param action - target
* @param node - tree node
* @param index - target
* @param event - 点击事件
*/
handleWithAction(action, node, index, event?) {
if (event) {
event.preventDefault();
event.stopPropagation();
}
switch (action) {
case 'addChild': {
if (this.isNodeEditing) {
this.snackBar.warning('请保存数据!');
return;
}
this.isNodeEditing = true;
this.addChildDictionary(node);
break;
}
case 'addLevel': {
if (this.isNodeEditing) {
this.snackBar.warning('请保存数据!');
return;
}
this.isNodeEditing = true;
this.addLevel(node);
break;
}
case 'delete': {
this.deleteNode(node);
break;
}
}
}
addLevel(node) {
const { data } = node;
let { id, path } = data;
const newNode = {
name: '',
tempalteName: '',
leaf: 0,
enterpriseId: data.enterpriseId,
kbId: data.kbId,
parentId: node.parentId,
path,
hasChildren: false,
isEditing: true,
isExpanded: true,
id: Math.random().toString(32).slice(2, 12),
isNew: true,
subDirectories: [],
};
let saveChild = node.parent.data.subDirectories;
saveChild.push(newNode);
node.parent.data.subDirectories = saveChild;
this.tree.treeModel.update();
}
/**
* 新增子目录
*/
addChildDictionary(node) {
const { data } = node;
let { id, path } = data;
data.hasChildren = true;
const newNode = {
name: '',
tempalteName: '',
leaf: 0,
enterpriseId: data.enterpriseId,
kbId: data.kbId,
parentId: id,
path,
hasChildren: false,
isEditing: true,
isExpanded: true,
id: Math.random().toString(32).slice(2, 12),
isNew: true,
subDirectories: [],
};
// 将 children 赋值给当前节点
let saveChild = data.subDirectories;
if (saveChild && saveChild.length) {
saveChild.push(newNode);
} else {
saveChild = [newNode];
}
node.data.subDirectories = saveChild;
if (!node.isExpanded) {
node.toggleExpanded();
}
this.tree.treeModel.update();
}
/**
* 创建树模型后触发
*/
onInitialized(tree: any) {
// const firstRoot = tree.treeModel.getFirstRoot();
// if (firstRoot) firstRoot.expandAll();
}
/**
* 点击树节点
* @param tree
* @param node
* @param event
*/
clickCurrentNode(tree, node, event) {
if (node && node.data && node.data.isEditing) {
return;
}
if (this.currentSelectNode && this.currentSelectNode.isChooseStyle) {
this.currentSelectNode.isChooseStyle = 'no';
}
node.isChooseStyle = 'show';
this.currentSelectNode = node;
this.clickNode.emit(node);
}
shownAllKb() {
let data = {
showAll: true,
};
this.clickNode.emit(data);
}
/**
* 当前节点
*/
onActivate(event) {
// 如果之前有编辑的节点,先保存
if (this.preNode) {
Object.assign(this.preNode.data, { isEditing: false, tempalteName: this.preNode.data.name });
}
const { node } = event;
if (node && node.data) {
if (!node.data.isEditing) {
// this.knowledgeService.selectDirectory = { id: node.data.id, name: node.data.name }
// this.router.navigate(['directory', node.data.id], { relativeTo: this.activatedRoute })
}
}
}
/**
* 编辑当前节点
* @param node
*/
editNode(event, node) {
event.stopPropagation();
if (this.preNode) {
Object.assign(this.preNode.data, { isEditing: false, tempalteName: this.preNode.data.name });
}
this.preNode = node;
Object.assign(node.data, { isEditing: true, tempalteName: node.data.name });
}
inputBlur(node, event) {
this.saveCurrentNode(node, event, 'blur');
}
/**
* 保存当前修改部分
*/
saveCurrentNode(node, event, action) {
const keycode = event.keyCode ? event.keyCode : event.which;
if (keycode === 13 || action === 'blur') {
if (node && node.data) {
if (!node.data.tempalteName) {
this.snackBar.warning('请输入名称!');
return;
}
const nullPattern = /^[ ]*$/;
if (nullPattern.test(node.data.tempalteName)) {
this.snackBar.warning('请正确输入名称!');
return;
}
if (node.data.tempalteName.length > 30) {
this.snackBar.warning('名称长度超过限制!');
return;
}
this.isNodeEditing = false;
if (node.data.isNew) {
// 当前节点为新增节点
const { kbId, tempalteName, parentId, leaf } = node.data;
this.service.addDirectories(appUtil.filterParams({ kbId, name: tempalteName, parentId, leaf })).subscribe(
(res) => {
if (res && res.status === 200) {
node.data.isNew = false;
node.data.id = res.result.result;
node.data.name = tempalteName;
node.data.isEditing = false;
node.data.hasChildren = false;
node.treeModel.update();
}
},
(error) => {},
);
} else {
// 当前节点为已有节点
const { tempalteName, id, parentId, kbId, leaf } = node.data;
const params = Object.assign({ name: tempalteName, id, parentId, kbId, leaf });
this.service.updateDirectories(id, params).subscribe((res) => {
if (res && res.status) {
node.data.name = tempalteName;
node.data.isEditing = false;
node.treeModel.update();
}
});
}
}
}
}
/**
* 删除当前节点
* @param node
*/
deleteNode(node: TreeNode): void {
if (node && node.data) {
const { id, isEditing, isNew } = node.data;
if (isNew) {
this.isNodeEditing = false;
// 当前节点为新增节点
if (node.parent && node.parent.data) {
if (node.parent.data.children.length) {
node.parent.data.children.pop();
this.tree.treeModel.update();
}
}
return;
}
if (!isNew && isEditing) {
this.snackBar.warning('当前节点正在编辑,无法删除!');
return;
}
if (this.nodes.length === 1) {
this.snackBar.warning('当前只剩下最后一个目录,删除后会导致无法使用,删除失败');
return;
}
this.service.deleteDirectories(id).subscribe(
(res) => {
if (res && res.status === 200) {
if (node.parent != null) {
node.parent.data.subDirectories.splice(node.parent.data.subDirectories.indexOf(node.data), 1);
this.tree.treeModel.update();
}
}
},
(error) => {},
);
}
}
}