<el-tree
class="filter-tree"
:data="treeList"
:props="defaultProps"
:filter-node-method="filterNode"
:highlight-current="true"
:expand-on-click-node="false"
ref="tree"
:key="reload"
node-key="treeId"
:draggable="true"
:allow-drop="allowDrop"
@node-drop="handleDrop"
:default-expand-all="false"
:default-expanded-keys="defaultExpandedKeys"
@node-expand="getNodeExpand"
@node-collapse="getNodeCollapse"
>
<template #default="{ node, data }">
<div class="node-item">
<span v-if="data.indexId == 0 || data.isRename">
<el-input
v-model.trim="data.label"
placeholder="请输入"
@blur="changeFolder(node, data)"
:disabled="!data.isRename && data.type == 2"
maxlength="30"
></el-input>
</span>
<div v-else @click="handleNodeClick(data)" class="label-set">
<label>
<i v-if="data.type === 1" class="el-icon-folder-opened"></i>
<i
v-else-if="data.type === 2"
class="el-icon-notebook-2"
></i>
<i v-else class="el-icon-document"></i
></label>
<label v-if="!ifCollapse">{{ data.label }}</label>
</div>
<el-popover placement="bottom" width="200" trigger="click">
<div
style="
display: flex;
flex-direction: column;
align-items: baseline;
"
>
<el-button
v-if="data.type == 1"
type="text"
v-no-more-click
@click="addChildDirectory(node, data)"
>文件夹</el-button
>
<el-button
v-if="data.type == 1"
type="text"
v-no-more-click
@click="addChildrenForm(node, data)"
>表单</el-button
>
<el-button
type="text"
v-no-more-click
@click="handleRename(node, data, true)"
>重命名</el-button
>
</div>
<i
v-if="isUpdate"
slot="reference"
class="el-icon-circle-plus-outline show-btn"
></i>
</el-popover>
</div>
</template>
</el-tree>
watch: {
filterText(val) {
this.$refs.tree.filter(val);
}
},
data() {
return {
ifCollapse: false,
filterText: '',
treeList: [],
defaultProps: {
children: 'children',
id: 'treeId'
},
isUpdate: 0, //是否有权限,主要为管理员1,非管0
isShow: false,
reload: 0,
folderId: null,
defaultExpandedKeys: [],
allCollectionInfo: []
};
},
//节点被展开时触发的事件
getNodeExpand(data, node, event) {
let keyId = data.type + '' + data.indexId;
this.defaultExpandedKeys.push(keyId);
},
getAllTreeId(data, treeIdArr) {
treeIdArr.push(data.treeId);
if (data.children && data.children.length > 0) {
for (let n in data.children) {
let item = data.children[n];
this.getAllTreeId(item, treeIdArr);
}
}
},
getNodeCollapse(data, node, event) {
let treeIdArr = [];
this.getAllTreeId(data, treeIdArr);
treeIdArr.forEach((treeId) => {
let arr = JSON.parse(JSON.stringify(this.defaultExpandedKeys));
this.defaultExpandedKeys = arr.filter((item) => item != treeId);
});
},
// 筛选
filterNode(value, data, node) {
if (!value) return true;
let _array = []; //这里使用数组存储 只是为了存储值。
this.getReturnNode(node, _array, value);
let result = false;
_array.forEach((item) => {
result = result || item;
});
return result;
},
getReturnNode(node, _array, value) {
let isPass =
node.data && node.data.label && node.data.label.indexOf(value) !== -1;
isPass ? _array.push(isPass) : '';
if (!isPass && node.level != 1 && node.parent) {
this.getReturnNode(node.parent, _array, value);
}
},
// 拖拽成功完成时触发的事件
async handleDrop(draggingNode, dropNode, dropType, ev) {
// 对treeData中的每一个节点调用上面的函数
// for (let index in this.treeList) {
// let child = this.treeList[index];
// this.sortAllNode(child, index);
// }
let res = await reSort({ folderList: this.treeList });
// 刷新目录
this.configurationList();
},
allowDrop(draggingNode, dropNode, type) {
// 当拖动类型为平级移动到前或者后
if (this.isUpdate === 1) {
if (type === 'prev' || type === 'next') {
if (draggingNode.data.type === 1 || draggingNode.data.type === 2) {
if (dropNode.data.type !== 3) {
return true;
}
} else if (draggingNode.data.type === 3) {
if (
dropNode.data.type === 3 &&
draggingNode.data.parentId === dropNode.data.parentId
) {
return true;
}
}
// 当拖动类型为拖入内部
} else if (type === 'inner') {
if (draggingNode.data.type === 1 || draggingNode.data.type === 2) {
if (dropNode.data.type === 1) {
return true;
}
}
}
}
return false;
},
changeIsRename(data, keyStr, value) {
let key = data.type + '' + data.indexId; // 当前点击的节点ID ,唯一标志
// 检查当前节点的ID是否与目标ID匹配
if (key === keyStr) {
// 如果匹配,将新数据添加到该节点的children数组中
this.$set(data, 'isRename', value);
return;
}
// 如果当前节点有子节点,则递归遍历子节点
if (data.children && data.children.length > 0) {
for (let child of data.children) {
this.changeIsRename(child, keyStr, value);
}
}
},
// 点击重命名按钮
handleRename(node, data, value) {
let keyStr = data.type + '' + data.indexId; // 当前点击的节点ID ,唯一标志
// 对treeData中的每一个节点调用上面的函数
for (let data of this.treeList) {
this.changeIsRename(data, keyStr, value);
}
// 记录展开的节点
// 改变数据时更新树
this.reload = Math.random();
let parentType = '';
if (data.type === 1) {
parentType = 1;
} else if (data.type === 2) {
parentType = 1;
} else if (data.type === 3) {
parentType = 2;
}
this.defaultExpandedKeys = [parentType + '' + data.parentId];
},
// 修改文件夹(名字)
async rename(node, data) {
let params = {
indexId: data.indexId,
label: data.label,
type: data.type
};
let res = await rename(params);
if (data.type != 1) {
this.isShow = true;
this.$nextTick(() => {
// isShow控制了子组件的显示和隐藏,所以需要加一个nexttick
this.$refs.rightCom.$emit('handleNodeClick', data); //调用子组件在点击目录时获取子组件的数据
});
}
},
// 添加文件夹
async addFolder(node, data) {
let params = {
folderName: data.label,
parentId: data.parentId,
folderOrder: data.folderOrder
};
let res = await addFolder(params);
},
hasWhiteSpace(s) {
return /\s/g.test(s);
},
// 输入框失焦
async changeFolder(node, data) {
if (!this.hasWhiteSpace(data.label)) {
if (data.indexId) {
await this.rename(node, data);
} else {
await this.addFolder(node, data);
}
await this.configurationList();
await this.handleRename(node, data, false);
// this.$nextTick(() => {
// // 新增时展开改文件夹
// this.$refs.tree.store.nodesMap[data.treeId].expanded = true;
// });
} else {
this.$message.warning('不能输入空格');
}
},
async configurationList(value) {
const res = await configurationList();
this.treeList = res.data.folderList;
this.allCollectionInfo = JSON.parse(JSON.stringify(res.data.folderList));
// isRename
this.isUpdate = res.data.isUpdate;
localStorage.setItem('isUpdate', this.isUpdate);
function addIsRenameProperty(nodes) {
nodes.forEach((node) => {
node.isRename = false; // 初始化时设为false
// 为每个节点做一个唯一值
node.treeId = node.type + '' + node.indexId;
if (node.children) {
addIsRenameProperty(node.children); // 递归处理子节点
}
});
}
// 对初始数据执行添加isRename属性的操作
addIsRenameProperty(this.treeList);
this.$nextTick(() => {
value && this.defaultExpandedKeys.push(value);
this.defaultExpandedKeys = Array.from(
new Set(this.defaultExpandedKeys)
);
});
},
// filterNode(value, data) {
// if (!value) return true;
// return data.label.indexOf(value) !== -1;
// },
handleCollapse() {
this.ifCollapse = !this.ifCollapse;
},
handleNodeClick: debounce(function (data) {
//默认展开的节点清空,当添加的时候才会赋值
// this.defaultExpandedKeys = [];
this.folderId = data.parentId ? data.parentId : 0;
if (data.type != 1) {
this.isShow = true;
this.$nextTick(() => {
// isShow控制了子组件的显示和隐藏,所以需要加一个nexttick
this.$refs.rightCom.$emit('handleNodeClick', data); //调用子组件在点击目录时获取子组件的数据
});
}
}, 1000),
// 点击左侧加号添加表单,
addForm() {
// 左侧出现输入框文件夹
this.folderId = null;
const newNode = {
id: '',
folderName: '',
type: 2,
order: '',
label: '未命名表单',
indexId: 0,
parentId: '',
children: [],
folderOrder: this.treeList.length
}; // 创建新节点对象
this.treeList.unshift(newNode);
// 右侧表单界面出现
this.addRightForm();
},
// 右侧表单界面出现
addRightForm() {
this.isShow = true;
this.$nextTick(() => {
this.$refs.rightCom.addForm(); // 调用子组件在新建时清理子组件的数据
});
},
addDirectory() {
this.folderId = null;
const newNode = {
id: '',
folderName: '',
type: 1,
order: '',
label: '未命名文件夹',
indexId: 0,
parentId: '',
children: [],
folderOrder: this.treeList.length
}; // 创建新节点对象
this.treeList.unshift(newNode);
},
addNode(parentNode, data) {
const childNodes = parentNode.data.children;
childNodes.push(data);
// this.$forceUpdate(); // 强制重新渲染组件,使新节点生效
},
// 目录内部添加表单
addChildrenForm(node, data) {
this.folderId = data.id ? data.id : 0;
// 右侧出现新表单页面相关代码
this.addRightForm();
// 左侧出现输入框相关代码
let keyStr = data.type + '' + data.indexId; // 当前点击的节点ID ,唯一标志
const newNode = {
// id: Date.now(),
folderName: '',
type: 2,
order: '',
label: '未命名表单',
indexId: 0,
children: []
}; // 创建新节点对象 // 新的子节点数据
// 对treeData中的每一个节点调用上面的函数
for (let data of this.treeList) {
this.findNodeAndAddChild(data, keyStr, newNode);
}
this.$nextTick(() => {
// // 新增时展开改文件夹
this.$refs.tree.store.nodesMap[data.treeId].expanded = true;
});
},
expandTreeNode(node, resolve) {
// if (node.level === 0) {
// return resolve(node.data);
// }
// if (node.data.childGetFlag === 0) {
// // 未取得子节点
// // 此处自定义取得方法;
// } else {
// // 已取得子节点
// return resolve(node.data.children);
// }
},
expandNode(node) {
if (node.data.children.length === 0) {
node.isLeaf = true; // 对于叶子节点,点击小三角后,小三角会消失。
}
node.expanded = true; // 展开节点
node.loaded = true; // 标识:已加载
},
// 目录内部添加文件夹
addChildDirectory(node, data) {
// 展开当前节点
let keyStr = data.type + '' + data.indexId; // 当前点击的节点ID ,唯一标志
let newNode = {
id: '',
folderName: '',
type: 1,
order: '',
label: '未命名文件夹',
indexId: 0,
parentId: data.id,
children: [],
folderOrder:
data.children && data.children.length ? data.children.length : 0
}; // 创建新节点对象 // 新的子节点数据
// 对treeData中的每一个节点调用上面的函数
for (let itemData of this.treeList) {
this.findNodeAndAddChild(itemData, keyStr, newNode);
}
// this.expandNode(node);
this.$nextTick(() => {
// 重命名时展开改文件夹
this.$refs.tree.store.nodesMap[data.treeId].expanded = true;
});
// this.reload = Math.random();
},
findNodeAndAddChild(data, keyStr, newNode) {
let key = data.type + '' + data.indexId; // 当前点击的节点ID ,唯一标志
// 检查当前节点的ID是否与目标ID匹配
if (key === keyStr) {
// 如果匹配,将新数据添加到该节点的children数组中
data.children = data.children ? data.children : [];
data.children.push(newNode);
return;
}
// 如果当前节点有子节点,则递归遍历子节点
if (data.children && data.children.length > 0) {
for (let child of data.children) {
this.findNodeAndAddChild(child, keyStr, newNode);
}
}
}