fix: 修复设备树节点key值生成逻辑,最大限度避免key值碰撞导致设备树渲染异常

This commit is contained in:
yangsy
2026-03-30 20:30:26 +08:00
parent f9f761b4e9
commit b4442fe6c4
@@ -1,3 +1,9 @@
<script lang="ts">
const createDeviceNodeKey = (stationCode?: Station['code'], device?: NdmDeviceResultVO) => {
return `${stationCode ?? ''}-${device?.id ?? ''}`;
};
</script>
<script setup lang="ts"> <script setup lang="ts">
import { initStationDevices, type NdmDeviceResultVO, type NdmNvrResultVO, type Station } from '@/apis'; import { initStationDevices, type NdmDeviceResultVO, type NdmNvrResultVO, type Station } from '@/apis';
import { useDeviceTree, usePermission, type UseDeviceTreeReturn } from '@/composables'; import { useDeviceTree, usePermission, type UseDeviceTreeReturn } from '@/composables';
@@ -110,7 +116,7 @@ watchImmediate(selectedDeviceType, (newDeviceType) => {
} }
}); });
const selectedKeys = computed(() => (selectedDevice.value?.id ? [selectedDevice.value.id] : undefined)); const selectedKeys = computed(() => (selectedDevice.value?.id ? [createDeviceNodeKey(selectedStationCode.value, selectedDevice.value)] : undefined));
watch([selectedKeys, selectedDevice, selectedStationCode], ([, device, code]) => { watch([selectedKeys, selectedDevice, selectedStationCode], ([, device, code]) => {
if (device && code) { if (device && code) {
onSelectDevice(device, code); onSelectDevice(device, code);
@@ -316,26 +322,26 @@ const lineDeviceTreeData = computed<Record<Station['code'], TreeOption[]>>(() =>
key: stationCode, key: stationCode,
prefix: () => renderStationNodePrefix(station), prefix: () => renderStationNodePrefix(station),
suffix: () => renderIcmpStatistics(onlineDevices?.length ?? 0, offlineDevices?.length ?? 0, devices?.length ?? 0), suffix: () => renderIcmpStatistics(onlineDevices?.length ?? 0, offlineDevices?.length ?? 0, devices?.length ?? 0),
children: nvrClusters.map<TreeOption>((nvrCluster) => { children: nvrClusters.map<TreeOption>((cluster) => {
return { return {
label: `${nvrCluster.name}`, label: `${cluster.name}`,
key: nvrCluster.id ?? `${nvrCluster.name}`, key: createDeviceNodeKey(stationCode, cluster),
prefix: () => renderDeviceNodePrefix(nvrCluster, stationCode), prefix: () => renderDeviceNodePrefix(cluster, stationCode),
suffix: () => `${nvrCluster.ipAddress}`, suffix: () => `${cluster.ipAddress}`,
children: nvrSingletons.map<TreeOption>((nvr) => { children: nvrSingletons.map<TreeOption>((device) => {
return { return {
label: `${nvr.name}`, label: `${device.name}`,
key: nvr.id ?? `${nvr.name}`, key: createDeviceNodeKey(stationCode, device),
prefix: () => renderDeviceNodePrefix(nvr, stationCode), prefix: () => renderDeviceNodePrefix(device, stationCode),
suffix: () => `${nvr.ipAddress}`, suffix: () => `${device.ipAddress}`,
// 当选择设备时,能获取到设备的所有信息,以及设备所属的车站 // 当选择设备时,能获取到设备的所有信息,以及设备所属的车站
stationCode, stationCode,
device: nvr, device: device,
}; };
}), }),
// 当选择设备时,能获取到设备的所有信息,以及设备所属的车站 // 当选择设备时,能获取到设备的所有信息,以及设备所属的车站
stationCode, stationCode,
device: nvrCluster, device: cluster,
}; };
}), }),
stationCode, stationCode,
@@ -352,7 +358,7 @@ const lineDeviceTreeData = computed<Record<Station['code'], TreeOption[]>>(() =>
const device = dev as NdmDeviceResultVO; const device = dev as NdmDeviceResultVO;
return { return {
label: `${device.name}`, label: `${device.name}`,
key: `${device.name}${device.ipAddress}`, key: createDeviceNodeKey(stationCode, device),
prefix: () => renderDeviceNodePrefix(device, stationCode), prefix: () => renderDeviceNodePrefix(device, stationCode),
suffix: () => `${device.ipAddress}`, suffix: () => `${device.ipAddress}`,
// 当选择设备时,能获取到设备的所有信息,以及设备所属的车站 // 当选择设备时,能获取到设备的所有信息,以及设备所属的车站
@@ -383,16 +389,16 @@ const stationDeviceTreeData = computed<TreeOption[]>(() => {
label: `${DEVICE_TYPE_NAMES[deviceType]}`, label: `${DEVICE_TYPE_NAMES[deviceType]}`,
key: deviceType, key: deviceType,
suffix: () => renderIcmpStatistics(onlineCount, offlineCount, nvrs.length), suffix: () => renderIcmpStatistics(onlineCount, offlineCount, nvrs.length),
children: clusters.map<TreeOption>((device) => { children: clusters.map<TreeOption>((cluster) => {
return { return {
label: `${device.name}`, label: `${cluster.name}`,
key: `${device.name}${device.ipAddress}`, key: createDeviceNodeKey(stationCode, cluster),
prefix: () => renderDeviceNodePrefix(device, stationCode), prefix: () => renderDeviceNodePrefix(cluster, stationCode),
suffix: () => `${device.ipAddress}`, suffix: () => `${cluster.ipAddress}`,
children: singletons.map<TreeOption>((device) => { children: singletons.map<TreeOption>((device) => {
return { return {
label: `${device.name}`, label: `${device.name}`,
key: `${device.name}${device.ipAddress}`, key: createDeviceNodeKey(stationCode, device),
prefix: () => renderDeviceNodePrefix(device, stationCode), prefix: () => renderDeviceNodePrefix(device, stationCode),
suffix: () => `${device.ipAddress}`, suffix: () => `${device.ipAddress}`,
stationCode, stationCode,
@@ -400,7 +406,7 @@ const stationDeviceTreeData = computed<TreeOption[]>(() => {
}; };
}), }),
stationCode, stationCode,
device, device: cluster,
}; };
}), }),
stationCode, stationCode,
@@ -414,7 +420,7 @@ const stationDeviceTreeData = computed<TreeOption[]>(() => {
children: stationDevices[deviceType].map<TreeOption>((device) => { children: stationDevices[deviceType].map<TreeOption>((device) => {
return { return {
label: `${device.name}`, label: `${device.name}`,
key: `${device.name}${device.ipAddress}`, key: createDeviceNodeKey(stationCode, device),
prefix: () => renderDeviceNodePrefix(device, stationCode), prefix: () => renderDeviceNodePrefix(device, stationCode),
suffix: () => `${device.ipAddress}`, suffix: () => `${device.ipAddress}`,
stationCode, stationCode,
@@ -462,6 +468,7 @@ const onFoldDeviceTree = () => {
}; };
const onLocateDeviceTree = async () => { const onLocateDeviceTree = async () => {
if (!selectedStationCode.value) return; if (!selectedStationCode.value) return;
const stationCode = selectedStationCode.value;
if (!selectedDevice.value) return; if (!selectedDevice.value) return;
const deviceType = tryGetDeviceType(selectedDevice.value.deviceType); const deviceType = tryGetDeviceType(selectedDevice.value.deviceType);
if (!deviceType) return; if (!deviceType) return;
@@ -473,24 +480,24 @@ const onLocateDeviceTree = async () => {
activeTab.value = deviceType; activeTab.value = deviceType;
// 展开选择的车站 // 展开选择的车站
expandedKeys.value.push(selectedStationCode.value); expandedKeys.value.push(stationCode);
// 当选择录像机时,如果不是集群,进一步展开该录像机所在的集群节点 // 当选择录像机时,如果不是集群,进一步展开该录像机所在的集群节点
if (deviceType === DEVICE_TYPE_LITERALS.ndmNvr) { if (deviceType === DEVICE_TYPE_LITERALS.ndmNvr) {
const stationDevices = lineDevices.value[selectedStationCode.value]; const stationDevices = lineDevices.value[stationCode];
if (stationDevices) { if (stationDevices) {
const selectedNvr = selectedDevice.value as NdmNvrResultVO; const selectedNvr = selectedDevice.value as NdmNvrResultVO;
if (!isNvrCluster(selectedNvr)) { if (!isNvrCluster(selectedNvr)) {
const nvrs = stationDevices[DEVICE_TYPE_LITERALS.ndmNvr]; const nvrs = stationDevices[DEVICE_TYPE_LITERALS.ndmNvr];
const clusters = nvrs.filter((nvr) => isNvrCluster(nvr) && nvr.clusterList?.includes(selectedNvr.clusterList ?? '')); const clusters = nvrs.filter((nvr) => isNvrCluster(nvr) && nvr.clusterList?.includes(selectedNvr.clusterList ?? ''));
expandedKeys.value.push(...clusters.map((nvr) => `${nvr.id}`)); expandedKeys.value.push(...clusters.map((nvr) => createDeviceNodeKey(stationCode, nvr)));
} }
} }
} }
// 等待设备树展开完成,滚动到选择的设备 // 等待设备树展开完成,滚动到选择的设备
await nextTick(); await nextTick();
deviceTreeInst.value.scrollTo({ key: `${selectedDevice.value.id}`, behavior: 'smooth' }); deviceTreeInst.value.scrollTo({ key: createDeviceNodeKey(stationCode, selectedDevice.value), behavior: 'smooth' });
animated.value = true; animated.value = true;
}; };