hazop插件节点拖拽修改

This commit is contained in:
2026-09-11 17:13:58 +08:00
parent c310ab351e
commit a7cd8f1901
+93 -20
View File
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, h, onBeforeUnmount, onMounted, ref } from "vue";
import { computed, h, onBeforeUnmount, onMounted, reactive, ref } from "vue";
import { Icon } from '@iconify/vue'
import { useThemeStore } from '@/store/modules/theme';
import { useDialog, NInput, NPopconfirm, NButton } from 'naive-ui';
@@ -78,7 +78,7 @@ const handleSearch = () => {
// 点击偏离
const clickDev = (dev:any,nodeIndex:number) => {
currentNodeIndex.value = nodeIndex
currentNodeList.value = nodes.value[nodeIndex]?.objects || []
currentNodeList.value = JSON.parse(JSON.stringify(nodes.value[nodeIndex]?.objects || []))
currentNodeListSource.value = JSON.parse(JSON.stringify(currentNodeList.value))
currentDev.value = dev
}
@@ -854,6 +854,79 @@ const getWorkers = async () => {
}
}
// ========== 拖拽状态记录(只记录设备卡片和偏离项) ==========
const isDeviceDragging = ref(false)
const draggedDeviceInfo = reactive({ deviceIdx: -1 })
const isDevDragging = ref(false)
const draggedDevInfo = reactive({ deviceIdx: -1, devIdx: -1 })
// ========== 分析对象拖拽逻辑 ==========
const onDeviceDragStart = (e: DragEvent, dIdx: number) => {
if (keyword.value)
return // 搜索过滤态下索引与暂存数组不一致,禁用拖拽排序
isDeviceDragging.value = true
draggedDeviceInfo.deviceIdx = dIdx
if (e.dataTransfer)
e.dataTransfer.effectAllowed = 'move'
}
const onDeviceDrop = (e: DragEvent, targetDeviceIdx: number) => {
e.preventDefault()
if (keyword.value)
return
if (!isDeviceDragging.value)
return
const { deviceIdx: srcDeviceIdx } = draggedDeviceInfo
if (srcDeviceIdx === targetDeviceIdx) {
resetDeviceDragState()
return
}
// 1. 移除源卡片
const [deviceItem] = currentNodeList.value.splice(srcDeviceIdx, 1)
// 2. 直接使用目标索引进行插入(上往下拖落在目标后,下往上拖落在目标前)
currentNodeList.value.splice(targetDeviceIdx, 0, deviceItem)
resetDeviceDragState()
}
const resetDeviceDragState = () => {
isDeviceDragging.value = false
draggedDeviceInfo.deviceIdx = -1
}
// ========== 内部偏离项拖拽逻辑(支持同对象排序与跨对象移动) ==========
const onDeviateDragStart = (e: DragEvent, dIdx: number, dvIdx: number) => {
if (keyword.value)
return // 同上,搜索过滤态禁用
isDevDragging.value = true
draggedDevInfo.deviceIdx = dIdx
draggedDevInfo.devIdx = dvIdx
if (e.dataTransfer)
e.dataTransfer.effectAllowed = 'move'
}
const onDeviateDrop = (e: DragEvent, targetDeviceIdx: number, targetDevIdx: number) => {
e.preventDefault()
if (keyword.value)
return
if (!isDevDragging.value)
return
const { deviceIdx: srcDeviceIdx, devIdx: srcDevIdx } = draggedDevInfo
if (srcDeviceIdx === targetDeviceIdx && srcDevIdx === targetDevIdx) {
resetDevDragState()
return
}
const srcDevice = currentNodeList.value[srcDeviceIdx]
const tgtDevice = currentNodeList.value[targetDeviceIdx]
// 1. 移除源偏离项
const [devItem] = srcDevice.deviations.splice(srcDevIdx, 1)
// 2. 直接使用目标索引进行插入
tgtDevice.deviations.splice(targetDevIdx, 0, devItem)
resetDevDragState()
}
const resetDevDragState = () => {
isDevDragging.value = false
draggedDevInfo.deviceIdx = -1
draggedDevInfo.devIdx = -1
}
onMounted(() => {
getWorkers();
getHazopNodes();
@@ -1311,16 +1384,15 @@ onBeforeUnmount(() => {
<div class="w-500px max-h-[60vh] overflow-y-auto">
<NCollapse v-if="currentNodeList.length" :trigger-areas="['arrow']">
<template v-for="(obj,objIndex) in currentNodeList" :key="objIndex">
<NCollapseItem
:title="obj.obj_name"
:name="objIndex"
:draggable="true"
@dragstart="onDeviceDragStart($event, objIndex)"
@dragover.prevent
@drop="onDeviceDrop($event, objIndex)"
>
<NCollapseItem :title="obj.obj_name" :name="objIndex">
<template #header>
<div class="mr-[5px] cursor-grab" :draggable="true">
<div
class="mr-[5px] cursor-grab"
:draggable="true"
@dragstart="onDeviceDragStart($event, objIndex)"
@dragover.prevent
@drop="onDeviceDrop($event, objIndex)"
>
<Icon icon="gravity-ui:grip" class="size-12px" />
</div>
<NInput v-model:value="obj.obj_name" size="small" clearable placeholder="分析对象名称" style="width: 300px;" @blur="saveData" />
@@ -1351,17 +1423,18 @@ onBeforeUnmount(() => {
v-for="(dev, devIndex) in obj.deviations"
:key="devIndex"
class="flex items-center justify-between"
:draggable="true"
@dragstart="onDeviateDragStart($event, objIndex, devIndex)"
@dragover.prevent
@drop="onDeviateDrop($event, objIndex, devIndex)"
>
<div class="flex items-center gap-[5px]">
<div class="mr-[5px] cursor-grab" :draggable="true">
<Icon icon="gravity-ui:grip" class="size-12px" />
</div>
<Split :size="14" class="text-orange-400" />
<NInput v-model:value="dev.deviation" size="small" clearable placeholder="偏离名称" style="width: 300px;" @blur="saveData" />
<div
class="mr-[5px] cursor-grab"
:draggable="true"
@dragstart="onDeviateDragStart($event, objIndex, devIndex)"
@dragover.prevent
@drop="onDeviateDrop($event, objIndex, devIndex)"
>
<Icon icon="gravity-ui:grip" class="size-12px" />
</div>
<NInput v-model:value="dev.deviation" size="small" clearable placeholder="偏离名称" style="width: 300px;" @blur="saveData" />
</div>
<div class="flex items-center gap-[10px]">
<span v-if="dev?.rows?.length" class="rounded-full bg-emerald-100 px-1.5 text-[10px] text-emerald-600">