dive/table + jsplumb ,实现字段映射连线 或 多个连线 ( 以字段 node 判断连线 )

发布时间 2023-08-30 16:20:58作者: 昵称已被使用。
//场景  两个表格做映射关系

<template>
<div class="app-container">
<el-row id="container" :gutter="20">
<el-col :span="10">
<table id="leftTable">
<thead>
<tr>
<th>名称</th>
</tr>
</thead>
<tbody>
<tr v-for="(data, index) in leftTableDataList" :id="data.name"
:key="index"
name="joint">
<td>{{ data.name }}</td>
</tr>
</tbody>
</table>
</el-col>
<el-col :span="10" :offset="4">
<table id="rightTable">
<thead>
<tr>
<th>名称</th>
</tr>
</thead>
<tbody>
<!-- 通过type来进行不同接口获取参数 返回数据结构不同 通过判断来进行对应展示-->
<!-- 通过名称来做映射关系 做映射关系的左右两边id不可重复 所以添加了right的拼接,在后续传递的数据里面进行截取就好-->
<tr v-for="(data, index) in rightTableDataList" :key="index"
:id="'right' + (data.name ? data.name : data)" name="data">
<td>{{ data.name ? data.name : data }}</td>
</tr>
</tbody>
</table>
</el-col>
</el-row>
</div>
</template>

<script>
//局部引入
import jsPlumb from "jsplumb";
//jsplumb使用
let $jsPlumb = jsPlumb.jsPlumb;
let jsPlumb_instance = null; // 缓存实例化的jsplumb对象
export default {
data() {
return {
// 左侧对照数据
leftTableDataList: [
{ name: "字段1" },
{ name: "字段2" },
{ name: "字段3" },
],
// 右侧标准字典数据
rightTableDataList: [
{ name: "字段1" },
{ name: "字段2" },
{ name: "字段3" },
{ name: "字段4" },
],
pointList: null, //向后端传递的map映射关系
};
},
methods: {
showPlumb() {
let self = this;
// 清除端点、连接
jsPlumb_instance.reset();
this.pointList = new Map();
this.$forceUpdate();
jsPlumb_instance = $jsPlumb.getInstance({
Container: "container", // 选择器id
EndpointStyle: { radius: 0.11, fill: "#409EFF" }, // 端点样式
PaintStyle: { stroke: "#409EFF", strokeWidth: 2 }, // 绘画样式,默认8px线宽 #456
HoverPaintStyle: { stroke: "#1E90FF" }, // 默认悬停样式 默认为null
ConnectionOverlays: [
// 此处可以设置所有箭头的样式,因为我们要改变连接线的样式,故单独配置
// Arrow-箭头 Label-标签 PlainArrow-平头箭头 Diamond-菱形 Diamond(钻石)-钻石箭头 Custom-自定义
[
"Arrow",
{
// 设置参数可以参考中文文档
location: 1,
length: 8,
paintStyle: {
stroke: "#409EFF",
fill: "#409EFF",
},
},
],
],
Connector: ["Straight"], // 连接器的类型:直线Straight,流程图flowchart,状态机state machine,贝塞尔曲线Bezier等 默认贝塞尔曲线
DrapOptions: { cursor: "crosshair", zIndex: 2000 },
});

jsPlumb_instance.batch(() => {
for (let i = 0; i < this.leftTableDataList.length; i++) {
this.initLeaf(this.leftTableDataList[i].name, "joint");
}
for (let i = 0; i < this.rightTableDataList.length; i++) {
this.initLeaf("right"+(this.rightTableDataList[i].name?this.rightTableDataList[i].name : this.rightTableDataList[i]),"data")
}
})

this.initConnect()//默认连线
const joint = document.getElementsByName("joint");
const data = document.getElementsByName("data");

jsPlumb_instance.setSourceEnabled(joint, true);
jsPlumb_instance.setTargetEnabled(data, true);
jsPlumb_instance.setDraggable(joint, false); // 是否支持拖拽
jsPlumb_instance.setDraggable(data, false); // 是否支持拖拽
jsPlumb_instance.bind("click", (conn, originalEvent) => {
this.$confirm("确认删除映射么?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
closeOnClickModal: false,
type: "warning",
})
.then(() => {
jsPlumb_instance.deleteConnection(conn);
})
.catch(() => {});
});
///两个表进行关联时 连线
jsPlumb_instance.bind("connection", function (info) {
self.pointList.set(info.targetId.split("right")[1], info.sourceId);
});
// 删除连线
jsPlumb_instance.bind("connectionDetached", function (evt) {
if (self.pointList.has(evt.targetId.split("right")[1])) {
self.pointList.delete(evt.targetId.split("right")[1]);
}
});
},
// 初始化具体节点
initLeaf(key, type) {
const ins = jsPlumb_instance;
const elem = document.getElementById(key);
if (type == "joint") {
ins.makeSource(elem, {
anchor: [1, 0.5, 0, 0], // 左 上 右 下
allowLoopback: false,
maxConnections: 1,
});
} else {
ins.makeTarget(elem, {
anchor: [0, 0.5, 0, 0],
allowLoopback: false,
maxConnections: 1,
});
}
},
initConnect(){
//实现默认连线 一一对应连线
const jsplumbConnectOptions ={
isSource: true,
isTarget: true,
// 动态锚点、提供了4个方向 Continuous、AutoDefault
anchor: "Continuous",
}
let length = Math.min(this.leftTableDataList.length,this.rightTableDataList.length)
jsPlumb_instance.deleteEveryConnection()
for (var i = 0; i < length; i++) {
jsPlumb_instance.connect({
source: this.leftTableDataList[i].name,
target: 'right'+this.rightTableDataList[i].name,
}, jsplumbConnectOptions);
}
},
},
};
</script>

<script>
//父组件获取数据 调用初始化 jsPlumb
//通过this.$refs.step2Child调用父组件中的方法和变量
async next() {
//校验第一步表单 进行第二步映射
this.$refs.step1Child.getValid().then((res) => {
await getTableData1().then((response) => {
this.$refs.step2Child.rightTableDataList= response
})
})
await getTableData2().then((response) => {
this.$nextTick(function () {
this.$refs.step2Child.leftTableDataList = response //给子组件中的表单赋值
this.$refs.step2Child.showPlumb(); //调用子组件中的方法进行初始化
this.current++;
})
})
})
},


mounted() {
this.jsPlumbInit();
},
methods: {
jsPlumbInit() {
var plumbIns = jsPlumb.jsPlumb.getInstance();
this.plumbIns = plumbIns;
console.log("jsPlumb实例化");
console.log(this.plumbIns);
},
}
// label 连线
this.plumbIns.ready(() => {
this.plumbIns.connect({
source: sourceNode,
target: targetNode,
paintStyle: {
stroke: "Pink",
strokeWidth: 1,
radius: 7
},
overlays: [
["Arrow", { width: 8, length: 8, location: 1 }],
["Label",{
location: 0.9,
label: rela,
cssClass: "endpointTargetLabel1",
visible: true,
id: "label",
},
],
],
},common);
});

</script>

<style>
.el-card ::v-deep .el-card__body {
height: calc(100vh - 170px);
}
#leftTable, #rightTable {
width: 100%;
margin: 15px 0;
border-collapse: collapse;
tr th {
color: #909399;
font-weight: bold;
background-color: #f5f5f5;
}
tr th, tr td {
font-size: 14px;
border: 1px solid #EBEEF5;
padding:10px;
text-align: center;
}
}
</style>

<script>

</script>