<template>
|
<div class="ltree bxs">
|
<div class="ct-inner bxs">
|
<div class="ct-inner-fiexd w">
|
<el-input
|
placeholder="请输入关键词"
|
suffix-icon="el-icon-search"
|
v-model="FilterText"
|
style="width: 200px; float: left"
|
></el-input>
|
<div class="buttons">
|
<el-button type="primary" @click="ExpandAll">M</el-button>
|
<el-button type="primary" plain @click="CollapseAll">E</el-button>
|
</div>
|
</div>
|
<div ref="TreeBox" class="ct-inner-content h">
|
<!-- show-checkbox 是否展示多选框 -->
|
<!-- :check-on-click-node="true" 点击文本内容是否选中 -->
|
<el-tree
|
:data="TreeData"
|
:node-key="DefaultProps.Id"
|
:default-expand-all="DefaultExpand"
|
:expand-on-click-node="false"
|
@node-click="OnLeftclick"
|
@node-drag-start="OnDragStart"
|
@node-drag-enter="OnDragEnter"
|
@node-drag-leave="OnDragLeave"
|
@node-drag-over="OnDragOver"
|
@node-drag-end="OnDragEnd"
|
@node-drop="OnDrop"
|
@node-contextmenu="OnRightClick"
|
:filter-node-method="FilterNode"
|
draggable
|
:allow-drop="AllowDrop"
|
:allow-drag="AllowDrag"
|
:props="DefaultProps"
|
ref="tree"
|
>
|
<span class="slot-t-node span-ellipsis" slot-scope="{ node, data }">
|
<span class="span-ellipsis-inner" v-show="!data.IsEdit">
|
<!-- <el-tooltip class="item" effect="dark" :content="node.label" placement="right"> -->
|
<span class="span-ellipsis">
|
<span
|
class="span-ellipsis"
|
:class="[
|
SelectTreeData &&
|
data[DefaultProps.Id] == SelectTreeData[DefaultProps.Id]
|
? 'slot-t-node--label'
|
: '',
|
]"
|
style="vertical-align: middle"
|
>
|
<i class="iconfont jxintegral-fill"></i>
|
{{ node.label }}
|
</span>
|
</span>
|
<!-- </el-tooltip> -->
|
</span>
|
<!-- autofocus -->
|
<span v-show="data.IsEdit">
|
<el-input
|
class="slot-t-input"
|
style="height: 28px"
|
size="mini"
|
v-model="data.label"
|
:ref="'SlotTreeInput' + data.Id"
|
@blur.stop="OnBlurNode(node, data)"
|
@keydown.native.enter="OnBlurNode(node, data)"
|
></el-input>
|
</span>
|
</span>
|
</el-tree>
|
|
<el-card class="box-card" ref="card" v-show="MenuVisible">
|
<div @click="AddSameLevelNode()" v-show="FirstLevel">
|
<i class="el-icon-circle-plus-outline"></i>
|
<span class="ml10">增加同级</span>
|
</div>
|
|
<div class="add" @click="AddChildNode()">
|
<i class="el-icon-circle-plus-outline"></i>
|
<span class="ml10">增加下级</span>
|
</div>
|
|
<div class="delete" @click="DeleteNode()">
|
<i class="el-icon-remove-outline"></i>
|
<span class="ml10">删除</span>
|
</div>
|
|
<div class="edit" @click="EditNode()">
|
<i class="el-icon-edit"></i>
|
<span class="ml10">修改</span>
|
</div>
|
</el-card>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
import axios from "axios";
|
export default {
|
name: "LTree",
|
components: {},
|
data() {
|
return {
|
DefaultExpand: true, //默认全部展开
|
IsShow: false,
|
SelectData: "",
|
SelectNode: "",
|
MenuVisible: false,
|
FirstLevel: false,
|
FilterText: "",
|
MaxExpandId: 4,
|
SrcList: [],
|
TreeData: [
|
{
|
id: 1,
|
label: "一级 1",
|
IsEdit: false,
|
children: [
|
{
|
id: 4,
|
label: "二级 1-1",
|
IsEdit: false,
|
children: [
|
{
|
id: 9,
|
label:
|
"三级 1-1-1呜呜呜呜呜呜呜呜无无无无无无无无无无无无无无无无无",
|
IsEdit: false,
|
},
|
{
|
id: 10,
|
label: "三级 1-1-2",
|
IsEdit: false,
|
},
|
],
|
},
|
],
|
},
|
{
|
id: 2,
|
label: "一级 2",
|
IsEdit: false,
|
children: [
|
{
|
id: 5,
|
label: "二级 2-1",
|
IsEdit: false,
|
},
|
{
|
id: 6,
|
label: "二级 2-2",
|
IsEdit: false,
|
},
|
],
|
},
|
{
|
id: 3,
|
label: "一级 3",
|
IsEdit: false,
|
children: [
|
{
|
id: 7,
|
label: "二级 3-1",
|
IsEdit: false,
|
},
|
{
|
id: 8,
|
label: "二级 3-2",
|
IsEdit: false,
|
children: [
|
{
|
id: 11,
|
label: "三级 3-2-1",
|
IsEdit: false,
|
},
|
{
|
id: 12,
|
label: "三级 3-2-2",
|
IsEdit: false,
|
},
|
{
|
id: 13,
|
label: "三级 3-2-3",
|
IsEdit: false,
|
},
|
],
|
},
|
],
|
},
|
],
|
TreeDataCopy: "", //拖拽结束后验证后不可拖拽
|
DefaultProps: {
|
Id: "Id", //节点唯一标识
|
children: "Children", //子集
|
label: "Name", //显示名称
|
},
|
SelectTreeNode: "", //选中的树节点,内含父节点
|
SelectTreeData: "", //选中的树data
|
NewAddTreeObjs: {}, //新增节点储存对象
|
NowAddTreeNodeid: "", //当前新增节点id
|
};
|
},
|
props: [
|
"IsEditInTree", //是否在树中修改(是:则会在树组件中改完名称后,再调用外部的OnEdit事件直接提交。否:则会在点修改时直接调用外部的OnEdit事件,由外部处理修改的信息。)
|
],
|
methods: {
|
//全部展开
|
ExpandAll() {
|
let treemap = this.$refs.tree.store.nodesMap;
|
let list = this.SrcList;
|
for (let i = 0; i < list.length; i++) {
|
treemap[list[i].Id].expanded = true;
|
}
|
},
|
//全部折叠
|
CollapseAll() {
|
let treemap = this.$refs.tree.store.nodesMap;
|
let list = this.SrcList;
|
for (let i = 0; i < list.length; i++) {
|
treemap[list[i].Id].expanded = false;
|
}
|
},
|
//修改名称后调用OnEdit事件
|
OnBlurNode(Node, Data) {
|
let self = this,
|
label = self.$refs["SlotTreeInput" + Data.Id].$refs.input.value;
|
if (Data.IsEdit) {
|
self.$set(Data, "IsEdit", false);
|
}
|
if (label.length === 0) {
|
return false;
|
}
|
Data.Name = label;
|
self.$emit("OnEdit", Data);
|
},
|
//查询
|
FilterNode(value, Data) {
|
if (!value) return true;
|
return Data[this.DefaultProps.label].indexOf(value) !== -1;
|
},
|
|
OnDragStart(node, ev) {
|
console.log(this.TreeData, "树");
|
console.log("drag start", node);
|
// 如果要阻止拖拽
|
// if(node.childNodes.length>0){
|
// console.log("有子节点不能移动")
|
// ev.preventDefault();
|
// return;
|
// }
|
},
|
|
OnDragEnter(DragNode, DropNode, ev) {
|
console.log("tree drag enter: ", DropNode.label);
|
},
|
|
OnDragLeave(DragNode, DropNode, ev) {
|
console.log("tree drag leave: ", DropNode.label);
|
},
|
|
OnDragOver(DragNode, DropNode, ev) {
|
console.log("tree drag over: ", DropNode.label);
|
},
|
|
OnDragEnd(DragNode, DropNode, DropType, ev) {
|
switch (DropType) {
|
case "before":
|
DragNode.data.ParentId = DropNode.data.ParentId;
|
this.$emit("OnMove", DragNode.data, DropNode.data.Id);
|
break;
|
case "inner":
|
DragNode.data.ParentId = DropNode.data.Id;
|
this.$emit("OnMove", DragNode.data, 0);
|
break;
|
}
|
console.log("tree drag end: ", DropNode && DropNode.label, DropType);
|
},
|
|
OnDrop(DragNode, DropNode, DropType, ev) {
|
console.log("tree drop: ", DropNode.label, DropType);
|
// 拖拽结束后验证后不可拖拽
|
// console.log(this.TreeData,'树')
|
// this.TreeData=JSON.parse(JSON.stringify(this.TreeDataCopy));
|
},
|
//拖拽时判定目标节点能否被放置
|
AllowDrop(DragNode, DropNode, type) {
|
//console.log(DropNode.data, type);
|
return type != "next";
|
},
|
|
//是否允许拖动
|
AllowDrag(DragNode) {
|
var isnotdrag = DragNode.data.IsNotDrag;
|
return !isnotdrag;
|
},
|
|
//鼠标右击事件
|
OnRightClick(MouseEvent, object, Node, element) {
|
//暂存数据
|
this.SelectData = object;
|
this.SelectNode = Node;
|
//菜单调整
|
if (Node.level === 2) {
|
this.FirstLevel = true;
|
} else {
|
this.FirstLevel = false;
|
}
|
//菜单
|
this.MenuVisible = true;
|
document.addEventListener("click", this.Foo);
|
//定位
|
let treebox = this.$refs.TreeBox,
|
ctxmenu = this.$refs.card.$el,
|
cw = ctxmenu.offsetWidth || 182,
|
ch = ctxmenu.offsetHeight || 165,
|
x = event.target.offsetLeft + event.layerX,
|
y = event.target.offsetTop + event.layerY;
|
ctxmenu.style.left =
|
(treebox.offsetWidth < x + cw ? treebox.offsetWidth - cw : x) + "px";
|
ctxmenu.style.top =
|
(treebox.offsetHeight < y + ch ? treebox.offsetHeight - ch : y) + "px";
|
},
|
//鼠标左击事件
|
OnLeftclick(data, node) {
|
// console.log(data,'选中的节点')
|
this.SelectTreeNode = node;
|
this.SelectTreeData = data;
|
this.Foo(data.id, true);
|
this.$emit("OnClick", data);
|
},
|
//判断是否为新增id,且新增id是否为真id
|
SureNewOrOld(id) {
|
//1 表明是旧id,2表示新id,3表示id未返回
|
id = id + "";
|
let arrs = id.split("-");
|
let NewAddTreeObjs = this.NewAddTreeObjs;
|
if (arrs[0] == "xzjd") {
|
console.log(id);
|
console.log(NewAddTreeObjs);
|
console.log(NewAddTreeObjs[id]);
|
let idData = NewAddTreeObjs[id];
|
if (idData.id != id) {
|
return 2;
|
} else {
|
// 新增部门,请刷新列表获取信息!
|
this.$message.warning("新增部门,请稍后操作!");
|
this.SelectTreeNode = "";
|
this.SelectTreeData = "";
|
return 3;
|
}
|
} else {
|
return 1;
|
}
|
},
|
|
//取消鼠标监听事件 菜单栏
|
Foo(id, havesure) {
|
//havesure判断是否为左键点击
|
let NewAddTreeObjs = this.NewAddTreeObjs;
|
this.MenuVisible = false; // 要及时关掉监听,不关掉的是一个坑,不信你试试,虽然前台显示的时候没有啥毛病,加一个alert你就知道了
|
document.removeEventListener("click", this.Foo);
|
if (this.NowAddTreeNodeid) {
|
this.NowAddTreeNodeid = "";
|
return;
|
}
|
console.log("真正选中的节点");
|
if (!havesure) {
|
return;
|
}
|
let oldSure = this.SureNewOrOld(id);
|
console.log(oldSure);
|
if (oldSure == 2) {
|
} else if (oldSure == 3) {
|
return;
|
} else {
|
this.ChangeRightMess(id);
|
}
|
},
|
// 刷新右侧信息
|
ChangeRightMess(id) {
|
this.$emit("sentFather", { id: id });
|
},
|
|
// 增加同级节点事件
|
AddSameLevelNode() {
|
this.AddNode(this.SelectData.ParentId);
|
},
|
|
//增加子级节点事件
|
AddChildNode() {
|
this.AddNode(this.SelectData.Id);
|
},
|
|
//增加节点
|
AddNode(ParentId) {
|
let self = this;
|
let onevt = self.$listeners["OnAdd"];
|
|
let pdata = self.SelectData;
|
let data = {};
|
data.ParentId = ParentId;
|
let callback = function (datax) {
|
Object.assign(data, datax);
|
self.$refs.tree.append(data, self.SelectNode);
|
};
|
|
if (onevt) {
|
let tdata = {};
|
Object.assign(tdata, data);
|
self.$emit("OnAdd", tdata, callback);
|
} else {
|
data[self.DefaultProps.label] = "新增节点";
|
data[self.DefaultProps.children] = [];
|
callback(data);
|
}
|
},
|
|
//删除节点
|
DeleteNode() {
|
let self = this;
|
let onevt = self.$listeners["OnDelete"];
|
let callback = function (Ok) {
|
self.$refs.tree.remove(self.SelectNode);
|
};
|
if (onevt) {
|
this.$emit("OnDelete", this.SelectData, callback);
|
} else {
|
callback(1);
|
}
|
},
|
|
//编辑节点
|
EditNode() {
|
let self = this,
|
data = self.SelectData;
|
//内部修改
|
if (self.IsEditInTree && !data.IsEdit) {
|
self.$set(data, "IsEdit", true);
|
self.$nextTick(() => {
|
self.$refs["SlotTreeInput" + data.Id].$refs.input.focus();
|
});
|
return;
|
}
|
//外部修改
|
let onevt = self.$listeners["OnEdit"];
|
let callback = function (datax) {
|
Object.assign(data, datax);
|
};
|
|
if (onevt) {
|
let tdata = {};
|
Object.assign(tdata, data);
|
self.$emit("OnEdit", tdata, callback);
|
} else {
|
callback(data);
|
}
|
},
|
|
//加载列表(不需要树型结构,模型必须实现IModTree接口)
|
LoadList(List) {
|
this.SrcList = List;
|
let dic = {},
|
treedata = [];
|
for (let i = 0, c = List.length; i < c; i++) {
|
let mod = List[i];
|
if (mod.ParentId == 0) {
|
treedata.push(mod);
|
}
|
dic[mod.Id] = mod;
|
}
|
for (let i = 0, c = List.length; i < c; i++) {
|
let mod = List[i];
|
let parent = dic[mod.ParentId];
|
if (!parent) {
|
continue;
|
}
|
if (!parent.Children) {
|
parent.Children = [];
|
}
|
parent.Children.push(mod);
|
}
|
this.TreeData = [
|
{ Id: 0, Name: "所有", Children: treedata, ParentId: 0 },
|
];
|
},
|
},
|
|
watch: {
|
FilterText(val) {
|
this.$refs.tree.filter(val);
|
},
|
},
|
|
mounted() {
|
// this.test();
|
// 拖拽结束后验证后不可拖拽
|
// this.TreeDataCopy=JSON.parse(JSON.stringify(this.TreeData))
|
},
|
};
|
</script>
|
|
<style scoped>
|
.ltree {
|
width: 100%;
|
height: 100%;
|
}
|
.ltree .ct-inner {
|
height: 100%;
|
position: relative;
|
padding-top: 50px;
|
}
|
.ltree .ct-inner-fiexd {
|
width: 100%;
|
position: absolute;
|
left: 0;
|
top: 0;
|
}
|
.ltree .ct-inner-content {
|
position: relative;
|
}
|
.ltree .text {
|
font-size: 14px;
|
}
|
.ltree .buttons {
|
margin-left: 10px;
|
float: left;
|
}
|
.ltree .buttons button {
|
padding: 10px 15px;
|
float: left;
|
}
|
.ltree .add {
|
cursor: pointer;
|
margin-top: 10px;
|
}
|
.ltree .delete {
|
margin: 10px 0;
|
cursor: pointer;
|
}
|
.ltree .edit {
|
margin-bottom: 10px;
|
cursor: pointer;
|
}
|
.ltree .box-card {
|
width: 180px;
|
position: absolute;
|
z-index: 1000;
|
}
|
.ltree .slot-t-node--label {
|
background-color: #f5f7fa;
|
}
|
|
.ltree .span-ellipsis {
|
width: 100%;
|
overflow: hidden;
|
white-space: nowrap;
|
text-overflow: ellipsis;
|
display: inline-block;
|
}
|
.ltree .el-tree {
|
width: 100%;
|
max-height: 95%;
|
padding-bottom: 20px;
|
overflow: auto;
|
& > .el-tree-node {
|
display: inline-block;
|
min-width: 100%;
|
}
|
}
|
.el-tree-node__content {
|
height: 30px;
|
}
|
.el-card__body {
|
padding: 10px 20px;
|
}
|
</style>
|