Files
pqs-9100_client/frontend/src/views/home/components/channelPairing.vue

841 lines
31 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<div class="flow-container" style="overflow: hidden; position: relative"
:style="{ height: vueFlowElement + 'px' }">
<!-- <el-button @click="logConnections">打印当前配对</el-button> -->
<VueFlow :nodes="nodes" :edges="edges" :connection-radius="30" :nodes-draggable="false" :dragging="false"
:zoom-on-scroll="false" :pan-on-drag="false" :disable-zoom-pan-on-connect="true"
:prevent-scrolling="true" :fit-view="true" :min-zoom="1" :max-zoom="1"
:nodesConnectable="checkStore.nodesConnectable" :elements-selectable="false" auto-connect
@connect="handleConnect" @connect-start="handleConnectStart" @connect-end="handleConnectEnd"
@pane-ready="onPaneReady" @node-double-click="handleNodeDoubleClick" v-on:pane-mouse-move="false"></VueFlow>
</div>
<!-- 底部操作按钮 -->
<!-- <template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleNext">下一步</el-button>
</div>
</template> -->
<!-- 手动检测-勾选检测项弹窗 -->
<!-- <SelectTestItemPopup ref="selectTestItemPopupRef" @openTestDialog="openTestDialog"></SelectTestItemPopup> -->
</div>
</template>
<script lang="ts" setup>
import { h, ref, onMounted, PropType, computed } from 'vue'
import { VueFlow, useVueFlow } from '@vue-flow/core'
import { dialogBig } from '@/utils/elementBind'
import { Platform, Flag } from '@element-plus/icons-vue'
import { Device } from '@/api/device/interface/device'
import { StandardDevice } from '@/api/device/interface/standardDevice'
import SelectTestItemPopup from '@/views/home/components/selectTestItemPopup.vue'
import { ElMessage, stepProps } from 'element-plus'
import CustomEdge from './RemoveableEdge.vue' // 导入自定义连接线组件
import { jwtUtil } from '@/utils/jwtUtil'
import { useCheckStore } from '@/stores/modules/check'
import { ipc } from '@/utils/ipcRenderer'
import { fa, tr } from 'element-plus/es/locale'
import { CheckData } from '@/api/check/interface'
const vueFlowElement = ref(442)
const checkStore = useCheckStore()
const dialogVisible = ref(false)
const selectTestItemPopupRef = ref<InstanceType<typeof SelectTestItemPopup>>()
const testPopup = ref()
const dialogTitle = ref('手动检测')
const prop = defineProps({
devIdList: {
type: Array as any,
default: []
},
pqStandardDevList: {
type: Array as any,
default: []
},
planIdKey: {
type: String,
default: ''
},
deviceMonitor: {
type: Map as PropType<Map<string, any[]>>,
default: () => new Map()
},
dialogWidth: {
type: Number,
default: 0
}
})
// 计算对话框高度
const dialogHeight = ref(600)
// 初始化 VueFlow注册自定义连线类型
const { edges, setViewport,removeEdges } = useVueFlow({
edgeTypes: {
default: CustomEdge
}
})
const handleNodeDoubleClick = (event: any) => {
const { node } = event
// 判断节点类型
if (node.type === 'input') {
// 被检通道节点,检查是否已经连接
const isConnected = edges.value.some(edge => edge.source === node.id)
if (isConnected) {
ElMessage.warning('该被检通道已经连接,不能重复连接')
return
}
// 寻找未连接的标准通道节点(优先寻找未被连接的标准通道)
const targetNodes = nodes.value.filter(n => n.type === 'output')
// 首先尝试连接尚未被连接的标准通道
for (const targetNode of targetNodes) {
const isTargetConnected = edges.value.some(edge => edge.target === targetNode.id)
if (!isTargetConnected) {
// 检查是否已存在连接(虽然这里应该不会存在)
const isAlreadyConnected = edges.value.some(edge =>
edge.source === node.id && edge.target === targetNode.id
)
if (!isAlreadyConnected) {
const newEdge = {
id: `edge-${node.id}-${targetNode.id}`,
source: node.id,
target: targetNode.id,
type: 'default'
}
edges.value.push(newEdge)
return
}
}
}
// 如果所有标准通道都已被连接,尝试连接已被连接但连接的是其他被检通道的标准通道
for (const targetNode of targetNodes) {
// 检查是否已存在连接
const isAlreadyConnected = edges.value.some(edge =>
edge.source === node.id && edge.target === targetNode.id
)
if (!isAlreadyConnected) {
const isTargetConnected = edges.value.some(edge => edge.target === targetNode.id)
// 如果标准通道已被连接,但不是连接到当前被检通道,则不能连接
if (isTargetConnected) {
continue
}
const newEdge = {
id: `edge-${node.id}-${targetNode.id}`,
source: node.id,
target: targetNode.id,
type: 'default'
}
edges.value.push(newEdge)
ElMessage.success(`已自动连接到 ${targetNode.data.label.children[1].children[0].children[0].replace('设备名称:', '')} 的标准通道`)
return
}
}
ElMessage.warning('没有可用的标准通道进行连接')
} else if (node.type === 'output') {
// 标准通道节点,检查是否已经连接
const isConnected = edges.value.some(edge => edge.target === node.id)
if (isConnected) {
ElMessage.warning('该标准通道已经连接,不能重复连接')
return
}
// 寻找未连接的被检通道节点(优先寻找未被连接的被检通道)
const sourceNodes = nodes.value.filter(n => n.type === 'input')
// 首先尝试连接尚未被连接的被检通道
for (const sourceNode of sourceNodes) {
const isSourceConnected = edges.value.some(edge => edge.source === sourceNode.id)
if (!isSourceConnected) {
// 检查是否已存在连接(虽然这里应该不会存在)
const isAlreadyConnected = edges.value.some(edge =>
edge.source === sourceNode.id && edge.target === node.id
)
if (!isAlreadyConnected) {
const newEdge = {
id: `edge-${sourceNode.id}-${node.id}`,
source: sourceNode.id,
target: node.id,
type: 'default'
}
edges.value.push(newEdge)
return
}
}
}
// 如果所有被检通道都已被连接,尝试连接已被连接但连接的是其他标准通道的被检通道
for (const sourceNode of sourceNodes) {
// 检查是否已存在连接
const isAlreadyConnected = edges.value.some(edge =>
edge.source === sourceNode.id && edge.target === node.id
)
if (!isAlreadyConnected) {
const isSourceConnected = edges.value.some(edge => edge.source === sourceNode.id)
// 如果被检通道已被连接,但不是连接到当前标准通道,则不能连接
if (isSourceConnected) {
continue
}
const newEdge = {
id: `edge-${sourceNode.id}-${node.id}`,
source: sourceNode.id,
target: node.id,
type: 'default'
}
edges.value.push(newEdge)
return
}
}
ElMessage.warning('没有可用的被检通道进行连接')
}
}
// 初始化时锁定画布位置
const onPaneReady = () => {
setViewport({ x: 0, y: 0, zoom: 1 })
}
// 提取公共的label渲染函数
const createLabel = (device:any, Key: number) => {
return h(
'div',
{
style: {
display: 'flex',
// flexDirection: 'column',
alignItems: 'center',
fontSize: '15px',
height: '75px',
// textAlign: 'center',
border: '1px solid #ccc',
borderRadius: '8px',
padding: '8px',
backgroundColor: '#f9f9f9'
}
},
[
// h(Platform, {
// style: {
// height: '40px',
// marginBottom: '4px',
// color: '#526ade'
// }
// }),
h('img', {
src:
Key == 2
? new URL('@/assets/images/inspected1.jpg', import.meta.url).href
: new URL('@/assets/images/inspected2.png', import.meta.url).href,
// alt: '设备图标',
style: {
width: '50px',
marginRight: '5px'
// 保持原有的颜色风格,如果需要可以调整滤镜
// filter: 'invert(35%) sepia(65%) saturate(300%) hue-rotate(210deg)'
}
}),
h('div', { style: { textAlign: 'left' } }, ['设备名称:' + device.name,
h('br'),
'设备类型:' + device.deviceType,
h('br'),
'Ip地址' + device.ip,
])
// h('div', null, '设备名称:' + text),
// h('div', null, '设备类型:' + type)
]
) as any
}
const createLabel3 = (text: string) => {
return h(
'div',
{
style: {
display: 'flex',
alignItems: 'center',
fontSize: '15px',
height: '35px',
textAlign: 'center',
border: '1px solid #ccc',
borderRadius: '8px',
// padding: '8px',
backgroundColor: '#f9f9f9'
}
},
[
h('div', {
style: {
width: '8px',
marginRight: '4px',
color: '#526ade'
}
}),
text
]
) as any
}
const handleConnectStart = (params: any) => {
onPaneReady()
}
// const handleConnectEnd = (params: any) => {
// console.log('handleConnectEnd',edges.value,edges.value.length)
// onPaneReady()
// }
// const handleConnect = (params: any) => {
// const sourceNode = nodes.value.find(node => node.id === params.source)
// const targetNode = nodes.value.find(node => node.id === params.target)
// const isValidConnection = sourceNode?.type === 'input' && targetNode?.type === 'output'
// if (!isValidConnection) {
// removeEdge(params)
// ElMessage.warning('只能从被检通道连接到标准通道')
// return
// }
// // 过滤掉当前连接,检查是否还有重复的
// const existingEdges = edges.value.filter(edge => edge.source === params.source || edge.target === params.target)
// // 如果同源或同目标的连接超过1个说明有重复
// if (existingEdges.length > 1) {
// const duplicateSource = existingEdges.filter(edge => edge.source === params.source).length > 1
// const duplicateTarget = existingEdges.filter(edge => edge.target === params.target).length > 1
// if (duplicateSource) {
// removeEdge(params)
// ElMessage.warning('该被检通道已经连接,不能重复连接')
// return
// }
// if (duplicateTarget) {
// removeEdge(params)
// ElMessage.warning('该标准通道已经连接,不能重复连接')
// return
// }
// }
// }
// // 删除不合法连接
// const removeEdge = (params: any) => {
// // console.log('删除不合法连接:', params);
// // console.log('删除连接信息:', edges.value);
// // console.log('11111===', edges.value.length);
// const edgeIndex = edges.value.findIndex(edge => edge.source === params.source && edge.target === params.target)
// console.log('删除连接索引:', edgeIndex);
// if (edgeIndex !== -1) {
// edges.value.splice(edgeIndex , 1)
// }
// }
// 添加一个响应式变量来存储需要删除的连接信息
const pendingRemoveEdge = ref<any>(null)
const handleConnectEnd = (params: any) => {
// 在连接结束时检查是否有待删除的连接
if (pendingRemoveEdge.value) {
removeEdge(pendingRemoveEdge.value)
pendingRemoveEdge.value = null // 清空待删除连接
}
onPaneReady()
}
const handleConnect = (params: any) => {
const sourceNode = nodes.value.find(node => node.id === params.source)
const targetNode = nodes.value.find(node => node.id === params.target)
const isValidConnection = sourceNode?.type === 'input' && targetNode?.type === 'output'
if (!isValidConnection) {
// 设置待删除连接而不是立即删除
pendingRemoveEdge.value = params
ElMessage.warning('只能从被检通道连接到标准通道')
return
}
// 检查是否已经存在完全相同的连接(精确匹配源和目标)
const isAlreadyConnected = edges.value.some(edge =>
edge.source === params.source && edge.target === params.target
)
if (isAlreadyConnected) {
// 设置待删除连接而不是立即删除
pendingRemoveEdge.value = params
ElMessage.warning('这两个通道已经连接,不能重复连接')
return
}
// 检查源节点是否已经被连接(一个被检通道只能连接一个标准通道)
const isSourceConnected = edges.value.some(edge => edge.source === params.source)
if (isSourceConnected) {
// 设置待删除连接而不是立即删除
pendingRemoveEdge.value = params
ElMessage.warning('该被检通道已经连接,不能重复连接')
return
}
// 检查目标节点是否已经被连接(一个标准通道只能连接一个被检通道)
const isTargetConnected = edges.value.some(edge => edge.target === params.target)
if (isTargetConnected) {
// 设置待删除连接而不是立即删除
pendingRemoveEdge.value = params
ElMessage.warning('该标准通道已经连接,不能重复连接')
return
}
// 如果没有问题,清空待删除连接
pendingRemoveEdge.value = null
}
// 删除不合法连接
const removeEdge = (params: any) => {
const edgeIndex = edges.value.findIndex(edge => edge.source === params.source && edge.target === params.target)
if (edgeIndex !== -1) {
edges.value.splice(edgeIndex, 1)
}
}
const nodes = ref([])
const planId = ref('')
const devIds = ref<string[]>()
const standardDevIds = ref<string[]>()
const open = async () => {
edges.value = []
//devIds.value = prop.devIdList.map(d => d.id)
standardDevIds.value = prop.pqStandardDevList.map(d => d.id)
planId.value = prop.planIdKey
nodes.value = createNodes(prop.devIdList, prop.pqStandardDevList, prop.deviceMonitor)
dialogVisible.value = true
onPaneReady()
}
onMounted(() => {
open()
})
const handleNext = async () => {
if (edges.value.length === 0) {
ElMessage.warning('请先完成通道配对')
return false
}
// const sourceKey = edge.source.replace('被检通道-', '').replace('-', '_');
let chnNumList: string[] = []
await edges.value.forEach(edge => {
const match = edge.source.split('-')
if (match) {
chnNumList.push(match[1] + '-'+ match[2])
}
})
const connectedDeviceIds = [...new Set(chnNumList.map(item => item.split('-')[0]))]
devIds.value = connectedDeviceIds
//可能存在勾选的被检设备未连线的情况,需要过滤掉
let devices: CheckData.Device[] = prop.devIdList
.filter((item: any) => connectedDeviceIds.includes(item.id))
.map((item: any) => {
return {
deviceId: item.id,
deviceName: item.name,
chnNum: item.devChns,
planId: item.planId,
deviceType: item.devType,
devVolt: item.devVolt,
devCurr: item.devCurr,
factorFlag: item.factorFlag,
checkResult: item.checkResult
}
})
checkStore.clearDevices()
checkStore.addDevices(devices)
const connections = edges.value.reduce(
(map, edge) => {
// 从source中提取设备ID和通道号: 被检通道-{deviceId}-{channelNum} => {deviceId}-{channelNum}
const sourceKey = edge.source.replace('被检通道-', '').replace('-', '_')
// 从target中提取设备ID和通道号: 标准通道-{deviceId}-{channelNum} => {deviceId}-{channelNum}
const targetValue = edge.target.replace('标准通道-', '').replace('-', '_')
map[sourceKey] = targetValue
return map
},
{} as Record<string, string>
)
await generateChannelMapping()
await checkStore.setChnNum(chnNumList)
return {
title: dialogTitle.value,
mapping: channelMapping.value,
plan: planId.value,
login: jwtUtil.getLoginName(),
devIdsArray: devIds.value,
standardDevIdsArray: standardDevIds.value,
pair: connections
}
}
const openTestDialog = async () => {
// 转换连接信息只保留设备ID和通道号
const connections = edges.value.reduce(
(map, edge) => {
// 从source中提取设备ID和通道号: 被检通道-{deviceId}-{channelNum} => {deviceId}-{channelNum}
const sourceKey = edge.source.replace('被检通道-', '').replace('-', '_')
// 从target中提取设备ID和通道号: 标准通道-{deviceId}-{channelNum} => {deviceId}-{channelNum}
const targetValue = edge.target.replace('标准通道-', '').replace('-', '_')
map[sourceKey] = targetValue
return map
},
{} as Record<string, string>
)
generateChannelMapping()
setTimeout(() => {
testPopup.value?.open(
dialogTitle.value,
channelMapping.value,
planId.value,
jwtUtil.getLoginName(),
devIds.value,
standardDevIds.value,
connections
)
}, 100)
}
// 转换 edges.value 为 channelMapping 格式
const channelMapping = ref<Record<string, Record<string, string>>>({})
// 生成映射关系的方法
const generateChannelMapping = () => {
const mapping: Record<string, Record<string, string>> = {}
edges.value.forEach(edge => {
// 解析 source 节点信息(被检通道)
const sourceParts = edge.source.split('-')
const sourceDeviceId = sourceParts[1]
const sourceChannel = sourceParts[2]
// 解析 target 节点信息(标准通道)
const targetParts = edge.target.split('-')
const targetDeviceId = targetParts[1]
const targetChannel = targetParts[2]
// 查找对应的节点以获取显示名称
const sourceDeviceNode = nodes.value.find(node => node.id === sourceDeviceId)
const targetDeviceNode = nodes.value.find(node => node.id === targetDeviceId)
if (sourceDeviceNode && targetDeviceNode) {
// 提取设备显示文本
const sourceDeviceText = sourceDeviceNode.data.label.children[1].children[0].children
const targetDeviceText = targetDeviceNode.data.label.children[1].children[0].children
// 构造键名 - 现在以标准设备为键
const targetKey = `${targetDeviceText}`.replace('设备名称:', '')
const sourceValue = `${sourceDeviceText}通道${sourceChannel}`.replace('设备名称:', '')
// 初始化对象
if (!mapping[targetKey]) {
mapping[targetKey] = {}
}
// 添加映射关系 - 标准设备通道 -> 被检设备信息
mapping[targetKey][`通道${targetChannel}`] = sourceValue
}
})
channelMapping.value = mapping
}
// 计算基于 dialogWidth 的位置参数 - 确保最小距离
const standardWidthVal = computed(() => {
return Math.max(0, 50)
})
const inputChannelXVal = computed(() => {
return Math.max(300, standardWidthVal.value + 300)
})
const outputChannelXVal = computed(() => {
return Math.max(600, prop.dialogWidth - 500)
})
const deviceWidthVal = computed(() => {
return Math.max(800, prop.dialogWidth - 350)
})
const createNodes = (device: Device.ResPqDev[], standardDev: StandardDevice.ResPqStandardDevice[], deviceMonitor: Map<string, any[]>) => {
const channelCounts: Record<string, number> = {}
device.forEach(device => {
channelCounts[device.id] = device.devChns || 0
})
const inspectionDevices = device.map(d => ({
id: d.id,
name: d.name,
type: 'normal',
deviceType: d.devType,
ip: d.ip,
monitorResults:d.monitorResults
}))
const channelCounts2: Record<string, number> = {}
standardDev.forEach(dev => {
const channelList = dev.inspectChannel ? dev.inspectChannel.split(',') : []
channelCounts2[dev.id] = channelList.length
})
const standardDevices = standardDev.map(d => ({
id: d.id,
name: d.name,
type: 'normal',
deviceType: d.devType,
ip: d.ip
}))
const newNodes: any[] = []
const deviceChannelGroups: { deviceId: string; centerY: number }[] = []
const standardChannelGroups: any[] = []
// const deviceWidth = 50
// const inputChannelX = 350
// const outputChannelX = 1050
// const standardWidth = 1170
const standardWidth = standardWidthVal.value
const outputChannelX = inputChannelXVal.value
const inputChannelX = outputChannelXVal.value
const deviceWidth = deviceWidthVal.value
// 添加被检通道
// let currentYPosition = 50; // 初始Y位置
let actualChannelsTotalLength = 0;
for (const [deviceId, count] of Object.entries(channelCounts)) {
// 直接计算当前设备的通道数并累加,无需完整构建数组
actualChannelsTotalLength += deviceMonitor.has(deviceId)
? (deviceMonitor.get(deviceId) || []).length
: count;
}
let currentYPosition = (vueFlowElement.value - 60 * actualChannelsTotalLength) / 2; // 初始Y位置
const deviceSpacing = 30; // 设备间的垂直间距
Object.entries(channelCounts).forEach(([deviceId, count]) => {
// 从deviceMonitor中获取实际通道信息
let actualChannels = []; // 存储实际的通道号
let deviceMonitorResults: number[] = []; // 存储该设备的监控结果
// 获取该设备的monitorResults
const deviceInfo = inspectionDevices.find(d => d.id === deviceId);
if (deviceInfo && deviceInfo.monitorResults) {
deviceMonitorResults = deviceInfo.monitorResults;
}
// 如果deviceMonitor中有该设备的数据则使用实际监测点信息
if (deviceMonitor.has(deviceId)) {
const monitorPoints = deviceMonitor.get(deviceId) || [];
// 提取监测点的num值作为通道号
actualChannels = monitorPoints.map(point => point.num);
//console.log('deviceId', deviceId, '实际通道号:', actualChannels, '监测点:', monitorPoints);
} else {
// 如果没有monitor数据默认使用连续的通道号
actualChannels = Array.from({ length: count }, (_, i) => i + 1);
}
const yPosition = currentYPosition;
// 遍历实际通道号而不是连续的数字
actualChannels.forEach((channelNum, index) => {
const channelId = `被检通道-${deviceId}-${channelNum}`;
const channelResult = deviceMonitorResults[index]
let statusText = '';
if (channelResult === 0) {
statusText = '(不符合)';
} else if (channelResult === 1) {
statusText = '(符合)';
} else if (channelResult === 2) {
statusText = '(未检)';
}
newNodes.push({
id: channelId,
type: 'input',
data: { label: createLabel3(`被检通道${channelNum}`+ statusText) },
position: { x: inputChannelX, y: yPosition + index * 50 },
sourcePosition: 'left',
style: { width: '160px', border: 'none', boxShadow: 'none' }
});
deviceChannelGroups.push({
deviceId,
centerY: 0
});
});
// 更新currentYPosition为下一台设备留出空间
// 每台设备需要的空间 = 实际通道数 * 50 + 设备间距
currentYPosition += actualChannels.length * 50 + deviceSpacing;
});
// 添加标准通道
// let currentYPosition2 = 50; // 初始Y位置
let totalCount = 0;
// 遍历所有条目并累加 count 值
Object.entries(channelCounts2).forEach(([deviceId, count]) => {
totalCount += count;
});
let currentYPosition2 = (vueFlowElement.value - 60 * totalCount) / 2; // 初始Y位置; // 初始Y位置
const standardDeviceSpacing = 30; // 标准设备间的垂直间距
Object.entries(channelCounts2).forEach(([deviceId, count]) => {
const yPosition2 = currentYPosition2;
for (let i = 1; i <= count; i++) {
const channelId = `标准通道-${deviceId}-${i}`;
newNodes.push({
id: channelId,
type: 'output',
data: { label: createLabel3(`标准通道${i}`) },
position: { x: outputChannelX, y: yPosition2 + (i - 1) * 50 },
targetPosition: 'right',
style: { width: '120px', border: 'none', boxShadow: 'none' }
});
standardChannelGroups.push({
deviceId,
centerY: 0
});
}
// 更新currentYPosition2为下一台标准设备留出空间
currentYPosition2 += count * 50 + standardDeviceSpacing;
});
// 添加被检设备
// let deviceCurrentYPosition = 50; // 与通道计算保持一致的初始位置
let deviceCurrentYPosition = (vueFlowElement.value - 60 * actualChannelsTotalLength) / 2; // 与通道计算保持一致的初始位置
let lastDeviceId = ''; // 记录上一个处理的设备ID
deviceChannelGroups.forEach(({ deviceId, centerY }) => {
const device = inspectionDevices.find(d => d.id === deviceId)
if (device) {
// 只有当设备ID变化时才计算新位置
if (lastDeviceId !== deviceId) {
// 计算该设备对应的实际通道数量
let actualChannelCount = channelCounts[deviceId] || 0;
// 如果deviceMonitor中有该设备的数据则使用实际监测点数量
if (deviceMonitor.has(deviceId)) {
const monitorPoints = deviceMonitor.get(deviceId) || [];
actualChannelCount = monitorPoints.length;
}
// 计算设备高度居中位置 - 基于该设备组的实际位置
const deviceCenterY = deviceCurrentYPosition + (actualChannelCount * 50) / 2 - 50
newNodes.push({
id: device.id,
data: { label: createLabel(device, 1) },
position: { x: deviceWidth, y: deviceCenterY },
class: 'no-handle-node',
style: { width: '300px', border: 'none', boxShadow: 'none' }
})
// 更新位置为下一台设备的起始位置
deviceCurrentYPosition += actualChannelCount * 50 + 30
// 更新上一个设备ID
lastDeviceId = deviceId
}
}
})
// 添加标准设备
// let standardDeviceCurrentYPosition = 50; // 与标准通道计算保持一致的初始位置
let standardDeviceCurrentYPosition = (vueFlowElement.value - 60 * totalCount) / 2; // 与标准通道计算保持一致的初始位置
let lastStandardDeviceId = ''; // 记录上一个处理的标准设备ID
standardChannelGroups.forEach(({ deviceId, centerY }) => {
const device = standardDevices.find(d => d.id === deviceId)
if (device) {
// 只有当设备ID变化时才计算新位置
if (lastStandardDeviceId !== deviceId) {
// 计算该标准设备对应的通道数量
const channelCount = channelCounts2[deviceId] || 0
// 计算设备高度居中位置 - 基于该设备组的实际位置
const deviceCenterY = standardDeviceCurrentYPosition + (channelCount * 50) / 2 - 50
newNodes.push({
id: device.id,
data: { label: createLabel(device, 2) },
position: { x: standardWidth, y: deviceCenterY },
class: 'no-handle-node',
style: { width: '300px', border: 'none', boxShadow: 'none' }
})
// 更新位置为下一台标准设备的起始位置
standardDeviceCurrentYPosition += channelCount * 50 + 30
// 更新上一个标准设备ID
lastStandardDeviceId = deviceId
}
}
})
//页面高度取决于设备通道
// dialogHeight.value = Math.max(yPosition.value, yPosition2.value)
return newNodes
}
defineExpose({ open, handleNext })
</script>
<style>
.flow-container {
width: 100%;
overflow: hidden;
}
.vue-flow__node.no-handle-node .vue-flow__handle {
display: none !important;
}
/* 放大连线点 */
.vue-flow__handle {
width: 12px !important; /* 原来默认是 6px */
height: 12px !important; /* 原来默认是 6px */
background-color: #3b82f6 !important; /* 更明显的颜色 */
}
</style>