1、SystemTreeItem.vue
:data="treeData" node-key="id" default-expand-all :expand-on-click-node="false" @node-drop="handleDrop" @node-drag-enter="nodeDragEnter" draggable :allow-drop="allowDrop" :allow-drag="allowDrag" > {{ node.data.knowledgeName }} {{ "(已禁用)" + node.data.knowledgeName }} 添加同级 | 添加下级 | 查看详情 | 删除
import { debounce } from '@/utils/comUtil'
export default {
name: 'systemTreeItem',
data() {
return {
knowledgeCode: '',
}
},
props: {
treeData: Array,
canStatusChange: Boolean
},
directives: {
focus: {
inserted: function(el) {
el.querySelector("input").focus();
}
}
},
methods: {
addKnoeledgeCode(node,data){
this.$emit('addKnoeledgeCode',node,data,this.knowledgeCode)
this.knowledgeCode = ""
},
// 拖拽成功完成时触发的事件
handleDrop(draggingNode, dropNode, dropType, e) {
this.$emit('handleDrop', draggingNode, dropNode, dropType, e)
},
// 获取总层级数
getTotalLevel(node, arr) {
if (node.childNodes && node.childNodes.length) {
node.childNodes.forEach(item => {
arr.push(item.level)
if(item.childNodes && node.childNodes.length) {
this.getTotalLevel(item, arr)
}
})
}else{
arr.push(node.level)
}
},
// 拖拽进入其他节点时触发的事件
nodeDragEnter(draggingNode, dropNode){
// console.log("拖拽进入其他节点时触发的事件",draggingNode, dropNode)
let arr = []
this.getTotalLevel(draggingNode, arr)
const totalLevel = Math.max(...arr) - draggingNode.level + 1 + dropNode.level
if(totalLevel <= 8) return
this.banMessag();
arr = []
},
banMessag: debounce(function(){
this.$message({
type: 'warning',
message: '节点层级已达最大值!',
})
},500),
// 拖拽时判定目标节点能否被放置
allowDrop(draggingNode, dropNode, type) {
//draggingNode 被拖拽的节点
//dropNode 目标节点
//type 参数有三种情况:'prev'、'inner' 和 'next',分别表示放置在目标节点前、插入至目标节点和放置在目标节点后
// console.log(draggingNode.level, dropNode.level, type)
// 获取被拖拽的节点层级
let arr = []
this.getTotalLevel(draggingNode, arr)
const totalLevel = Math.max(...arr) - draggingNode.level + 1 + dropNode.level
// 插入至目标节点内部 节点层级大于8级 不能被放置
if(totalLevel > 8){
this.banMessag();
arr = []
return false
}else{
return true;
}
},
// 判断节点能否被拖拽
allowDrag(draggingNode) {
// console.log("allowDrag", draggingNode)
// 节点处于编辑状态 或者 节点为空节点 不能拖拽
if(draggingNode.data.isEdit || !draggingNode.data.id){
return false
}else{
return true
}
},
// 节点双击事件 节点变为可编辑状态
nodeClick(data, node, isEdit) {
if(isEdit === false){
this.knowledgeCode = ""
}
this.$emit('nodeClick', data, node, isEdit)
},
// 添加同级
insertAfter(data, refNode) {
this.$emit('insertAfter', data, refNode)
},
// 添加下级
append(data, parentNode) {
this.$emit('append', data, parentNode)
},
toDetail(data) {
this.$emit('toDetail', data)
},
remove(node, data) {
this.$emit('remove', node, data)
},
},
}
2、SystemTree.vue
拖拽涉及代码是:handleDrop
:treeData="systemTreeList" :canStatusChange="canStatusChange" @handleDrop="handleDrop" @nodeClick="nodeClick" @insertAfter="insertAfter" @append="append" @toDetail="toDetail" @remove="remove" @addKnoeledgeCode="addKnoeledgeCode" /> import systemTreeService from '@/api/systemTreeService' import SystemTreeItem from './components/SystemTreeItem.vue' export default { name: 'SystemTree', components: { SystemTreeItem }, data() { return { systemTreeList: [], // 体系树列表 list: [], // 备份体系树列表数据 canStatusChange: false //禁用/启用是否可切换 体系树无数据,节点处于编辑状态,节点无id 为false } }, created() { this.getSystemTreeList() }, methods: { // 体系树数据排序 sortTreeData(arr){ if(!arr.length) return arr.sort((a,b) => a.sort - b.sort) arr.forEach(item => { if(item.children){ this.sortTreeData(item.children) } }) }, // 获取体系树列表 async getSystemTreeList(type) { if(!this.systemCode) return if (type === 'add') { this.systemTreeList = [ { id: '', knowledgeCode: '', knowledgeName: '', parentId: 'ROOT', level: 1, systemCode: this.systemCode, isEdit: true, enabled: true, children: [] }, ] } else { let res = await systemTreeService.getSystemTreeList({ systemCode: this.systemCode }) if (res && res.errorCode === 0) { this.systemTreeList = res.result // 后端返回的数据为树状结构 this.sortTreeData(this.systemTreeList) // 备份原数据 拖拽失败后还原 this.list = JSON.parse(JSON.stringify(this.systemTreeList)) if(this.systemTreeList.length){ this.canStatusChange = true }else{ this.systemTreeList = [ { id: '', knowledgeCode: '', knowledgeName: '', parentId: 'ROOT', level: 1, systemCode: this.systemCode, isEdit: true, enabled: true, children: [] }, ] this.canStatusChange = false } } else { this.systemTreeList = [] this.canStatusChange = false } } }, // 添加知识点 async addKnoeledgeCode(node, data, knowledgeCode) { // console.log("添加知识点", node, data) node.data.isEdit = false data.isEdit = false if (knowledgeCode) { if(data.id){ // 替换 // 如果knowledgeCode等于oldKnowledgeCode let oldKnowledgeCode = data.knowledgeCode if(knowledgeCode === oldKnowledgeCode){ this.$message({ type: 'warning', message: '当前knowledgeCode与旧knowledgeCode相同,不能替换!' }) return } let params = { systemCode: this.systemCode, nodeId: data.id, oldKnowledgeCode, newKnowledgeCode: knowledgeCode, } let res = await systemTreeService.updateKnowledgePoint(params) if (res && res.errorCode === 0) { this.$message({ type: 'success', message: res.errorInfo, }) } }else{ // 新增 添加同级 添加下级 // 添加同级 若为一级节点 nodeParentId 为 "", 否则为node.parent.data.id let nodeParentId = node.level === 1 ? "" : node.parent.data.id let params = { systemCode: this.systemCode, knowledgeCode, nodeParentId, } let res = await systemTreeService.addKnowledgePoint(params) if (res && res.errorCode === 0) { this.$message({ type: 'success', message: res.errorInfo, }) } } this.getSystemTreeList() } }, // 拖拽事件 async handleDrop(draggingNode, dropNode, dropType,e) { //draggingNode 被拖拽的节点 //dropNode 目标节点 //dropType 类型 被拖拽的节点相对于目标节点的位置 inner before after // console.log('tree drop', draggingNode, dropNode, dropType) // 难点在于获取受影响的节点,然后遍历,后端根据节点ID修改父节点ID以及sort let paramData = []; // 当拖拽类型不为inner,同级排序,寻找目标节点的父ID,获取其对象以及所有的子节点 // 当拖拽类型为inner,说明拖拽节点成为了目标节点的子节点,只需获取目标节点对象 let data = dropType != "inner" ? dropNode.parent.data : dropNode.data; //目标节点为一级节点,并且拖拽类型不为inner即当前节点将成为与目标节点同一级的节点,也是一级节点 //nodeData=dropNode.parent.data,但是因为目标节点已经是一级节点了,因此nodeData还是目标节点 //目标节点为一级节点,并且拖拽类型为inner即当前节点将成为目标节点的子节点即二级节点 //nodeDate=dropNode.parent.data.children,即为目标节点的父节点的子节点,即目标节点同一层级的节点 //目标节点不是一级节点,并且拖拽类型不为inner即当前节点将成为与目标节点同一层级的节点 //nodeDate=dropNode.parent.data.children,即为目标节点的父节点的子节点,即目标节点同一层级的节点 //目标节点不是一级节点,并且拖拽类型为inner即当前节点将成为目标节的子节点 //nodeDate=dropNode.data.children,即目标节点的子节点 let nodeData = dropNode.level == 1 && dropType != "inner" ? data : data.children; let nodeParentId = "" nodeData.forEach((item, i) => { if(dropType != "inner"){ if(draggingNode.data.parentId === dropNode.data.parentId){ nodeParentId = item.parentId }else{ nodeParentId = dropNode.data.parentId } }else{ nodeParentId = data.id } let collection = { nodeId: item.id, nodeParentId, sort: i + 1 }; paramData.push(collection); }); // console.log(paramData) let params = { systemCode: this.systemCode, nodeSortList: paramData } let res = await systemTreeService.dragTreeNode(params) if(res && res.errorCode === 0){ this.$message({ type: 'success', message: res.errorInfo, }) this.getSystemTreeList() }else{ // 接口报错之后,将数据恢复 this.systemTreeList = this.list } }, // 节点双击事件 nodeClick(data, node, isEdit) { // console.log("nodeClick",data,node,isEdit) // 当节点处于编辑状态 或者 节点id不存在 if(isEdit || !data.id){ this.canStatusChange = false }else{ this.canStatusChange = true } this.$set(data,'isEdit',isEdit) this.$set(node.data,'isEdit',isEdit) }, // 添加同级 insertAfter(data, refNode) { // console.log("添加同级", data, refNode) const newNode = { parentId: data.parentId, id: '', knowledgeCode: '', knowledgeName: '', level: data.level, systemCode: this.systemCode, isEdit: true, enabled: true, children: [], } this.canStatusChange = false if(data.parentId === 'ROOT'){ refNode.parent.data.push(newNode) }else{ refNode.parent.data.children.push(newNode) } }, //添加下级 append(data, parentNode) { // console.log('添加下级', data) if (data.level >= 8) { this.$message({ type: 'warning', message: '节点层级已达最大值!', }) return } else { const newChild = { parentId: data.id, id: '', knowledgeCode: '', knowledgeName: '', level: data.level + 1, systemCode: this.systemCode, isEdit: true, enabled: true, children: [], } this.canStatusChange = false if (!data.children) { this.$set(data, 'children', []) } data.children.push(newChild) } } } } 好文推荐
发表评论