效果图(优点:可以自定义每一条折线的颜色,可以自定义节点的颜色,以及折线的计算样式等):
代码:
<!-- 流程图组件 -->
<template>
<div id="container"></div>
</template>
<script setup lang="ts">
import {watch, reactive, toRefs, nextTick, ref, onBeforeUnmount} from "vue";
import {Graph} from "@antv/g6";
import RuleCommonUtil from "../utils/RuleCommonUtil";
import GlobalConst from "../utils/GlobalConst";
import DictConst from "../enums/DictConst";
const dataValue: any = reactive({
nodes: [
// {
// id: "dom2",
// data: {label: "dom2", width: 60, height: 100},
// style: {x: 50, y: 100, width: 100, height: 50},
// },
// {
// id: "dom3",
// data: {label: "dom3", width: 60, height: 100},
// style: {x: 150, y: 100, width: 100, height: 50},
// },
// {
// id: "dom4",
// data: {label: "dom4", width: 60, height: 100},
// style: {x: 250, y: 100, width: 100, height: 50},
// },
// {
// id: "dom5",
// data: {label: "dom5", width: 50, height: 100},
// style: {x: 350, y: 100, width: 100, height: 50},
// },
],
edges: [
// {id: "dom2->dom3", source: "dom2", target: "dom3"},
// {id: "dom3->dom4", source: "dom3", target: "dom4"},
// {id: "dom4->dom5", source: "dom4", target: "dom5"},
// {
// id: "dom1->dom5",
// source: "dom2",
// target: "dom5",
// style: {
// controlPoints: [
// [50, 180], // [起始点x轴 ,起始点y轴+要高出部分的]
// [350, 180], // [目标点x轴 ,目标点y轴+要高出部分的]
// ],
// },
// },
// {
// id: "dom1->dom4",
// source: "dom2",
// target: "dom4",
// style: {
// controlPoints: [
// [50, 180], // [起始点x轴 ,起始点y轴+要高出部分的]
// [250, 180], // [目标点x轴 ,目标点y轴+要高出部分的]
// ],
// },
// },
],
});
// 新增:声明图表实例引用
const graphInstance = ref<any>(null);
const props = defineProps({
nodeList: {
type: Array,
default: () => [],
},
process: {
type: Object,
default: () => ({}),
},
});
const {nodeList, process} = toRefs(props);
// 新增:组件卸载时自动销毁图表
onBeforeUnmount(() => {
destroyGraph();
});
watch(
() => nodeList.value,
(newValue) => {
nextTick(async () => {
if (newValue) {
setNodes();
setEdges();
await initDataList();
} else {
destroyGraph();
}
});
},
{
deep: true,
immediate: true,
},
);
// 新增:销毁图表的方法
const destroyGraph = () => {
if (graphInstance.value) {
graphInstance.value.destroy(); // 销毁图表实例
graphInstance.value = null;
}
};
const initDataList = () => {
// 销毁旧实例
destroyGraph();
// 创建新实例
graphInstance.value = new Graph({
container: document.getElementById("container") as any,
autoFit: "center",
data: dataValue,
behaviors: [
"zoom-canvas", // 保留缩放功能
"drag-canvas", // 保留画布拖拽功能
// "drag-node" // 移除或不启用拖拽节点的行为
],
node: {
type: "rect",
style: {
size: (d: any) => [d.data.width, d.data.height] as any,
radius: 10,
iconText: (d: any) => d.data.label as any,
iconFontSize: 10,
},
palette: {
type: "group",
field: "label",
},
},
edge: {
type: "polyline",
style: {
stroke: (d: any) => d.color as any,
lineWidth: 2,
lineAppendWidth: 8, // 加宽线宽度
endArrow: {
// path: Arrow.triangle(10, 10, 2), // 使用导入的箭头路径
// fill: "#18c298ad", // 填充颜色
} as any,
offset: 20, // 设置箭头偏移
},
},
plugins: [
{
type: "tooltip",
getContent: (_event: any, items: any) => {
return `<span>${items[0]?.logicNode}</span>`;
},
},
],
});
graphInstance.value.render();
};
const setNodes = () => {
dataValue.nodes = nodeList.value.map((item: any, index: number) => {
return {
id: `${item.seq}`,
data: {label: item?.taskName || "--", width: 80, height: 100},
logicNode: item?.taskName || "--",
style: {
x: 50 + index * 150,
y: 100,
width: 100,
height: 50,
fill: "#3761f5", // 或者你可以设置为一个统一颜色,比如 "#FFFFFF"
stroke: "#f0f0f0", // 设置边框颜色 (黑色)
lineWidth: 2, // 设置边框宽度
radius: 10, // 如果你希望有圆角,可以保持这一行
color: "#6c8bf7",
},
};
});
};
const setEdges = () => {
const list: any = nodeList.value;
const aaa = list.map((item: any, index: number) => {
if (list[index + 1]) {
return {
id: `${item.seq}->${list[index + 1].seq}`,
logicNode: setTooltip(
item.taskConditionList.find((c: any) => list[index + 1].taskCode === c.targetTaskCode)
?.logicNode || {},
),
source: `${item.seq}`,
target: `${list[index + 1].seq}`,
color: "#41d89f",
};
}
});
dataValue.edges = aaa.filter((item: any) => item);
relationship();
};
// 计算非直连的节点关系表
const relationship = () => {
let topArrow: number[] = [];
const list: any = nodeList.value;
//先过滤出有条件的节点
const subset = list.filter(
(item: any) => item?.taskConditionList && item?.taskConditionList.length > 0,
);
let subsetlength = subset.length || 0;
subset.forEach((item: any, index: number) => {
item.taskConditionList.forEach((v: any) => {
// 目标节点
const objIndex = list.findIndex((vv: any) => vv.taskCode === v.targetTaskCode);
const obj = list.find((vv: any) => vv.taskCode === v.targetTaskCode);
if (obj && objIndex > -1 && item.seq + 1 !== obj.seq) {
dataValue.edges.push({
id: `${item.seq}->${v.targetTaskCode}`,
source: `${item.seq}`,
target: `${obj.seq}`,
logicNode: setTooltip(v?.logicNode || {}),
// color: item.seq >= 1 ? "#1783ff" : "#41d89f", //设置线条颜色
color: "#41d89f",
style: {
controlPoints: [
[
50 + (item.seq - 1) * 150,
topArrow.includes(item.seq)
? 100 +
((topArrow.indexOf(item.seq) + 1) * 80) /
(topArrow.indexOf(item.seq) + 1 > 1 ? 1.5 : 1)
: 100 - ((index + 1) * 80) / (index + 1 > 1 ? 1.5 : 1),
], // [起始点x轴 ,起始点y轴+要高出部分的]
[
50 + objIndex * 150,
topArrow.includes(item.seq)
? 100 +
((topArrow.indexOf(item.seq) + 1) * 80) /
(topArrow.indexOf(item.seq) + 1 > 1 ? 1.5 : 1)
: 100 - ((index + 1) * 80) / (index + 1 > 1 ? 1.5 : 1),
], // [目标点x轴 ,目标点y轴+要高出部分的]
],
},
});
topArrow.push(obj.seq);
}
});
subsetlength--;
});
};
//动态设置线条的tooltip
const setTooltip = (logicNode: any) => {
return "1111";
};
</script>