<template>
<div style="width: 100%;height: 100%;">
<div id="container" style="width: 100%;height: 100%;" >
<!-- <templateDialog
v-if="dialogVisible"
:templateData="templateData"
@handleClose="dialogVisible = false"
/> -->
</div>
</div>
</template>
<script>
// import templateDialog from "../templateDialog.vue";
import G6 from "@antv/g6";
import { node } from "../design/G6/node";
// import {
// moveTask,
// delProject,
// getReport,
// sameLevelSort,
// } from "@/service/project";
import { Loading } from "element-ui";
export default {
// components: { templateDialog },
data() {
return {
graph: null,
dialogVisible: false,
templateData: {},
};
},
props: {
nodes: {
type: Object,
},
userList: {
type: Object,
},
amountList: {
type: Object,
},
timeList: {
type: Object,
},
weightList: {
type: Object,
},
errorList: {
type: Object,
},
routeType: {
type: String,
},
},
computed: {
treeNodes: {
get() {
// return JSON.parse(JSON.stringify(this.nodes));
return {
id: "root",
label: "决策节点",
children: [
{
id: "child1",
label: "子节点1",
children: [
{
id: "grandchild1",
label: "孙子节点1",
},
{
id: "grandchild2",
label: "孙子节点2",
},
],
},
{
id: "child2",
label: "子节点2",
},
],
};
},
},
},
mounted() {
console.log(this.nodes,'---------------------------------')
},
methods: {
initCharts() {
let vm = this;
// 注册一个自定义节点
node(
G6,
this.userList,
this.timeList,
this.amountList,
this.weightList,
this.errorList,
this.routeType
);
const menu = new G6.Menu({
offsetX: 6,
offsetX: 10,
itemTypes: ["node"],
getContent(e) {
// 判断是否有权限显示右键菜单
const outDiv = document.createElement("div");
const model = e.item.getModel();
if (model.operate === "0") {
return (outDiv.innerHTML = `<ul class='ulNone'></ul>`);
}
// ${
// model.approvalStatus === "0"
// ? ""
// : "<li id='son'>添加子节点</li><li id='import'>导入模板</li><li id='del'>删除节点</li>"
// }
outDiv.innerHTML =
vm.routeType !== "template"
? `
<ul>
<li id='son' class=${
model.approvalStatus === "0" ? "disiable-btn" : ""
} >添加子节点</li>
<li id='import' class=${
model.approvalStatus === "0" ? "disiable-btn" : ""
} >导入模板</li>
<li id='del' class=${
model.approvalStatus === "0" ? "disiable-btn" : ""
} >删除节点</li>
<li id='report'>报告生成</li>
<li id='export'>导出模板</li>
</ul>`
: `
<ul>
<li id='son'>添加子节点</li>
<li id='del'>删除节点</li>
</ul>`;
return outDiv;
},
handleMenuClick(target, item) {
let id = target.id;
switch (id) {
case "son":
console.log(item.getModel().approvalStatus === "0");
if (item.getModel().approvalStatus === "0") return;
console.log(13123123);
vm.$emit("handleAddTask", item.getModel());
break;
case "del":
if (item.getModel().approvalStatus === "0") return;
vm.handleDelItem(item.getModel());
break;
case "export":
vm.handleExportItem(item.getModel());
break;
case "import":
if (item.getModel().approvalStatus === "0") return;
vm.$emit("handleAddTemTask", item.getModel());
break;
case "wbs":
console.log(item.getModel());
// vm.$emit("handleAddTemTask", item.getModel());
break;
case "report":
const loading = Loading.service({});
let formData = new FormData();
formData.append("id", item.getModel().id);
formData.append("type", item.getModel().commonType);
// getReport(formData).then((res) => {
// loading.close();
// let url = window.URL.createObjectURL(new Blob([res]));
// let a = document.createElement("a");
// a.style.display = "none";
// a.href = url;
// a.setAttribute("download", `${item.getModel().name}.docx`);
// document.body.appendChild(a);
// a.click(); //执行下载
// window.URL.revokeObjectURL(a.href); //释放url
// document.body.removeChild(a); //释放标签
// });
break;
}
},
});
const container = document.getElementById("container");
const width = container.scrollWidth;
const height = (container.scrollHeight || 500) - 20;
this.graph = new G6.TreeGraph({
container: "container",
width,
height,
animate: false, // Boolean,切换布局时是否使用动画过度,默认为 false
animateCfg: {
duration: 200, // Number,一次动画的时长
easing: "linearEasing", // String,动画函数
},
modes: {
default: [
"drag-canvas",
"zoom-canvas",
{
type: "collapse-expand",
trigger: "dblclick",
onChange: function onChange(item, collapsed) {
const data = item.getModel();
data.collapsed = collapsed;
return true;
},
},
{
type: "drag-node",
enableDelegate: true,
},
],
},
defaultNode: {
type: "card-node",
},
defaultEdge: {
type: "cubic-horizontal",
zIndex: 1,
style: {
stroke: "#A3B1BF",
},
},
layout: {
type: "compactBox",
direction: "LR",
getId: function getId(d) {
return d.id;
},
getHeight: function getHeight() {
return 30;
},
getWidth: function getWidth() {
return 50;
},
getVGap: function getVGap() {
return 50;
},
getHGap: function getHGap() {
return 150;
},
},
plugins: [menu], // 配置 Menu 插件
});
this.graph.data(this.treeNodes);
this.graph.render();
this.graph.fitCenter();
this.graph.get("canvas").set("localRefresh", false);
// 选中
this.graph.on("node:click", (evt) => {
this.graph.getNodes().forEach((evt) => {
this.graph.setItemState(evt, "selected", false);
});
const { item } = evt;
this.graph.setItemState(item, "selected", true);
this.$emit("handleSelect", evt.item.getModel());
});
this.graph.on("right-btns:click", (e) => {
e.stopPropagation();
e.item.getModel().collapsed = !e.item.getModel().collapsed;
this.graph.setItemState(
e.item,
"collapsed",
e.item.getModel().collapsed
);
this.graph.layout();
});
this.graph.on("collapse-btn:click", (e) => {
e.stopPropagation();
e.item.getModel().collapsed = !e.item.getModel().collapsed;
this.graph.setItemState(
e.item,
"collapsed",
e.item.getModel().collapsed
);
this.graph.layout();
});
this.graph.on("right-btns:mouseenter", (e) => {
this.graph.setItemState(e.item, "showRight", true);
});
this.graph.on("right-btns:mouseleave", (e) => {
this.graph.setItemState(e.item, "showRight", false);
});
this.graph.on("collapse-btn:mouseenter", (e) => {
this.graph.setItemState(e.item, "showRight", true);
});
this.graph.on("collapse-btn:mouseleave", (e) => {
this.graph.setItemState(e.item, "showRight", false);
});
this.graph.on("node-add:click", (evt) => {
evt.stopPropagation();
this.$emit("handleAddTask", evt.item.getModel());
});
this.graph.on("add-icon:click", (evt) => {
evt.stopPropagation();
this.$emit("handleAddTask", evt.item.getModel());
});
this.graph.on("node-add:mouseenter", (e) => {
this.graph.setItemState(e.item, "nodeAdd", true);
});
this.graph.on("add-icon:mouseenter", (e) => {
this.graph.setItemState(e.item, "nodeAdd", true);
});
this.graph.on("add-icon:mouseleave", (e) => {
this.graph.setItemState(e.item, "nodeAdd", false);
});
this.graph.on("node-add:mouseleave", (e) => {
this.graph.setItemState(e.item, "nodeAdd", false);
});
this.graph.on("canvas:click", () => {
this.graph.getNodes().forEach((evt) => {
this.graph.setItemState(evt, "selected", false);
});
this.$emit("handleClose");
});
this.graph.on("node:mouseenter", (e) => {
this.graph.setItemState(e.item, "showText", true);
});
this.graph.on("node:mouseleave", (e) => {
this.graph.setItemState(e.item, "showText", false);
});
let minDisNode = null,
apiStatus = 0;
this.graph.on("node:dragstart", (e) => {
if (e.item.getModel() === "0") {
e.item.lock();
} else {
e.item.unlock();
}
minDisNode = undefined;
});
this.graph.on("node:drag", (e) => {
minDisNode = undefined;
const item = e.item;
const model = item.getModel();
const nodes = this.graph.getNodes();
if (!this.graph.findById(model.parentId)) return;
const parentNode = this.graph.findById(model.parentId).getModel();
const sourceIndex = parentNode.children.findIndex(
(element) => element.id === model.id
);
nodes.forEach((inode) => {
this.graph.setItemState(inode, "closest", false);
this.graph.setItemState(inode, "borderTopHeightLight", false);
this.graph.setItemState(inode, "borderbottomHeightLight", false);
const node = inode.getModel();
if (node.id === model.id) return;
if (node.operate === "0") {
this.$message.warning("该项目不可操作!");
return;
}
if (model.parentId === node.id) return;
if (this.isTreeContainsId(model.children, node.id)) return;
const targetIndex = parentNode.children.findIndex(
(element) => element.id === node.id
);
if (
node.x <= e.x &&
node.x + 300 >= e.x &&
node.y <= e.y &&
node.y + 70 >= e.y
) {
apiStatus = 0;
minDisNode = inode;
this.graph.setItemState(minDisNode, "closest", true);
} else if (
node.x <= e.x &&
node.x + 300 >= e.x &&
node.y - 10 <= e.y &&
node.y >= e.y &&
node.parentId === model.parentId &&
sourceIndex + 1 != targetIndex
) {
apiStatus = 1;
minDisNode = inode;
this.graph.setItemState(minDisNode, "borderTopHeightLight", true);
} else if (
node.x <= e.x &&
node.x + 300 >= e.x &&
node.y <= e.y &&
node.y + 90 + 10 >= e.y &&
node.parentId === model.parentId &&
sourceIndex - 1 != targetIndex
) {
apiStatus = 2;
minDisNode = inode;
this.graph.setItemState(
minDisNode,
"borderbottomHeightLight",
true
);
}
});
});
this.graph.on("node:dragend", async (e) => {
if (!minDisNode) {
this.graph.removeChild(id);
return;
}
const item = e.item;
const id = item.getID();
const data = this.graph.findDataById(id);
const minDisNodeId = minDisNode.getID();
switch (apiStatus) {
case 0:
if (item.getModel().approvalStatus === "0") {
this.graph.removeChild(undefined);
this.$message.warning("该项目审核,无法拖动");
return;
}
this.$emit("handleStartLoading");
let subObj = {
taskId: data.id,
parentTaskId: minDisNodeId,
};
if (this.routeType === "template") {
subObj.templateId = this.$route.query.temId;
}
// const res = await moveTask(subObj, this.routeType);
// if (res.status === 1) {
// this.$message.success(res.msg);
// this.$emit("handleRefreshTree");
// } else if (res.status === 2) {
// this.graph.removeChild(undefined);
// this.$message.warning(res.msg);
// this.$emit("handleStopLoading");
// }
break;
case 1:
this.handleSortTask("up", data.id, minDisNodeId);
// this.graph.removeChild(undefined);
break;
case 2:
this.$emit("handleStartLoading");
this.handleSortTask("down", data.id, minDisNodeId);
// this.graph.removeChild(undefined);
break;
}
});
if (typeof window !== "undefined")
window.onresize = () => {
if (!this.graph || this.graph.get("destroyed")) return;
if (!container || !container.scrollWidth || !container.scrollHeight)
return;
this.graph.changeSize(
container.scrollWidth,
container.scrollHeight - 20
);
};
},
async handleSortTask(position, taskId, targetTaskId) {
this.$emit("handleStartLoading");
let submitObj = {
taskId,
targetTaskId,
position,
};
if (this.routeType === "template") {
submitObj.templateId = this.$route.query.temId;
}
// const res = await sameLevelSort(submitObj, this.routeType);
// this.$message[
// res.status === 1 ? "success" : res.status === 2 ? "warning" : "error"
// ](res.msg);
// if (res.status === 1) {
// this.$emit("handleRefreshTree");
// } else {
// this.graph.removeChild(undefined);
// this.$emit("handleStopLoading");
// }
},
handleExportItem(row) {
this.dialogVisible = true;
this.templateData = JSON.parse(JSON.stringify(row));
},
isTreeContainsId(treeData, targetId) {
for (let i = 0; i < treeData.length; i++) {
if (treeData[i].id === targetId) {
// 如果当前节点的id与目标id相等,则返回true
return true;
} else if (Array.isArray(treeData[i].children)) {
// 如果当前节点有子节点,则递归调用该函数进行查询
const result = this.isTreeContainsId(treeData[i].children, targetId);
if (result) {
// 若在子节点中找到了目标id,则返回true
return true;
}
}
}
return false; // 没有找到目标id时返回false
},
handleDelItem(data) {
this.$confirm("此操作将永久删除该项目及子项目?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
let subObj = {};
if (this.routeType === "template") {
subObj = {
taskId: data.id,
templateId: this.$route.query.temId,
};
} else if (data.commonType === "project") {
subObj.projectId = data.id;
} else {
subObj = {
id: data.id,
type: data.commonType,
};
}
// delProject(subObj, data.commonType, this.routeType)
// .then((res) => {
// this.$message[
// res.status === 1
// ? "success"
// : res.status === 2
// ? "warning"
// : "error"
// ](res.msg);
// if (res.status === 1) {
// this.$emit("handleNodeRefresh", data);
// }
// })
// .catch((err) => {
// console.log(err);
// });
})
.catch(() => {});
},
},
watch: {
nodes: {
handler(val) {
if (this.graph) {
node(
G6,
this.userList,
this.timeList,
this.amountList,
this.weightList,
this.errorList,
this.routeType
);
this.graph.data(this.treeNodes);
this.graph.render();
this.graph.fitCenter();
} else {
this.$nextTick(() => {
this.initCharts();
});
}
},
deep: true,
},
},
beforeDestroy() {
if (this.graph) {
this.graph.destroy();
}
},
};
</script>
<style lang="less">
::v-deep .ulNone {
display: none !important;
}
.g6-component-contextmenu {
padding: 0 !important;
z-index: 99;
background: transparent !important;
border: 0 !important;
ul {
border-radius: 3px;
overflow: hidden;
.disiable-btn {
background: #e3e3e3 !important;
cursor: not-allowed !important;
}
li {
padding: 10px;
background: #fff;
&:hover {
transition: all 0.3s;
background: #ccc;
cursor: pointer;
}
}
}
}
</style>