fix: DevicePage fix

- remove dblclick of device node
- auto scroll to selected device node
This commit is contained in:
yangsy
2025-08-18 15:05:45 +08:00
parent d0168f84bc
commit f044671528

View File

@@ -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<Record<string, TreeOption[]>>(() => {
const treeData: Record<string, TreeOption[]> = {};
deviceTabPanes.forEach(({ name: paneName /* , tab: paneTab */ }) => {
@@ -86,7 +88,7 @@ const lineDeviceTreeData = computed<Record<string, TreeOption[]>>(() => {
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<DeviceTypeCode>(DeviceType.Camera);
const selectedKeys = ref<string[]>();
const expandedKeys = ref<string[]>();
const selectedDevice = ref<NdmDeviceResultVO>();
// 从路由参数中设置选中的设备
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<TreeInst[]>('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);
};
</script>
@@ -252,17 +253,18 @@ const onClickLocateDeviceTree = () => {
<NTabs v-model:value="selectedTab" animated type="line" placement="left" style="height: 100%">
<NTabPane v-for="pane in deviceTabPanes" :key="pane.name" :name="pane.name" :tab="pane.tab">
<NTree
:ref="'deviceTreeInsts'"
v-model:selected-keys="selectedKeys"
v-model:expanded-keys="expandedKeys"
:ref="'deviceTreeInsts'"
:data="lineDeviceTreeData[pane.name]"
:node-props="nodeProps"
:show-irrelevant-nodes="false"
:pattern="searchPattern"
:filter="searchFilter"
:override-default-node-click-behavior="override"
default-expand-all
block-line
block-node
show-line
default-expand-all
virtual-scroll
style="height: 100%"
/>
@@ -281,6 +283,7 @@ const onClickLocateDeviceTree = () => {
</template>
</NPageHeader>
<div>selectedKeys: {{ selectedKeys }}</div>
<div>expandedKeys: {{ expandedKeys }}</div>
<div>selectedDevice: {{ selectedDevice?.deviceId }}</div>
<NScrollbar style="width: 500px; height: 400px; border: solid 1px salmon">
<pre>{{ selectedDevice }}</pre>