修改组态化
parent
ea59268910
commit
c1347b14d3
@ -0,0 +1,80 @@
|
|||||||
|
<template>
|
||||||
|
<div class="leftPanel">
|
||||||
|
<el-tabs v-model="leftPanelState" class="demo-tabs" type="border-card">
|
||||||
|
<el-tab-pane label="图表组件" name="1">
|
||||||
|
<el-card style="width: 80px" shadow="never" :draggable="true"
|
||||||
|
@dragstart="onDragStart($event, 'line')" :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="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>
|
||||||
|
</div>
|
||||||
|
<div class="content" @drop="onDrop">
|
||||||
|
<VueFlow :min-zoom="0.01" ref="flowRef" v-model:nodes="nodes" v-model:edges="edges" fit-view-on-init
|
||||||
|
default-marker-color="#409EFF"
|
||||||
|
@node-click="logEvent('click', $event)"
|
||||||
|
@node-contextMenu="logEvent('contextmenu', $event)"
|
||||||
|
@dragover="onDragOver"
|
||||||
|
>
|
||||||
|
<Background :size="1" :gap="20" pattern-color="#BDBDBD" />
|
||||||
|
<template #node-line="lineNodeProps">
|
||||||
|
<LineNdoe v-bind="lineNodeProps"
|
||||||
|
@resize="resize"></LineNdoe>
|
||||||
|
</template>
|
||||||
|
</VueFlow>
|
||||||
|
</div>
|
||||||
|
<div class="rightPanel"></div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { VueFlow, useVueFlow } from '@vue-flow/core';
|
||||||
|
import { Background } from '@vue-flow/background';
|
||||||
|
import { StarFilled } from '@element-plus/icons-vue';
|
||||||
|
import { onDragStart, onDrop, onDragOver } from './tool';
|
||||||
|
|
||||||
|
const leftPanelState = ref('1');
|
||||||
|
const nodes = ref([]);
|
||||||
|
const edges = ref([]);
|
||||||
|
const logEvent = async (eventname, event) => {
|
||||||
|
switch (eventname) {
|
||||||
|
case 'click':
|
||||||
|
console.log('click', event);
|
||||||
|
break;
|
||||||
|
case 'contextmenu':
|
||||||
|
console.log('contextmenu', event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.leftPanel {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 300px;
|
||||||
|
height: 100%;
|
||||||
|
border-right: 1px solid #409EFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 320px;
|
||||||
|
width: calc(100% - 320px - 320px);
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rightPanel {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 300px;
|
||||||
|
height: 100%;
|
||||||
|
border-left: 1px solid #409EFF;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,151 @@
|
|||||||
|
<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,72 @@
|
|||||||
|
import { useVueFlow } from '@vue-flow/core';
|
||||||
|
import { ref, watch } from 'vue';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
const nodeType = ref('');
|
||||||
|
const { addNodes, screenToFlowCoordinate, onNodesInitialized, updateNode } = useVueFlow();
|
||||||
|
|
||||||
|
const getId = (type) => {
|
||||||
|
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) => {
|
||||||
|
return {
|
||||||
|
deviceType: e, deviceName: ''
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const onDragOver = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (nodeType.value) {
|
||||||
|
|
||||||
|
if (event.dataTransfer) {
|
||||||
|
event.dataTransfer.dropEffect = 'move';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDrop = (event) => {
|
||||||
|
console.log('onDrop', event);
|
||||||
|
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: {
|
||||||
|
width: 100, height: 60
|
||||||
|
}, position, data: { label: nodeId, options: getOption(nodeType.value), deviceData: {} }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const { off } = onNodesInitialized(() => {
|
||||||
|
updateNode(nodeId, (node) => ({
|
||||||
|
position: { x: node.position.x - node.dimensions.width / 2, y: node.position.y - node.dimensions.height / 2 }
|
||||||
|
}));
|
||||||
|
|
||||||
|
off();
|
||||||
|
});
|
||||||
|
|
||||||
|
addNodes(newNode);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
onDragStart, onDragEnd, onDrop, onDragOver
|
||||||
|
};
|
Loading…
Reference in New Issue