修改组态化

master
夜笙歌 2 months ago
parent c1347b14d3
commit 320f56e77c

@ -22,6 +22,7 @@
"@highlightjs/vue-plugin": "2.1.0", "@highlightjs/vue-plugin": "2.1.0",
"@vue-flow/background": "^1.3.2", "@vue-flow/background": "^1.3.2",
"@vue-flow/core": "^1.43.1", "@vue-flow/core": "^1.43.1",
"@vue-flow/node-resizer": "^1.4.0",
"@vueup/vue-quill": "1.2.0", "@vueup/vue-quill": "1.2.0",
"@vueuse/core": "10.9.0", "@vueuse/core": "10.9.0",
"animate.css": "4.1.1", "animate.css": "4.1.1",

@ -3,8 +3,9 @@ import { createApp, provide } from 'vue';
import 'virtual:uno.css'; import 'virtual:uno.css';
import '@/assets/styles/index.scss'; import '@/assets/styles/index.scss';
import 'element-plus/theme-chalk/dark/css-vars.css'; import 'element-plus/theme-chalk/dark/css-vars.css';
import '@vue-flow/core/dist/style.css' import '@vue-flow/core/dist/style.css';
import '@vue-flow/core/dist/theme-default.css' import '@vue-flow/core/dist/theme-default.css';
import '@vue-flow/node-resizer/dist/style.css';
// App、router、store // App、router、store
import App from './App.vue'; import App from './App.vue';

@ -10,7 +10,7 @@ import useSettingsStore from '@/store/modules/settings';
import usePermissionStore from '@/store/modules/permission'; import usePermissionStore from '@/store/modules/permission';
NProgress.configure({ showSpinner: false }); NProgress.configure({ showSpinner: false });
const whiteList = ['/boardGenerate','/board1','/board2','/login', '/register', '/social-callback']; const whiteList = ['/boardGenerate', '/boardView', '/board1', '/board2', '/login', '/register', '/social-callback'];
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
NProgress.start(); NProgress.start();
@ -41,7 +41,14 @@ router.beforeEach(async (to, from, next) => {
} }
}); });
// @ts-ignore // @ts-ignore
next({ path: to.path, replace: true, params: to.params, query: to.query, hash: to.hash, name: to.name as string }); // hack方法 确保addRoutes已完成 next({
path: to.path,
replace: true,
params: to.params,
query: to.query,
hash: to.hash,
name: to.name as string
}); // hack方法 确保addRoutes已完成
} }
} else { } else {
next(); next();

@ -31,6 +31,11 @@ export const constantRoutes: RouteRecordRaw[] = [
hidden: true, hidden: true,
component: () => import('@/views/boardGenerate/index.vue') component: () => import('@/views/boardGenerate/index.vue')
}, },
{
path: '/boardView',
hidden: true,
component: () => import('@/views/boardGenerate/view.vue')
},
{ {
path: '/board1', path: '/board1',
hidden: true, hidden: true,

@ -8,50 +8,520 @@
<template #header> <template #header>
<StarFilled /> <StarFilled />
</template> </template>
图表 折线
</el-card>
<el-card style="width: 80px" shadow="never" :draggable="true"
@dragstart="onDragStart($event, 'customBoard')" :style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<StarFilled />
</template>
自定义图表1
</el-card>
</el-tab-pane>
<el-tab-pane label="数据源" name="2">
<el-card style="width: 80px" shadow="never" :draggable="true"
@dragstart="onDragStart($event, 'data')" :style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<StarFilled />
</template>
设备数据
</el-card>
</el-tab-pane>
<el-tab-pane label="表单组件" name="3">
<el-card style="width: 80px" shadow="never" :draggable="true"
@dragstart="onDragStart($event, 'inputNode')" :style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<StarFilled />
</template>
输入框
</el-card>
<el-card style="width: 80px" shadow="never" :draggable="true"
@dragstart="onDragStart($event, 'time')" :style="{display:'inline-block',margin:'0 4px 4px 0'}"
:body-style="{padding:'4px 0'}">
<template #header>
<StarFilled />
</template>
时间
</el-card> </el-card>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="数据源" name="2">Config</el-tab-pane>
<el-tab-pane label="表单组件" name="3">Role</el-tab-pane>
<el-tab-pane label="Task" name="4">Task</el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
<div class="content" @drop="onDrop"> <div class="content" @drop="onDrop">
<VueFlow :min-zoom="0.01" ref="flowRef" v-model:nodes="nodes" v-model:edges="edges" fit-view-on-init <VueFlow :min-zoom="0.01" ref="flowRef" v-model:nodes="nodes" v-model:edges="edges" fit-view-on-init
default-marker-color="#409EFF" default-marker-color="#409EFF"
@connect="logEvent('connect', $event)"
@node-click="logEvent('click', $event)" @node-click="logEvent('click', $event)"
@node-contextMenu="logEvent('contextmenu', $event)" @node-contextMenu="logEvent('contextmenu', $event)"
@dragover="onDragOver" @dragover="onDragOver"
> >
<Background :size="1" :gap="20" pattern-color="#BDBDBD" /> <Background :size="1" :gap="20" pattern-color="#BDBDBD" style="background-color: #000" />
<template #node-area="areaNodeProps">
<AreaNode v-bind="areaNodeProps"></AreaNode>
</template>
<template #node-customBoard="customBoardNodeProps">
<CustomBoardNode :inputData=getInputData(customBoardNodeProps.id) v-bind="customBoardNodeProps"
@resize="resize"></CustomBoardNode>
</template>
<template #node-line="lineNodeProps"> <template #node-line="lineNodeProps">
<LineNdoe v-bind="lineNodeProps" <LineNode :inputData=getInputData(lineNodeProps.id) v-bind="lineNodeProps"
@resize="resize"></LineNdoe> @resize="resize"></LineNode>
</template>
<template #node-data="dataNodeProps">
<DataNode :inputData=getInputData(dataNodeProps.id) v-bind="dataNodeProps"
@resize="resize"></DataNode>
</template>
<template #node-inputNode="inputNodeProps">
<InputNode :inputData=getInputData(inputNodeProps.id) v-bind="inputNodeProps"
@resize="resize"></InputNode>
</template>
<template #node-time="timeNodeProps">
<TimeNode :inputData=getInputData(timeNodeProps.id) v-bind="timeNodeProps"
@resize="resize"></TimeNode>
</template> </template>
</VueFlow> </VueFlow>
</div> </div>
<div class="rightPanel"></div> <div class="rightPanel">
<el-form :model="nodeAttrForm" label-width="auto" style="max-width: 600px" v-if="nodeAttrForm">
<el-form-item label="输出字段名" v-if="Object.keys(nodeAttrForm).includes('field')">
<el-input v-model="nodeAttrForm.field" />
</el-form-item>
<el-form-item label="开始时间字段名" v-if="Object.keys(nodeAttrForm).includes('startTimeId')">
<el-input v-model="nodeAttrForm.startTimeId" />
</el-form-item>
<el-form-item label="结束时间字段名" v-if="Object.keys(nodeAttrForm).includes('endTimeId')">
<el-input v-model="nodeAttrForm.endTimeId" />
</el-form-item>
</el-form>
{{ nodes }}
<br />
---
<br />
{{ edges }}
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { VueFlow, useVueFlow } from '@vue-flow/core'; import { v4 as uuidv4 } from 'uuid';
import { MarkerType, VueFlow, useVueFlow } from '@vue-flow/core';
import { Background } from '@vue-flow/background'; import { Background } from '@vue-flow/background';
import { StarFilled } from '@element-plus/icons-vue'; import { StarFilled } from '@element-plus/icons-vue';
import { onDragStart, onDrop, onDragOver } from './tool'; import LineNode from './nodes/board/lineNode.vue';
import CustomBoardNode from './nodes/board/customBoardNode.vue';
import DataNode from './nodes/data/dataNode.vue';
import InputNode from './nodes/form/inputNode.vue';
import TimeNode from './nodes/form/timeNode.vue';
import AreaNode from './nodes/other/areaNode.vue';
import tool from './tool';
// tool
const { onDragStart, onDrop, onDragOver } = tool();
// flow
const {
addEdges
} = useVueFlow();
const leftPanelState = ref('1'); const leftPanelState = ref('1');
const nodes = ref([]); const areaId = `area_${uuidv4().replaceAll('-', '_')}`;
const edges = ref([]); // const nodes = ref([{
// id: areaId,
// name: 'area',
// type: 'area',
// position: {
// x: 0,
// y: 0
// },
// data: { label: areaId }
// }]);
// const edges = ref([]);
const nodes = ref([
{
'id': 'area_474cfc79_4011_495e_9fb3_5e268ad09cfe',
'type': 'area',
'dimensions': { 'width': 1910, 'height': 970 },
'computedPosition': { 'x': 0, 'y': 0, 'z': 0 },
'handleBounds': { 'source': null, 'target': null },
'selected': false,
'dragging': false,
'resizing': false,
'initialized': false,
'isParent': false,
'position': { 'x': 0, 'y': 0 },
'data': { 'label': 'area_474cfc79_4011_495e_9fb3_5e268ad09cfe' },
'events': {},
'name': 'area'
},
{
'id': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'type': 'time',
'dimensions': { 'width': 100, 'height': 100 },
'computedPosition': { 'x': 106.65085072834671, 'y': 39.36769433739843, 'z': 0 },
'handleBounds': {
'source': [{
'id': 'time_500c79d5_2a5a_4369_a37f_98a90f792547.-s',
'type': 'source',
'nodeId': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'position': 'right',
'x': 97.00007501159526,
'y': 47.00005927633669,
'width': 6,
'height': 6
}],
'target': [{
'id': 'time_500c79d5_2a5a_4369_a37f_98a90f792547.-t',
'type': 'target',
'nodeId': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'position': 'left',
'x': -2.9999932235447186,
'y': 47.00005927633669,
'width': 6,
'height': 6
}]
},
'selected': false,
'dragging': false,
'resizing': false,
'initialized': false,
'isParent': false,
'position': { 'x': 106.65085072834671, 'y': 39.36769433739843 },
'data': {
'label': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'options': { 'startTimeId': 'startTime', 'endTimeId': 'endTime' },
'outputData': {}
},
'events': {},
'name': 'time'
},
{
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'type': 'data',
'dimensions': { 'width': 200, 'height': 50 },
'computedPosition': { 'x': 468.30045871559633, 'y': -251.0728211009174, 'z': 0 },
'handleBounds': {
'source': [{
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818.-s',
'type': 'source',
'nodeId': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'position': 'right',
'x': 197.00014324673523,
'y': 22.000023835240277,
'width': 6,
'height': 6
}],
'target': [{
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818.-t',
'type': 'target',
'nodeId': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'position': 'left',
'x': -2.9999932235447186,
'y': 22.000023835240277,
'width': 6,
'height': 6
}]
},
'selected': false,
'dragging': false,
'resizing': false,
'initialized': false,
'isParent': false,
'position': { 'x': 468.30045871559633, 'y': -251.0728211009174 },
'data': {
'label': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'options': {},
'outputData': {
'time': ['2025-01-01 00:00:00', '2025-01-03 00:00:00', '2025-01-05 00:00:00'],
'value': [20, 30, 40]
}
},
'events': {},
'name': 'data'
},
{
'id': 'line_77194e11_6df2_4e80_b9d7_816dac933f62',
'type': 'line',
'dimensions': { 'width': 300, 'height': 150 },
'computedPosition': { 'x': 94.76924191953978, 'y': 216.41751167721483, 'z': 1000 },
'handleBounds': {
'source': null,
'target': [{
'id': 'line_77194e11_6df2_4e80_b9d7_816dac933f62.-t',
'type': 'target',
'nodeId': 'line_77194e11_6df2_4e80_b9d7_816dac933f62',
'position': 'left',
'x': -2.9999932235447186,
'y': 72.00005795281027,
'width': 6,
'height': 6
}]
},
'selected': true,
'dragging': false,
'resizing': false,
'initialized': false,
'isParent': false,
'position': { 'x': 94.76924191953978, 'y': 216.41751167721483 },
'data': { 'label': 'line_77194e11_6df2_4e80_b9d7_816dac933f62', 'options': {}, 'outputData': {} },
'events': {},
'name': 'line'
}
]);
const edges = ref([
{
'id': 'time_500c79d5_2a5a_4369_a37f_98a90f792547---data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'type': 'bezier',
'source': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'target': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'sourceHandle': 'time_500c79d5_2a5a_4369_a37f_98a90f792547.-s',
'data': {},
'events': {},
'label': '',
'animated': true,
'markerEnd': 'arrowclosed',
'style': { 'stroke': '#409EFF' },
'sourceNode': {
'id': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'type': 'time',
'dimensions': { 'width': 100, 'height': 100 },
'computedPosition': { 'x': 106.65085072834671, 'y': 39.36769433739843, 'z': 0 },
'handleBounds': {
'source': [{
'id': 'time_500c79d5_2a5a_4369_a37f_98a90f792547.-s',
'type': 'source',
'nodeId': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'position': 'right',
'x': 97.00007501159526,
'y': 47.00005927633669,
'width': 6,
'height': 6
}],
'target': [{
'id': 'time_500c79d5_2a5a_4369_a37f_98a90f792547.-t',
'type': 'target',
'nodeId': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'position': 'left',
'x': -2.9999932235447186,
'y': 47.00005927633669,
'width': 6,
'height': 6
}]
},
'selected': false,
'dragging': false,
'resizing': false,
'initialized': false,
'isParent': false,
'position': { 'x': 106.65085072834671, 'y': 39.36769433739843 },
'data': {
'label': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'options': { 'startTimeId': 'startTime', 'endTimeId': 'endTime' },
'outputData': {}
},
'events': {},
'name': 'time'
},
'targetNode': {
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'type': 'data',
'dimensions': { 'width': 200, 'height': 50 },
'computedPosition': { 'x': 468.30045871559633, 'y': -251.0728211009174, 'z': 0 },
'handleBounds': {
'source': [{
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818.-s',
'type': 'source',
'nodeId': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'position': 'right',
'x': 197.00014324673523,
'y': 22.000023835240277,
'width': 6,
'height': 6
}],
'target': [{
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818.-t',
'type': 'target',
'nodeId': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'position': 'left',
'x': -2.9999932235447186,
'y': 22.000023835240277,
'width': 6,
'height': 6
}]
},
'selected': false,
'dragging': false,
'resizing': false,
'initialized': false,
'isParent': false,
'position': { 'x': 468.30045871559633, 'y': -251.0728211009174 },
'data': {
'label': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'options': {},
'outputData': {
'time': ['2025-01-01 00:00:00', '2025-01-03 00:00:00', '2025-01-05 00:00:00'],
'value': [20, 30, 40]
}
},
'events': {},
'name': 'data'
},
'sourceX': 209.65092573994195,
'sourceY': 89.36775361373512,
'targetX': 465.3004654920516,
'targetY': -226.0727972656771
},
{
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818---line_77194e11_6df2_4e80_b9d7_816dac933f62',
'type': 'bezier',
'source': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'target': 'line_77194e11_6df2_4e80_b9d7_816dac933f62',
'sourceHandle': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818.-s',
'data': {},
'events': {},
'label': '',
'animated': true,
'markerEnd': 'arrowclosed',
'style': { 'stroke': '#409EFF' },
'sourceNode': {
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'type': 'data',
'dimensions': { 'width': 200, 'height': 50 },
'computedPosition': { 'x': 468.30045871559633, 'y': -251.0728211009174, 'z': 0 },
'handleBounds': {
'source': [{
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818.-s',
'type': 'source',
'nodeId': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'position': 'right',
'x': 197.00014324673523,
'y': 22.000023835240277,
'width': 6,
'height': 6
}],
'target': [{
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818.-t',
'type': 'target',
'nodeId': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'position': 'left',
'x': -2.9999932235447186,
'y': 22.000023835240277,
'width': 6,
'height': 6
}]
},
'selected': false,
'dragging': false,
'resizing': false,
'initialized': false,
'isParent': false,
'position': { 'x': 468.30045871559633, 'y': -251.0728211009174 },
'data': {
'label': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'options': {},
'outputData': {
'time': ['2025-01-01 00:00:00', '2025-01-03 00:00:00', '2025-01-05 00:00:00'],
'value': [20, 30, 40]
}
},
'events': {},
'name': 'data'
},
'targetNode': {
'id': 'line_77194e11_6df2_4e80_b9d7_816dac933f62',
'type': 'line',
'dimensions': { 'width': 300, 'height': 150 },
'computedPosition': { 'x': 94.76924191953978, 'y': 216.41751167721483, 'z': 1000 },
'handleBounds': {
'source': null,
'target': [{
'id': 'line_77194e11_6df2_4e80_b9d7_816dac933f62.-t',
'type': 'target',
'nodeId': 'line_77194e11_6df2_4e80_b9d7_816dac933f62',
'position': 'left',
'x': -2.9999932235447186,
'y': 72.00005795281027,
'width': 6,
'height': 6
}]
},
'selected': true,
'dragging': false,
'resizing': false,
'initialized': false,
'isParent': false,
'position': { 'x': 94.76924191953978, 'y': 216.41751167721483 },
'data': { 'label': 'line_77194e11_6df2_4e80_b9d7_816dac933f62', 'options': {}, 'outputData': {} },
'events': {},
'name': 'line'
},
'sourceX': 671.3006019623316,
'sourceY': -226.0727972656771,
'targetX': 91.76924869599506,
'targetY': 291.4175696300251
}
]);
const nodeAttrForm = ref({});
const logEvent = async (eventname, event) => { const logEvent = async (eventname, event) => {
switch (eventname) { switch (eventname) {
case 'connect':
console.log('connect');
if (!edges.value.some(r => r.id === `${event.source}---${event.target}`)) {
addEdges({
id: `${event.source}---${event.target}`,
source: event.source,
target: event.target,
type: 'bezier',
animated: true,
markerEnd: MarkerType.ArrowClosed,
sourceHandle: event.sourceHandle,
style: { stroke: '#409EFF' }
});
}
break;
case 'click': case 'click':
console.log('click', event); console.log('click', event);
nodeAttrForm.value = event.node.data.options;
break; break;
case 'contextmenu': case 'contextmenu':
console.log('contextmenu', event); console.log('contextmenu', event);
} }
}; };
const resize = (e, id) => {
nodes.value.forEach((item) => {
if (item.selected && item.id !== id) {
item.dimensions = {
width: e.params.width,
height: e.params.height
};
}
});
};
const getInputData = (e) => {
let outputData = {};
let nodeIds = edges.value.map(v => {
if (v.target === e) {
return v.source;
}
});
nodes.value.forEach(v => {
if (nodeIds.includes(v.id)) {
console.log('v.data.outputData', v.data.outputData);
outputData = {
...outputData,
...v.data.outputData
};
}
});
return outputData;
};
</script> </script>
<style> <style lang="less" scoped>
:deep(.vue-flow__node-area) {
z-index: 0 !important;
pointer-events: none !important;
}
.leftPanel { .leftPanel {
position: absolute; position: absolute;
top: 0; top: 0;

@ -0,0 +1,238 @@
<template>
<div
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px'}">
<NodeResizer color="#fff" v-if="!props.isView && !props.isHideHandle && props.selected" @resize="resize" />
<div class="custom-node"
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px',pointerEvents:props.isView?'auto': 'none'}">
<div style="width: 100%;height: 100%" ref="chartRef" />
</div>
<Handle v-if="!props.isView" :id="`${props.id}.-t`" type="target" :position="Position.Left" />
<div class="info">
<el-icon color="#fff" @click="openMsgBox">
<InfoFilled />
</el-icon>
</div>
<el-dialog
v-model="MsgBoxVisible"
width="500"
title="提示"
append-to-body
>
<span>This is a message</span>
<template #footer>
<div class="dialog-footer">
<el-button @click="MsgBoxVisible = false">关闭</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { InfoFilled } from '@element-plus/icons-vue';
import { defineEmits, defineProps, ref } from 'vue';
import { NodeResizer } from '@vue-flow/node-resizer';
import { Handle, Position } from '@vue-flow/core';
import * as echarts from 'echarts';
const MsgBoxVisible = ref(false);
const props = defineProps({
isView: {
type: Boolean,
required: false
},
inputData: {
type: Object,
required: false
},
id: {
type: String,
required: true
},
isHideHandle: {
type: Boolean,
required: false
},
selected: {
type: Boolean,
required: false
},
data: {
type: Object,
required: true
},
dimensions: {
type: Object,
required: true
}
});
const chartRef = ref();
let chart = null;
const colorList = ['#9E87FF', '#73DDFF', '#fe9a8b', '#F56948', '#9E87FF'];
const getOption = () => {
return {
title: {
text: '设备运行数量',
textStyle: {
fontSize: 12,
fontWeight: 400,
color: '#fff'
},
left: '0',
top: '5%'
},
legend: {
icon: 'circle',
top: '5%',
right: '5%',
itemWidth: 6,
itemGap: 20,
textStyle: {
color: '#fff'
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
label: {
show: true,
backgroundColor: '#fff',
color: '#000',
borderColor: 'rgba(0,0,0,0)',
shadowColor: 'rgba(0,0,0,0)',
shadowOffsetY: 0
},
lineStyle: {
width: 0
}
},
backgroundColor: '#fff',
textStyle: {
color: '#000'
},
padding: [10, 10],
extraCssText: 'box-shadow: 1px 0 2px 0 rgba(163,163,163,0.5)'
},
grid: {
top: '30%',
bottom: '10%'
},
xAxis: [
{
type: 'category',
data: props.inputData?.time || [],
axisLine: {
lineStyle: {
color: '#DCE2E8'
}
},
axisTick: {
show: true
},
axisLabel: {
interval: 0,
textStyle: {
color: '#fff'
},
// x
fontSize: 12,
// margin:x
margin: 3
},
axisPointer: {
label: {
padding: [0, 0, 0, 0],
margin: 0,
//
fontSize: 12
}
},
boundaryGap: true
}
],
yAxis: [
{
type: 'value',
axisTick: {
show: false
},
axisLine: {
show: true,
lineStyle: {
color: '#fff'
}
},
axisLabel: {
textStyle: {
color: '#fff'
}
},
splitLine: {
show: false
}
}
],
series: [
{
name: '数量',
type: 'line',
data: props.inputData?.value || [],
symbolSize: 1,
symbol: 'circle',
smooth: true,
yAxisIndex: 0,
showSymbol: false,
lineStyle: {
width: 1,
color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [
{
offset: 0,
color: '#9effff'
},
{
offset: 1,
color: '#9E87FF'
}
]),
shadowColor: 'rgba(158,135,255, 0.3)',
shadowBlur: 10,
shadowOffsetY: 20
},
itemStyle: {
normal: {
color: colorList[0],
borderColor: colorList[0]
}
}
}
]
};
};
const emit = defineEmits(['resize']);
const resize = (e) => {
chart.resize();
emit('resize', e, props.id);
};
const openMsgBox = () => {
MsgBoxVisible.value = true;
};
onMounted(() => {
chart = echarts.init(chartRef.value, 'macarons');
chart.setOption(getOption(), true);
});
watch(() => props.inputData, () => {
chart.setOption(getOption(), true);
}, { deep: true });
</script>
<style lang="less" scoped>
.custom-node {
width: 100%;
height: 100%;
}
.info {
position: absolute;
top: 0;
right: 0;
}
</style>

@ -0,0 +1,209 @@
<template>
<div
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px'}">
<NodeResizer color="#000" v-if="!props.isView && !props.isHideHandle && props.selected" @resize="resize" />
<div class="custom-node" :style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px',pointerEvents:props.isView?'auto': 'none'}">
<div style="width: 100%;height: 100%" ref="chartRef" />
</div>
<Handle v-if="!props.isView" :id="`${props.id}.-t`" type="target" :position="Position.Left" />
</div>
</template>
<script setup>
import { defineEmits, defineProps, ref } from 'vue';
import { NodeResizer } from '@vue-flow/node-resizer';
import { Handle, Position } from '@vue-flow/core';
import * as echarts from 'echarts';
const props = defineProps({
isView: {
type: Boolean,
required: false
},
inputData: {
type: Object,
required: false
},
id: {
type: String,
required: true
},
isHideHandle: {
type: Boolean,
required: false
},
selected: {
type: Boolean,
required: false
},
data: {
type: Object,
required: true
},
dimensions: {
type: Object,
required: true
}
});
const chartRef = ref();
let chart = null;
const colorList = ['#9E87FF', '#73DDFF', '#fe9a8b', '#F56948', '#9E87FF'];
const getOption = () => {
return {
title: {
text: '设备运行数量',
textStyle: {
fontSize: 12,
fontWeight: 400,
color: '#fff'
},
left: '0',
top: '5%'
},
legend: {
icon: 'circle',
top: '5%',
right: '5%',
itemWidth: 6,
itemGap: 20,
textStyle: {
color: '#fff'
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
label: {
show: true,
backgroundColor: '#fff',
color: '#000',
borderColor: 'rgba(0,0,0,0)',
shadowColor: 'rgba(0,0,0,0)',
shadowOffsetY: 0
},
lineStyle: {
width: 0
}
},
backgroundColor: '#fff',
textStyle: {
color: '#000'
},
padding: [10, 10],
extraCssText: 'box-shadow: 1px 0 2px 0 rgba(163,163,163,0.5)'
},
grid: {
top: '30%',
bottom: '10%'
},
xAxis: [
{
type: 'category',
data: props.inputData?.time || [],
axisLine: {
lineStyle: {
color: '#DCE2E8'
}
},
axisTick: {
show: true
},
axisLabel: {
interval: 0,
textStyle: {
color: '#fff'
},
// x
fontSize: 12,
// margin:x
margin: 3
},
axisPointer: {
label: {
padding: [0, 0, 0, 0],
margin: 0,
//
fontSize: 12
}
},
boundaryGap: true
}
],
yAxis: [
{
type: 'value',
axisTick: {
show: false
},
axisLine: {
show: true,
lineStyle: {
color: '#fff'
}
},
axisLabel: {
textStyle: {
color: '#fff'
}
},
splitLine: {
show: false
}
}
],
series: [
{
name: '数量',
type: 'line',
data: props.inputData?.value || [],
symbolSize: 1,
symbol: 'circle',
smooth: true,
yAxisIndex: 0,
showSymbol: false,
lineStyle: {
width: 1,
color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [
{
offset: 0,
color: '#9effff'
},
{
offset: 1,
color: '#9E87FF'
}
]),
shadowColor: 'rgba(158,135,255, 0.3)',
shadowBlur: 10,
shadowOffsetY: 20
},
itemStyle: {
normal: {
color: colorList[0],
borderColor: colorList[0]
}
}
}
]
};
};
onMounted(() => {
chart = echarts.init(chartRef.value, 'macarons');
chart.setOption(getOption(), true);
});
watch(() => props.inputData, () => {
chart.setOption(getOption(), true);
}, { deep: true });
const emit = defineEmits(['resize']);
const resize = (e) => {
chart.resize();
emit('resize', e, props.id);
};
</script>
<style scoped>
.custom-node {
width: 100%;
height: 100%;
}
</style>

@ -0,0 +1,94 @@
<template>
<div
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px'}">
<NodeResizer color="#000" v-if="!props.isView && !props.isHideHandle && props.selected" @resize="resize" />
<div class="custom-node" :style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px',pointerEvents:props.isView?'auto': 'none'}">
<el-button type="primary" :style="{width:props.dimensions.width +'px',height:props.dimensions.height+'px'}"
:icon="Connection">设备运行数量
</el-button>
<span style="color:#fff">
</span>
</div>
<Handle v-if="!props.isView" :id="`${props.id}.-t`" type="target" :position="Position.Left" />
<Handle v-if="!props.isView" :id="`${props.id}.-s`" type="source" :position="Position.Right" />
</div>
</template>
<script setup>
import { defineEmits, defineProps, ref } from 'vue';
import { NodeResizer } from '@vue-flow/node-resizer';
import { Connection } from '@element-plus/icons-vue';
import { Handle, Position } from '@vue-flow/core';
import axios from 'axios';
const props = defineProps({
isView: {
type: Boolean,
required: false
},
inputData: {
type: Object,
required: false
},
id: {
type: String,
required: true
},
isHideHandle: {
type: Boolean,
required: false
},
selected: {
type: Boolean,
required: false
},
data: {
type: Object,
required: true
},
dimensions: {
type: Object,
required: true
}
});
const service = axios.create({
baseURL: 'http://localhost:3000',
timeout: 10000
});
const getOutputData = () => {
service({
method: 'post',
url: '/test/getDevice',
data: props.inputData
}).then(res => {
props.data.outputData = {
time: res.data?.data?.map(e => e.time),
value: res.data?.data?.map(e => e.value)
};
});
};
onMounted(() => {
getOutputData();
});
let interval = setInterval(() => {
getOutputData();
}, 1000);
onBeforeUnmount(() => {
clearInterval(interval);
interval = null;
});
const emit = defineEmits(['resize']);
const resize = (e) => {
emit('resize', e, props.id);
};
</script>
<style scoped>
.custom-node {
width: 100%;
height: 100%;
}
</style>

@ -0,0 +1,65 @@
<template>
<div
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px'}">
<NodeResizer color="#000" v-if="!props.isView && !props.isHideHandle && props.selected" @resize="resize" />
<div class="custom-node" :style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px',pointerEvents:props.isView?'auto': 'none'}">
<el-input v-model="input" placeholder="输入值" style="width: 100%;height: 100%" />
</div>
<Handle v-if="!props.isView" :id="`${props.id}.-t`" type="target" :position="Position.Left" />
<Handle v-if="!props.isView" :id="`${props.id}.-s`" type="source" :position="Position.Right" />
</div>
</template>
<script setup>
import { defineEmits, defineProps, ref } from 'vue';
import { NodeResizer } from '@vue-flow/node-resizer';
import { Handle, Position } from '@vue-flow/core';
const input = ref('');
const props = defineProps({
isView: {
type: Boolean,
required: false
},
inputData: {
type: Object,
required: false
},
id: {
type: String,
required: true
},
isHideHandle: {
type: Boolean,
required: false
},
selected: {
type: Boolean,
required: false
},
data: {
type: Object,
required: true
},
dimensions: {
type: Object,
required: true
}
});
watch(() => input.value, () => {
if (props.data?.options?.field) {
props.data.outputData[props.data.options.field] = input.value;
}
}, { deep: true });
const emit = defineEmits(['resize']);
const resize = (e) => {
emit('resize', e, props.id);
};
</script>
<style scoped>
.custom-node {
position: absolute;
}
</style>

@ -0,0 +1,77 @@
<template>
<div
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px'}">
<NodeResizer color="#000" v-if="!props.isView && !props.isHideHandle && props.selected"
@resize="resize" />
<div class="custom-node"
:style="{width:props.dimensions.width+'px',height:props.dimensions.height+'px',pointerEvents:props.isView?'auto': 'none'}">
<el-date-picker
v-model="value"
type="datetimerange"
range-separator="到"
start-placeholder="开始时间"
end-placeholder="结束时间"
style="width: 100%;height: 100%"
/>
</div>
<Handle v-if="!props.isView" :id="`${props.id}.-t`" type="target" :position="Position.Left" />
<Handle v-if="!props.isView" :id="`${props.id}.-s`" type="source" :position="Position.Right" />
</div>
</template>
<script setup>
import { defineEmits, defineProps, ref } from 'vue';
import { NodeResizer } from '@vue-flow/node-resizer';
import { Handle, Position } from '@vue-flow/core';
const value = ref('');
const props = defineProps({
isView: {
type: Boolean,
required: false
},
inputData: {
type: Object,
required: false
},
id: {
type: String,
required: true
},
isHideHandle: {
type: Boolean,
required: false
},
selected: {
type: Boolean,
required: false
},
data: {
type: Object,
required: true
},
dimensions: {
type: Object,
required: true
}
});
watch(() => value, () => {
if (props.data?.options?.startTimeId) {
props.data.outputData[props.data.options.startTimeId || 'startTime'] = value.value[0];
}
if (props.data?.options?.endTimeId) {
props.data.outputData[props.data.options.endTimeId || 'endTime'] = value.value[1];
}
}, { deep: true });
const emit = defineEmits(['resize']);
const resize = (e) => {
emit('resize', e, props.id);
};
</script>
<style scoped>
.custom-node {
position: absolute;
}
</style>

@ -1,151 +0,0 @@
<template>
<div :style="`transform: rotate(${props.data.options?.rotate || 0}deg);cursor: progress;`">
<div class="custom-node" :style="{width:props.width}">
</div>
<NodeResizer :color="color || '#000' " v-if="!props.isHideHandle && props.selected" @resize="resize" />
</div>
</template>
<script setup>
import { defineEmits, defineProps, ref, watch } from 'vue';
import { Handle, Position } from '@vue-flow/core';
import { NodeResizer } from '@vue-flow/node-resizer';
const props = defineProps({
color: {
type: String,
required: false
},
id: {
type: String,
required: true
},
isAlm: {
type: Boolean,
required: false
},
isHideHandle: {
type: Boolean,
required: false
},
selected: {
type: Boolean,
required: false
},
data: {
type: Object,
required: true
},
dimensions: {
type: Object,
required: true
},
deviceData: {
type: Object,
required: false
}
});
const emit = defineEmits(['resize']);
const resize = (e) => {
emit('resize', e, props.id);
};
</script>
<style scoped>
.custom-node {
width: 100%;
height: 100%;
}
.counter {
position: relative;
width: 100%;
height: 100%;
}
.tsj-div {
width: 100%;
display: flex;
position: relative;
align-items: center;
justify-self: center;
overflow: hidden;
}
.tsj {
height: 300px;
}
.icon-tishengji1 {
position: absolute;
left: 50%;
top: 0;
transform: translateX(-50%);
}
.deviceIdAndName {
color: #fff;
position: absolute;
left: 100%;
width: 50%;
top: 0%;
white-space: pre-wrap;
text-align: left;
}
.info {
position: absolute;
top: 50%;
right: 100%;
transform: translateY(-50%);
color: #000;
}
.value {
display: inline-block;
width: 2vw;
height: 0.4vw;
line-height: 0.4vw;
font-size: 0.4vw;
text-align: center;
vertical-align: top;
background-color: #00ff02;
}
.unit {
display: inline-block;
width: 0.6vw;
height: 0.4vw;
line-height: 0.4vw;
font-size: 0.4vw;
text-align: center;
vertical-align: top;
background-color: #01a098;
}
.alarmInfo {
position: absolute;
top: 50%;
left: 50%;
width: 100%;
transform: translate(-50%, -50%);
text-align: center;
font-size: 0.4vw;
line-height: 0.6vw;
white-space: nowrap;
animation: colourSwitching 0.5s infinite;
pointer-events: none;
}
@keyframes colourSwitching {
0% {
color: #ffff00;
}
50% {
color: #ff0000;
}
100% {
color: #ffff00;
}
}
</style>

@ -0,0 +1,16 @@
<template>
<div style="pointer-events: none">
<div class="custom-node">
<div class="area" style="width:1910px;height:970px;border: 1px solid #fff"></div>
</div>
</div>
</template>
<script setup>
import { defineProps } from 'vue';
const props = defineProps({});
</script>
<style scoped>
</style>

@ -2,71 +2,96 @@ import { useVueFlow } from '@vue-flow/core';
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
const nodeType = ref('');
const { addNodes, screenToFlowCoordinate, onNodesInitialized, updateNode } = useVueFlow();
const getId = (type) => { const getId = (type) => {
return `${type}_${uuidv4().replaceAll('-', '_')}`; return `${type}_${uuidv4().replaceAll('-', '_')}`;
}; };
const onDragStart = (event, type) => {
if (event.dataTransfer) {
event.dataTransfer.setData('application/vueflow', type);
event.dataTransfer.effectAllowed = 'move';
}
nodeType.value = type;
document.addEventListener('drop', onDragEnd);
};
const onDragEnd = () => {
nodeType.value = null;
document.removeEventListener('drop', onDragEnd);
};
const getOption = (e) => { const getOption = (e) => {
return { if (e === 'line') {
deviceType: e, deviceName: '' return {};
}; } else if (e === 'data') {
return {};
} else if (e === 'inputNode') {
return { field: '' };
} else if (e === 'time') {
return { startTimeId: 'startTime', endTimeId: 'endTime' };
} else {
return {};
}
}; };
const getNodeSize = (e) => {
console.log(e);
const onDragOver = (event) => { if (e === 'line') {
event.preventDefault(); return { width: 300, height: 150 };
} else if (e === 'data') {
if (nodeType.value) { return { width: 200, height: 50 };
} else if (e === 'inputNode') {
if (event.dataTransfer) { return { width: 100, height: 30 };
event.dataTransfer.dropEffect = 'move'; } else {
} return { width: 100, height: 100 };
} }
}; };
const onDrop = (event) => { const tool = () => {
console.log('onDrop', event); const nodeType = ref('');
const position = screenToFlowCoordinate({ const { addNodes, screenToFlowCoordinate, onNodesInitialized, updateNode } = useVueFlow();
x: event.clientX, y: event.clientY const onDragStart = (event, type) => {
}); if (event.dataTransfer) {
event.dataTransfer.setData('application/vueflow', type);
event.dataTransfer.effectAllowed = 'move';
}
const nodeId = getId(nodeType.value); nodeType.value = type;
const newNode = { document.addEventListener('drop', onDragEnd);
id: nodeId, name: nodeType.value, type: nodeType.value, dimensions: {
width: 100, height: 60
}, position, data: { label: nodeId, options: getOption(nodeType.value), deviceData: {} }
}; };
const onDragEnd = () => {
nodeType.value = null;
document.removeEventListener('drop', onDragEnd);
};
const onDrop = (event) => {
console.log(event);
const dimensions = getNodeSize(nodeType.value);
const position = screenToFlowCoordinate({
x: event.clientX, y: event.clientY
});
const nodeId = getId(nodeType.value);
const newNode = {
id: nodeId,
name: nodeType.value,
type: nodeType.value,
dimensions,
position,
data: { label: nodeId, options: getOption(nodeType.value), outputData: {} }
};
const { off } = onNodesInitialized(() => { const { off } = onNodesInitialized(() => {
updateNode(nodeId, (node) => ({ updateNode(nodeId, (node) => ({
position: { x: node.position.x - node.dimensions.width / 2, y: node.position.y - node.dimensions.height / 2 } position: { x: node.position.x - node.dimensions.width / 2, y: node.position.y - node.dimensions.height / 2 }
})); }));
off(); off();
}); });
addNodes(newNode); addNodes(newNode);
};
const onDragOver = (event) => {
event.preventDefault();
if (nodeType.value) {
if (event.dataTransfer) {
event.dataTransfer.dropEffect = 'move';
}
}
};
return {
onDragStart, onDragEnd, onDrop, onDragOver
};
}; };
export default tool;
export {
onDragStart, onDragEnd, onDrop, onDragOver
};

@ -0,0 +1,381 @@
<template>
<div class="content" :style="{width:area.width+'px',height: area.height+'px'}">
<div v-for="i in nodes" class="node" :style="{left:i.position?.x+'px',top: i.position?.y+'px'}">
<template v-if="i.type === 'line'">
<LineNode :isView="true" :inputData=getInputData(i.id) v-bind="i"></LineNode>
</template>
<template v-if="i.type === 'data'">
<DataNode :isView="true" :inputData=getInputData(i.id) v-bind="i"></DataNode>
</template>
<template v-if="i.type === 'inputNode'">
<InputNode :isView="true" :inputData=getInputData(i.id) v-bind="i"></InputNode>
</template>
<template v-if="i.type === 'time'">
<TimeNode :isView="true" :inputData=getInputData(i.id) v-bind="i"></TimeNode>
</template>
</div>
</div>
</template>
<script setup lang="ts">
import TimeNode from '@/views/boardGenerate/nodes/form/timeNode.vue';
import DataNode from '@/views/boardGenerate/nodes/data/dataNode.vue';
import LineNode from '@/views/boardGenerate/nodes/board/lineNode.vue';
import InputNode from '@/views/boardGenerate/nodes/form/inputNode.vue';
const nodes = ref([
{
'id': 'area_474cfc79_4011_495e_9fb3_5e268ad09cfe',
'type': 'area',
'dimensions': { 'width': 1910, 'height': 970 },
'computedPosition': { 'x': 0, 'y': 0, 'z': 0 },
'handleBounds': { 'source': null, 'target': null },
'selected': false,
'dragging': false,
'resizing': false,
'initialized': false,
'isParent': false,
'position': { 'x': 0, 'y': 0 },
'data': { 'label': 'area_474cfc79_4011_495e_9fb3_5e268ad09cfe' },
'events': {},
'name': 'area'
},
{
'id': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'type': 'time',
'dimensions': { 'width': 100, 'height': 100 },
'computedPosition': { 'x': 106.65085072834671, 'y': 39.36769433739843, 'z': 0 },
'handleBounds': {
'source': [{
'id': 'time_500c79d5_2a5a_4369_a37f_98a90f792547.-s',
'type': 'source',
'nodeId': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'position': 'right',
'x': 97.00007501159526,
'y': 47.00005927633669,
'width': 6,
'height': 6
}],
'target': [{
'id': 'time_500c79d5_2a5a_4369_a37f_98a90f792547.-t',
'type': 'target',
'nodeId': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'position': 'left',
'x': -2.9999932235447186,
'y': 47.00005927633669,
'width': 6,
'height': 6
}]
},
'selected': false,
'dragging': false,
'resizing': false,
'initialized': false,
'isParent': false,
'position': { 'x': 106.65085072834671, 'y': 39.36769433739843 },
'data': {
'label': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'options': { 'startTimeId': 'startTime', 'endTimeId': 'endTime' },
'outputData': {}
},
'events': {},
'name': 'time'
},
{
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'type': 'data',
'dimensions': { 'width': 200, 'height': 50 },
'computedPosition': { 'x': 468.30045871559633, 'y': -251.0728211009174, 'z': 0 },
'handleBounds': {
'source': [{
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818.-s',
'type': 'source',
'nodeId': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'position': 'right',
'x': 197.00014324673523,
'y': 22.000023835240277,
'width': 6,
'height': 6
}],
'target': [{
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818.-t',
'type': 'target',
'nodeId': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'position': 'left',
'x': -2.9999932235447186,
'y': 22.000023835240277,
'width': 6,
'height': 6
}]
},
'selected': false,
'dragging': false,
'resizing': false,
'initialized': false,
'isParent': false,
'position': { 'x': 468.30045871559633, 'y': -251.0728211009174 },
'data': {
'label': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'options': {},
'outputData': {
'time': ['2025-01-01 00:00:00', '2025-01-03 00:00:00', '2025-01-05 00:00:00'],
'value': [20, 30, 40]
}
},
'events': {},
'name': 'data'
},
{
'id': 'line_77194e11_6df2_4e80_b9d7_816dac933f62',
'type': 'line',
'dimensions': { 'width': 300, 'height': 150 },
'computedPosition': { 'x': 94.76924191953978, 'y': 216.41751167721483, 'z': 1000 },
'handleBounds': {
'source': null,
'target': [{
'id': 'line_77194e11_6df2_4e80_b9d7_816dac933f62.-t',
'type': 'target',
'nodeId': 'line_77194e11_6df2_4e80_b9d7_816dac933f62',
'position': 'left',
'x': -2.9999932235447186,
'y': 72.00005795281027,
'width': 6,
'height': 6
}]
},
'selected': true,
'dragging': false,
'resizing': false,
'initialized': false,
'isParent': false,
'position': { 'x': 94.76924191953978, 'y': 216.41751167721483 },
'data': { 'label': 'line_77194e11_6df2_4e80_b9d7_816dac933f62', 'options': {}, 'outputData': {} },
'events': {},
'name': 'line'
}
]);
const edges = ref([
{
'id': 'time_500c79d5_2a5a_4369_a37f_98a90f792547---data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'type': 'bezier',
'source': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'target': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'sourceHandle': 'time_500c79d5_2a5a_4369_a37f_98a90f792547.-s',
'data': {},
'events': {},
'label': '',
'animated': true,
'markerEnd': 'arrowclosed',
'style': { 'stroke': '#409EFF' },
'sourceNode': {
'id': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'type': 'time',
'dimensions': { 'width': 100, 'height': 100 },
'computedPosition': { 'x': 106.65085072834671, 'y': 39.36769433739843, 'z': 0 },
'handleBounds': {
'source': [{
'id': 'time_500c79d5_2a5a_4369_a37f_98a90f792547.-s',
'type': 'source',
'nodeId': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'position': 'right',
'x': 97.00007501159526,
'y': 47.00005927633669,
'width': 6,
'height': 6
}],
'target': [{
'id': 'time_500c79d5_2a5a_4369_a37f_98a90f792547.-t',
'type': 'target',
'nodeId': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'position': 'left',
'x': -2.9999932235447186,
'y': 47.00005927633669,
'width': 6,
'height': 6
}]
},
'selected': false,
'dragging': false,
'resizing': false,
'initialized': false,
'isParent': false,
'position': { 'x': 106.65085072834671, 'y': 39.36769433739843 },
'data': {
'label': 'time_500c79d5_2a5a_4369_a37f_98a90f792547',
'options': { 'startTimeId': 'startTime', 'endTimeId': 'endTime' },
'outputData': {}
},
'events': {},
'name': 'time'
},
'targetNode': {
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'type': 'data',
'dimensions': { 'width': 200, 'height': 50 },
'computedPosition': { 'x': 468.30045871559633, 'y': -251.0728211009174, 'z': 0 },
'handleBounds': {
'source': [{
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818.-s',
'type': 'source',
'nodeId': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'position': 'right',
'x': 197.00014324673523,
'y': 22.000023835240277,
'width': 6,
'height': 6
}],
'target': [{
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818.-t',
'type': 'target',
'nodeId': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'position': 'left',
'x': -2.9999932235447186,
'y': 22.000023835240277,
'width': 6,
'height': 6
}]
},
'selected': false,
'dragging': false,
'resizing': false,
'initialized': false,
'isParent': false,
'position': { 'x': 468.30045871559633, 'y': -251.0728211009174 },
'data': {
'label': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'options': {},
'outputData': {
'time': ['2025-01-01 00:00:00', '2025-01-03 00:00:00', '2025-01-05 00:00:00'],
'value': [20, 30, 40]
}
},
'events': {},
'name': 'data'
},
'sourceX': 209.65092573994195,
'sourceY': 89.36775361373512,
'targetX': 465.3004654920516,
'targetY': -226.0727972656771
},
{
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818---line_77194e11_6df2_4e80_b9d7_816dac933f62',
'type': 'bezier',
'source': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'target': 'line_77194e11_6df2_4e80_b9d7_816dac933f62',
'sourceHandle': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818.-s',
'data': {},
'events': {},
'label': '',
'animated': true,
'markerEnd': 'arrowclosed',
'style': { 'stroke': '#409EFF' },
'sourceNode': {
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'type': 'data',
'dimensions': { 'width': 200, 'height': 50 },
'computedPosition': { 'x': 468.30045871559633, 'y': -251.0728211009174, 'z': 0 },
'handleBounds': {
'source': [{
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818.-s',
'type': 'source',
'nodeId': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'position': 'right',
'x': 197.00014324673523,
'y': 22.000023835240277,
'width': 6,
'height': 6
}],
'target': [{
'id': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818.-t',
'type': 'target',
'nodeId': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'position': 'left',
'x': -2.9999932235447186,
'y': 22.000023835240277,
'width': 6,
'height': 6
}]
},
'selected': false,
'dragging': false,
'resizing': false,
'initialized': false,
'isParent': false,
'position': { 'x': 468.30045871559633, 'y': -251.0728211009174 },
'data': {
'label': 'data_b9663ba9_503c_449a_a24b_1d2cceaa3818',
'options': {},
'outputData': {
'time': ['2025-01-01 00:00:00', '2025-01-03 00:00:00', '2025-01-05 00:00:00'],
'value': [20, 30, 40]
}
},
'events': {},
'name': 'data'
},
'targetNode': {
'id': 'line_77194e11_6df2_4e80_b9d7_816dac933f62',
'type': 'line',
'dimensions': { 'width': 300, 'height': 150 },
'computedPosition': { 'x': 94.76924191953978, 'y': 216.41751167721483, 'z': 1000 },
'handleBounds': {
'source': null,
'target': [{
'id': 'line_77194e11_6df2_4e80_b9d7_816dac933f62.-t',
'type': 'target',
'nodeId': 'line_77194e11_6df2_4e80_b9d7_816dac933f62',
'position': 'left',
'x': -2.9999932235447186,
'y': 72.00005795281027,
'width': 6,
'height': 6
}]
},
'selected': true,
'dragging': false,
'resizing': false,
'initialized': false,
'isParent': false,
'position': { 'x': 94.76924191953978, 'y': 216.41751167721483 },
'data': { 'label': 'line_77194e11_6df2_4e80_b9d7_816dac933f62', 'options': {}, 'outputData': {} },
'events': {},
'name': 'line'
},
'sourceX': 671.3006019623316,
'sourceY': -226.0727972656771,
'targetX': 91.76924869599506,
'targetY': 291.4175696300251
}
]);
const area = ref({
width: 1910,
height: 970
});
const getInputData = (e) => {
let outputData = {};
let nodeIds = edges.value.map(v => {
if (v.target === e) {
return v.source;
}
});
nodes.value.forEach(v => {
if (nodeIds.includes(v.id)) {
outputData = {
...outputData,
...v.data.outputData
};
}
});
console.log(outputData);
return outputData;
};
</script>
<style lang="less" scoped>
.content {
position: absolute;
background-color: #000;
}
.node {
position: absolute;
}
</style>
Loading…
Cancel
Save