1、SystemTreeItem.vue
<el-tree
: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"
>
<span class="custom-tree-node" :class="{isDisabled: node.data.enabled === false}" slot-scope="{ node, data }" :key="data.id">
<template v-if="!node.data.isEdit">
<el-tooltip class="item" effect="light" :content="node.data.knowledgeName" :open-delay="1000" placement="bottom">
<span class="label" v-if="node.data.enabled" @dblclick="nodeClick(data,node,true)">{{ node.data.knowledgeName }}</span>
<span class="label isDisabled" v-else-if="node.data.id && !node.data.enabled" @dblclick="nodeClick(data,node,true)">{{ "(已禁用)" + node.data.knowledgeName }}</span>
</el-tooltip>
</template>
<span class="knowledgeCode" v-else-if="node.data.isEdit && hasAuth('knowledge_points_system_edit')">
<el-input v-model.trim="knowledgeCode" placeholder="请输入知识点code" v-focus />
<el-button size="mini" type="primary" :disabled="!knowledgeCode" @click="addKnoeledgeCode(node,data)">确 定</el-button>
<el-button size="mini" @click="nodeClick(data,node,false)">取 消</el-button>
</span>
<span class="operation" v-show="!node.data.isEdit">
<el-button type="text" class="btn" :disabled="!canStatusChange || !node.data.id" @click="insertAfter(data, node)" style="color: #333">
添加同级
</el-button>
<span>|</span>
<el-button type="text" class="btn" :disabled="!canStatusChange || !node.data.id" @click="append(data, node)" style="color: #333">
添加下级
</el-button>
<span>|</span>
<el-button type="text" class="btn" :disabled="!node.data.id" @click="toDetail(data)" style="color: #333">
查看详情
</el-button>
<span>|</span>
<el-button type="text" class="btn" :disabled="!node.data.id" @click="remove(node, data)" style="color: #333">
删除
</el-button>
</span>
</span>
</el-tree>
<script>
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)
},
},
}
</script>
2、SystemTree.vue
拖拽涉及代码是:handleDrop
<system-tree-item
:treeData="systemTreeList"
:canStatusChange="canStatusChange"
@handleDrop="handleDrop"
@nodeClick="nodeClick"
@insertAfter="insertAfter"
@append="append"
@toDetail="toDetail"
@remove="remove"
@addKnoeledgeCode="addKnoeledgeCode"
/>
<script>
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)
}
}
}
}
</script>
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/117203.html