From f04467152898805e010236be9dcbbdd269ce10e4 Mon Sep 17 00:00:00 2001 From: yangsy Date: Mon, 18 Aug 2025 15:05:45 +0800 Subject: [PATCH] fix: DevicePage fix - remove dblclick of device node - auto scroll to selected device node --- src/pages/device-page.vue | 65 ++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/src/pages/device-page.vue b/src/pages/device-page.vue index 594c00a..c0e1f78 100644 --- a/src/pages/device-page.vue +++ b/src/pages/device-page.vue @@ -24,9 +24,10 @@ import { type TagProps, type TreeInst, type TreeOption, + type TreeOverrideNodeClickBehavior, } from 'naive-ui'; import { storeToRefs } from 'pinia'; -import { h, nextTick, onMounted, useTemplateRef } from 'vue'; +import { h, onMounted, useTemplateRef } from 'vue'; import { computed, ref, watch } from 'vue'; import { useRoute, useRouter, type LocationQuery } from 'vue-router'; import { destr } from 'destr'; @@ -49,6 +50,7 @@ const stationStore = useStationStore(); const { stationList } = storeToRefs(stationStore); const { data: lineDevices } = useLineDevicesQuery(); +// ========== 设备树数据 ========== const lineDeviceTreeData = computed>(() => { const treeData: Record = {}; deviceTabPanes.forEach(({ name: paneName /* , tab: paneTab */ }) => { @@ -86,7 +88,7 @@ const lineDeviceTreeData = computed>(() => { key: nvr.id, suffix: () => `${nvr.ipAddress}`, prefix: () => { - return renderDeviceNodePrefix(nvrCluster, stationCode); + return renderDeviceNodePrefix(nvr, stationCode); }, // 当选择设备时,能获取到设备的所有信息,以及设备所属的车站 device: nvr, @@ -152,11 +154,13 @@ const renderDeviceNodePrefix = (device: NdmDeviceResultVO, stationCode: string) return h('div', [renderViewDeviceButton(device, stationCode), renderDeviceStatusTag(device)]); }; +// ========== 选中设备 ========== const selectedTab = ref(DeviceType.Camera); const selectedKeys = ref(); +const expandedKeys = ref(); const selectedDevice = ref(); // 从路由参数中设置选中的设备 -const setFromRouteQuery = (query: LocationQuery) => { +const setDeviceTreePropsFromRouteQuery = (query: LocationQuery) => { const { stationCode, deviceType, deviceDBId } = query; let stnCode = ''; let devType: DeviceTypeCode = DeviceType.Camera; @@ -164,6 +168,7 @@ const setFromRouteQuery = (query: LocationQuery) => { if (stationCode) stnCode = stationCode as string; if (deviceType) devType = deviceType as DeviceTypeCode; if (deviceDBId) devDBId = deviceDBId as string; + selectedTab.value = devType; selectedKeys.value = [devDBId]; const stnDevices = lineDevices.value?.[stnCode]; @@ -172,35 +177,24 @@ const setFromRouteQuery = (query: LocationQuery) => { selectedDevice.value = devices?.find((device) => device.id === devDBId) ?? selectedDevice.value; }; // 页面加载时,需要设置选中的设备 -onMounted(() => setFromRouteQuery(route.query)); +onMounted(() => { + setDeviceTreePropsFromRouteQuery(route.query); + scrollDeviceTreeToSelectedDevice(); +}); // 页面加载时设备数据可能不存在,因此当设备数据更新时,需要重新设置选中的设备 -watch(lineDevices, () => setFromRouteQuery(route.query), { immediate: true }); +watch(lineDevices, () => setDeviceTreePropsFromRouteQuery(route.query), { immediate: true }); // 更改选择的设备类型时,更新路由查询参数 watch(selectedTab, (newTab) => router.replace({ query: { ...route.query, deviceType: newTab } })); -// 双击设备时更新路由查询参数 -const nodeProps = ({ option }: { option: TreeOption }) => { - return { - ondblclick: () => { - if (option['device']) { - const device = option['device'] as NdmDeviceResultVO; - selectedKeys.value = device.id ? [device.id] : undefined; // 更新选中的树节点 - selectedDevice.value = device; // 更新选中的设备 - router.replace({ - query: { - ...route.query, - stationCode: option['stationCode'] as string, - deviceType: selectedTab.value, - deviceDBId: device.id, - }, - }); - } - }, - }; +const override: TreeOverrideNodeClickBehavior = ({ option }) => { + if (!option['device']) { + return 'none'; + } + return 'default'; }; +// ========== 设备树搜索 ========== const searchInput = ref(''); const statusInput = ref(''); - // 设备树将搜索框和单选框的值都交给NTree的pattern属性 // 但是如果一个车站下没有匹配的设备,那么这个车站节点也不会显示 const searchPattern = computed(() => { @@ -218,15 +212,22 @@ const searchFilter = (pattern: string, node: TreeOption): boolean => { return searchMatched && statusMatched; }; +// ========== 设备树交互 ========== // 定位到选中的设备 const deviceTreeInsts = useTemplateRef('deviceTreeInsts'); const onClickLocateDeviceTree = () => { selectedTab.value = (selectedDevice.value?.deviceType ?? selectedTab.value) as DeviceTypeCode; - // 等待Tab切换完成后再执行滚动 - nextTick(() => { + selectedKeys.value = selectedDevice.value?.id ? [selectedDevice.value.id] : undefined; + expandedKeys.value = route.query['stationCode'] ? [route.query['stationCode'] as string] : undefined; + // 由于数据量大所以开启虚拟滚动, + // 但是无法知晓NTree内部的虚拟列表容器何时创建完成,所以使用setTimeout延迟固定时间后执行滚动 + scrollDeviceTreeToSelectedDevice(); +}; +const scrollDeviceTreeToSelectedDevice = (timeout: number = 500) => { + setTimeout(() => { const inst = deviceTreeInsts.value?.at(0); inst?.scrollTo({ key: selectedDevice.value?.id, behavior: 'smooth' }); - }); + }, timeout); }; @@ -252,17 +253,18 @@ const onClickLocateDeviceTree = () => { @@ -281,6 +283,7 @@ const onClickLocateDeviceTree = () => {
selectedKeys: {{ selectedKeys }}
+
expandedKeys: {{ expandedKeys }}
selectedDevice: {{ selectedDevice?.deviceId }}
{{ selectedDevice }}