294 lines
7.2 KiB
Vue
294 lines
7.2 KiB
Vue
|
|
<template>
|
|||
|
|
<div class="flow_container">
|
|||
|
|
<div class="btn_container">
|
|||
|
|
<div class="instState">实例状态:<span :class="instStatus">{{ stateMap[instStatus]}}</span></div>
|
|||
|
|
<el-button key=" translateCenter" type="primary" @click="() => lfRef.translateCenter()">居中</el-button>
|
|||
|
|
<el-button key="fitView" type="primary" @click="() => lfRef.fitView()">适应屏幕</el-button>
|
|||
|
|
<el-button v-if="['RUNNING','PAUSED'].includes(instStatus)" type="primary" @click="stopFlow">停止</el-button>
|
|||
|
|
<el-button v-if="instStatus === 'RUNNING'" type="primary" @click="pauseFlow">暂停</el-button>
|
|||
|
|
<el-button v-if="instStatus === 'PAUSED'" type="primary" @click="restartFlow">恢复</el-button>
|
|||
|
|
</div>
|
|||
|
|
<div ref="containerRef" class="containerRef"></div>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
<script setup>
|
|||
|
|
import { ref, onMounted } from "vue";
|
|||
|
|
import LogicFlow from "@logicflow/core";
|
|||
|
|
import { Group } from "@logicflow/extension";
|
|||
|
|
import "@logicflow/core/es/index.css";
|
|||
|
|
import { convertNodeRedToLogicFlow, recursiveFilter, changeOtherNodeState } from '@/utils/convertNodeRedToLogicFlow'
|
|||
|
|
import { registerCustomNode } from "./customFlowNode";
|
|||
|
|
import { registerCustomGroup } from "./CustomGroup";
|
|||
|
|
import { getLogicFlow } from '@/api/test/log'
|
|||
|
|
import { pauseInst, resumeInst, stopInst } from '@/api/device/terminal'
|
|||
|
|
import { ElMessage } from 'element-plus'
|
|||
|
|
|
|||
|
|
const containerRef = ref(null);
|
|||
|
|
const lfRef = ref(null);
|
|||
|
|
// 在新窗口的脚本中
|
|||
|
|
const queryParams = new URLSearchParams(window.location.search);
|
|||
|
|
const instId = queryParams.get('instId') || '';
|
|||
|
|
const taskId = queryParams.get('taskId') || '';
|
|||
|
|
const itemId = queryParams.get('itemId') || '03e0842c2fd7ab7575636a473aeefc89';
|
|||
|
|
|
|||
|
|
const data = {
|
|||
|
|
nodes: [
|
|||
|
|
{
|
|||
|
|
id: "custom-node-1",
|
|||
|
|
text: "node-1",
|
|||
|
|
type: "CustomNode",
|
|||
|
|
x: 100,
|
|||
|
|
y: 100,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 'custom-node-2',
|
|||
|
|
type: 'CustomNode',
|
|||
|
|
x: 300,
|
|||
|
|
y: 300,
|
|||
|
|
text: 'node-2',
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
// 边
|
|||
|
|
edges: [
|
|||
|
|
{
|
|||
|
|
type: 'polyline',
|
|||
|
|
sourceNodeId: 'custom-node-1',
|
|||
|
|
targetNodeId: 'custom-node-2',
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const dataNodes = ref([])
|
|||
|
|
|
|||
|
|
const loadNodeRedData = async () => {
|
|||
|
|
const {nodes, edges} = await convertNodeRedToLogicFlow(itemId)
|
|||
|
|
lfRef.value.render({
|
|||
|
|
nodes,
|
|||
|
|
edges
|
|||
|
|
})
|
|||
|
|
dataNodes.value = nodes
|
|||
|
|
setTimeout(() => {
|
|||
|
|
lfRef.value.fitView()
|
|||
|
|
}, 20)
|
|||
|
|
getLog()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const getLog = async () => {
|
|||
|
|
const res = await getLogicFlow({
|
|||
|
|
instId,
|
|||
|
|
taskId,
|
|||
|
|
itemId
|
|||
|
|
})
|
|||
|
|
if (res.code === 200) {
|
|||
|
|
const arr = res.data.filter(item => {
|
|||
|
|
return item.nodeType
|
|||
|
|
})
|
|||
|
|
const map = new Map()
|
|||
|
|
arr.forEach(item => {
|
|||
|
|
if (['inject', 'start'].includes(item.nodeType)) { // , 'end'
|
|||
|
|
map.set(item.nodeId, {
|
|||
|
|
state: 'success',
|
|||
|
|
nodeType: item.nodeType,
|
|||
|
|
input: item.params
|
|||
|
|
})
|
|||
|
|
} else {
|
|||
|
|
let obj
|
|||
|
|
if (map.has(item.nodeId)) {
|
|||
|
|
obj = map.get(item.nodeId)
|
|||
|
|
} else {
|
|||
|
|
obj = {
|
|||
|
|
nodeType: item.nodeType,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (item.paramsType === 'INPUT') {
|
|||
|
|
obj.state = item.instStatus.toLowerCase(),
|
|||
|
|
obj.input = item.instStatus === 'FAILED' ? item.params : item.message
|
|||
|
|
} else {
|
|||
|
|
obj.state = item.instStatus.toLowerCase() === 'running' ? 'success' : item.instStatus.toLowerCase(),
|
|||
|
|
obj.output = item.instStatus === 'FAILED' ? item.message : item.params
|
|||
|
|
}
|
|||
|
|
map.set(item.nodeId, obj)
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
for (const [key, value] of map) {
|
|||
|
|
lfRef.value.setProperties(key, value)
|
|||
|
|
}
|
|||
|
|
changeOtherNodeState(dataNodes.value, lfRef.value)
|
|||
|
|
if (arr[arr.length - 1].nodeType !== 'end' && arr[arr.length - 1].instStatus !== 'FAILED') {
|
|||
|
|
setTimeout(() => {
|
|||
|
|
getLog()
|
|||
|
|
}, 2000)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const stopFlow = async () => {
|
|||
|
|
const res = await stopInst(instId)
|
|||
|
|
if (res.code === 200) {
|
|||
|
|
ElMessage.success('停止成功')
|
|||
|
|
getInstDetail()
|
|||
|
|
} else {
|
|||
|
|
ElMessage.error(res.msg)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const pauseFlow = async () => {
|
|||
|
|
const res = await pauseInst(instId)
|
|||
|
|
if (res.code === 200) {
|
|||
|
|
ElMessage.success('暂停成功')
|
|||
|
|
getInstDetail()
|
|||
|
|
} else {
|
|||
|
|
ElMessage.error(res.msg)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const restartFlow = async () => {
|
|||
|
|
const res = await resumeInst(instId)
|
|||
|
|
if (res.code === 200) {
|
|||
|
|
ElMessage.success('恢复成功')
|
|||
|
|
getInstDetail()
|
|||
|
|
} else {
|
|||
|
|
ElMessage.error(res.msg)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const instStatus = ref('RUNNING')
|
|||
|
|
const stateMap = {
|
|||
|
|
SUCCESS: "已完成",
|
|||
|
|
RUNNING: "执行中",
|
|||
|
|
FAILED: "失败",
|
|||
|
|
PAUSED: "已暂停",
|
|||
|
|
STOPPED: "已终止"
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const getInstDetail = async () => {
|
|||
|
|
const res = await getLogicFlow({
|
|||
|
|
instId,
|
|||
|
|
taskId,
|
|||
|
|
itemId
|
|||
|
|
})
|
|||
|
|
if (res.code === 200) {
|
|||
|
|
const item = res.data[res.data.length - 1]
|
|||
|
|
instStatus.value = item.instStatus
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
onMounted(() => {
|
|||
|
|
if (containerRef.value) {
|
|||
|
|
const lf = new LogicFlow({
|
|||
|
|
container: containerRef.value,
|
|||
|
|
isSilentMode: true,
|
|||
|
|
adjustNodePosition: true,
|
|||
|
|
stopZoomGraph: false,
|
|||
|
|
stopScrollGraph: false,
|
|||
|
|
stopMoveGraph: false,
|
|||
|
|
autoExpand: true,
|
|||
|
|
adjustEdgeStartAndEnd: true,
|
|||
|
|
allowRotate: false,
|
|||
|
|
edgeTextEdit: false,
|
|||
|
|
keyboard: {
|
|||
|
|
enabled: true,
|
|||
|
|
},
|
|||
|
|
partial: true,
|
|||
|
|
background: {
|
|||
|
|
color: "#FFFFFF",
|
|||
|
|
},
|
|||
|
|
grid: true,
|
|||
|
|
edgeTextDraggable: false,
|
|||
|
|
nodeTextEdit: false, //节点是否可编辑。false不可编辑
|
|||
|
|
textEdit: false, //是否开启文本编辑
|
|||
|
|
style: {
|
|||
|
|
inputText: {
|
|||
|
|
background: "black",
|
|||
|
|
color: "white",
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
idGenerator(type) {
|
|||
|
|
return type + "_" + Math.random();
|
|||
|
|
},
|
|||
|
|
plugins: [Group],
|
|||
|
|
group: {
|
|||
|
|
foldable: true, // 启用折叠功能
|
|||
|
|
foldSize: 30, // 折叠后显示的图标尺寸
|
|||
|
|
},
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 注册自定义节点
|
|||
|
|
registerCustomNode(lf)
|
|||
|
|
registerCustomGroup(lf)
|
|||
|
|
// 渲染数据 data
|
|||
|
|
lf.render(data);
|
|||
|
|
|
|||
|
|
lf.on('node:dragstart', (data, e) => {
|
|||
|
|
lfRef.value.setProperties(data.data.id, {
|
|||
|
|
nowTime: new Date().getTime()
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// 监听子节点拖动事件
|
|||
|
|
lf.on("node:mousemove", ({ data, e }) => {
|
|||
|
|
const { nodes } = lf.getGraphData();
|
|||
|
|
const arr = recursiveFilter(nodes, data.id)
|
|||
|
|
arr.forEach(item => {
|
|||
|
|
lf.getNodeModelById(item.id).updateSize()
|
|||
|
|
})
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 监听子节点拖动事件
|
|||
|
|
lf.on("blank:drop", () => {
|
|||
|
|
getLog()
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
lfRef.value = lf;
|
|||
|
|
}
|
|||
|
|
loadNodeRedData()
|
|||
|
|
getInstDetail()
|
|||
|
|
});
|
|||
|
|
</script>
|
|||
|
|
<style lang="scss" scoped>
|
|||
|
|
.flow_container {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 100%;
|
|||
|
|
position: relative;
|
|||
|
|
|
|||
|
|
.btn_container {
|
|||
|
|
height: 60px;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: end;
|
|||
|
|
position: absolute;
|
|||
|
|
right: 10px;
|
|||
|
|
top: 0;
|
|||
|
|
z-index: 2;
|
|||
|
|
|
|||
|
|
.instState {
|
|||
|
|
margin-right: 12px;
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
|
|||
|
|
.RUNNING, .PAUSED, .STOPPED {
|
|||
|
|
color: #8bbf86;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.SUCCESS {
|
|||
|
|
color: green;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.FAILED {
|
|||
|
|
color: rgb(128, 41, 0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
:deep(.containerRef) {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 100%;
|
|||
|
|
|
|||
|
|
.lf-graph {
|
|||
|
|
width: 100% !important;
|
|||
|
|
height: 100% !important;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</style>
|