feat: migrate id and improve interaction
- use DB id of device to mark tree node key - dblclick offlien device node to jump to DevicePage - dblclick device node to view device detail
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { NInput, NModal, NTree } from 'naive-ui';
|
||||
import { NButton, NInput, NModal, NTree } from 'naive-ui';
|
||||
import { computed, ref, toRefs, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import type { TreeOption, TreeOverrideNodeClickBehavior } from 'naive-ui';
|
||||
@@ -17,6 +17,7 @@ import type {
|
||||
import { useQueryControlStore } from '@/stores/query-control';
|
||||
import { DeviceType, DeviceTypeName } from '@/enums/device-type';
|
||||
import type { Station } from '@/apis/domains';
|
||||
import { h } from 'vue';
|
||||
|
||||
interface Props {
|
||||
station: Station;
|
||||
@@ -51,8 +52,8 @@ watch(show, (newValue) => {
|
||||
|
||||
const searchPattern = ref('');
|
||||
const searchFilter: (pattern: string, node: TreeOption) => boolean = (pattern, node) => {
|
||||
const device = node['device'] as NdmDeviceVO;
|
||||
const { name, ipAddress } = device;
|
||||
const device = node['device'] as NdmDeviceVO | undefined;
|
||||
const { name, ipAddress } = device ?? {};
|
||||
return (name ?? '').includes(pattern) || (ipAddress ?? '').includes(pattern);
|
||||
};
|
||||
|
||||
@@ -75,12 +76,38 @@ const treeData = computed<TreeOption[]>(() => {
|
||||
label: `${device.name}`,
|
||||
key: device.id,
|
||||
suffix: () => `${device.ipAddress ?? '未知IP地址'}`,
|
||||
prefix: () => {
|
||||
return h(
|
||||
NButton,
|
||||
{
|
||||
text: true,
|
||||
size: 'tiny',
|
||||
type: 'info',
|
||||
onClick: () => {
|
||||
const queryControlStore = useQueryControlStore();
|
||||
queryControlStore.enablePolling();
|
||||
const dev = device as NdmDeviceVO;
|
||||
router.push({
|
||||
path: '/device',
|
||||
query: {
|
||||
stationCode: station.value.code,
|
||||
deviceType: dev.deviceType,
|
||||
deviceDBId: dev.id,
|
||||
from: route.path,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{ default: () => h('span', '查看') },
|
||||
);
|
||||
},
|
||||
device,
|
||||
})),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// 双击设备节点,跳转到`实时设备状`态页面
|
||||
const nodeProps = ({ option }: { option: TreeOption }) => {
|
||||
return {
|
||||
ondblclick: () => {
|
||||
@@ -93,7 +120,7 @@ const nodeProps = ({ option }: { option: TreeOption }) => {
|
||||
query: {
|
||||
stationCode: station.value.code,
|
||||
deviceType: device.deviceType,
|
||||
deviceId: device.deviceId,
|
||||
deviceDBId: device.id,
|
||||
from: route.path,
|
||||
},
|
||||
});
|
||||
@@ -103,7 +130,7 @@ const nodeProps = ({ option }: { option: TreeOption }) => {
|
||||
};
|
||||
|
||||
const override: TreeOverrideNodeClickBehavior = ({ option }) => {
|
||||
if (option.children) {
|
||||
if (!option['device']) {
|
||||
return 'toggleExpand';
|
||||
}
|
||||
return 'default';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { NdmDeviceResultVO, NdmDeviceVO, NdmNvrResultVO } from '@/apis/models/device';
|
||||
import type { NdmDeviceResultVO, NdmNvrResultVO } from '@/apis/models/device';
|
||||
import { useLineDevicesQuery } from '@/composables/query/use-line-devices-query';
|
||||
import { DeviceType, DeviceTypeName, type DeviceTypeCode, type DeviceTypeKey } from '@/enums/device-type';
|
||||
import { useStationStore } from '@/stores/station';
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
NTabs,
|
||||
NTag,
|
||||
NTree,
|
||||
type TagProps,
|
||||
type TreeInst,
|
||||
type TreeOption,
|
||||
} from 'naive-ui';
|
||||
@@ -70,16 +71,10 @@ const lineDeviceTreeData = computed<Record<string, TreeOption[]>>(() => {
|
||||
.map<TreeOption>((nvrCluster) => {
|
||||
return {
|
||||
label: `${nvrCluster.name}`,
|
||||
key: nvrCluster.deviceId,
|
||||
key: nvrCluster.id,
|
||||
suffix: () => `${nvrCluster.ipAddress}`,
|
||||
prefix: () => {
|
||||
return h(
|
||||
NTag,
|
||||
{ type: nvrCluster.deviceStatus === '10' ? 'success' : nvrCluster.deviceStatus === '20' ? 'error' : 'warning', size: 'tiny' },
|
||||
{
|
||||
default: () => (nvrCluster.deviceStatus === '10' ? '在线' : nvrCluster.deviceStatus === '20' ? '离线' : '未知'),
|
||||
},
|
||||
);
|
||||
return renderDeviceNodePrefix(nvrCluster, stationCode);
|
||||
},
|
||||
children: nvrs
|
||||
.filter((nvr) => {
|
||||
@@ -88,16 +83,10 @@ const lineDeviceTreeData = computed<Record<string, TreeOption[]>>(() => {
|
||||
.map<TreeOption>((nvr) => {
|
||||
return {
|
||||
label: `${nvr.name}`,
|
||||
key: nvr.deviceId,
|
||||
key: nvr.id,
|
||||
suffix: () => `${nvr.ipAddress}`,
|
||||
prefix: () => {
|
||||
return h(
|
||||
NTag,
|
||||
{ type: nvr.deviceStatus === '10' ? 'success' : nvr.deviceStatus === '20' ? 'error' : 'warning', size: 'tiny' },
|
||||
{
|
||||
default: () => (nvr.deviceStatus === '10' ? '在线' : nvr.deviceStatus === '20' ? '离线' : '未知'),
|
||||
},
|
||||
);
|
||||
return renderDeviceNodePrefix(nvrCluster, stationCode);
|
||||
},
|
||||
// 当选择设备时,能获取到设备的所有信息,以及设备所属的车站
|
||||
device: nvr,
|
||||
@@ -117,16 +106,10 @@ const lineDeviceTreeData = computed<Record<string, TreeOption[]>>(() => {
|
||||
suffix: () => `(${onlineDevices?.length ?? 0}/${offlineDevices?.length ?? 0}/${devices?.length ?? 0})`,
|
||||
children: lineDevices.value?.[stationCode][paneName].map<TreeOption>((device) => ({
|
||||
label: `${device.name}`,
|
||||
key: device.deviceId,
|
||||
key: device.id,
|
||||
suffix: () => `${device.ipAddress}`,
|
||||
prefix: () => {
|
||||
return h(
|
||||
NTag,
|
||||
{ type: device.deviceStatus === '10' ? 'success' : device.deviceStatus === '20' ? 'error' : 'warning', size: 'tiny' },
|
||||
{
|
||||
default: () => (device.deviceStatus === '10' ? '在线' : device.deviceStatus === '20' ? '离线' : '未知'),
|
||||
},
|
||||
);
|
||||
return renderDeviceNodePrefix(device, stationCode);
|
||||
},
|
||||
// 当选择设备时,能获取到设备的所有信息,以及设备所属的车站
|
||||
device,
|
||||
@@ -137,25 +120,56 @@ const lineDeviceTreeData = computed<Record<string, TreeOption[]>>(() => {
|
||||
});
|
||||
return treeData;
|
||||
});
|
||||
const renderDeviceNodePrefix = (device: NdmDeviceResultVO, stationCode: string) => {
|
||||
const renderDeviceStatusTag = (device: NdmDeviceResultVO) => {
|
||||
const { deviceStatus } = device;
|
||||
const tagType: TagProps['type'] = deviceStatus === '10' ? 'success' : deviceStatus === '20' ? 'error' : 'warning';
|
||||
const tagText = device.deviceStatus === '10' ? '在线' : device.deviceStatus === '20' ? '离线' : '未知';
|
||||
return h(NTag, { type: tagType, size: 'tiny' }, () => tagText);
|
||||
};
|
||||
const renderViewDeviceButton = (device: NdmDeviceResultVO, stationCode: string) => {
|
||||
return h(
|
||||
NButton,
|
||||
{
|
||||
text: true,
|
||||
size: 'tiny',
|
||||
type: 'info',
|
||||
onClick: () => {
|
||||
selectedDevice.value = device; // 更新选中的设备
|
||||
router.replace({
|
||||
query: {
|
||||
...route.query,
|
||||
stationCode: stationCode,
|
||||
deviceType: selectedTab.value,
|
||||
deviceDBId: device.id,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
() => '查看',
|
||||
);
|
||||
};
|
||||
return h('div', [renderViewDeviceButton(device, stationCode), renderDeviceStatusTag(device)]);
|
||||
};
|
||||
|
||||
const selectedTab = ref<DeviceTypeCode>(DeviceType.Camera);
|
||||
const selectedKeys = ref<string[]>([]);
|
||||
const selectedKeys = ref<string[]>();
|
||||
const selectedDevice = ref<NdmDeviceResultVO>();
|
||||
// 从路由参数中设置选中的设备
|
||||
const setFromRouteQuery = (query: LocationQuery) => {
|
||||
const { stationCode, deviceType, deviceId } = query;
|
||||
const { stationCode, deviceType, deviceDBId } = query;
|
||||
let stnCode = '';
|
||||
let devType: DeviceTypeCode = DeviceType.Camera;
|
||||
let devId = '';
|
||||
let devDBId = '';
|
||||
if (stationCode) stnCode = stationCode as string;
|
||||
if (deviceType) devType = deviceType as DeviceTypeCode;
|
||||
if (deviceId) devId = deviceId as string;
|
||||
if (deviceDBId) devDBId = deviceDBId as string;
|
||||
selectedTab.value = devType;
|
||||
selectedKeys.value = [devId];
|
||||
selectedKeys.value = [devDBId];
|
||||
const stnDevices = lineDevices.value?.[stnCode];
|
||||
const devices = stnDevices?.[devType];
|
||||
// 如果没找到,那还是赋值为原来选择的设备
|
||||
selectedDevice.value = devices?.find((device) => device.deviceId === deviceId) ?? selectedDevice.value;
|
||||
selectedDevice.value = devices?.find((device) => device.id === devDBId) ?? selectedDevice.value;
|
||||
};
|
||||
// 页面加载时,需要设置选中的设备
|
||||
onMounted(() => setFromRouteQuery(route.query));
|
||||
@@ -163,19 +177,20 @@ onMounted(() => setFromRouteQuery(route.query));
|
||||
watch(lineDevices, () => setFromRouteQuery(route.query), { immediate: true });
|
||||
// 更改选择的设备类型时,更新路由查询参数
|
||||
watch(selectedTab, (newTab) => router.replace({ query: { ...route.query, deviceType: newTab } }));
|
||||
// 点击设备时更新路由查询参数
|
||||
// 双击设备时更新路由查询参数
|
||||
const nodeProps = ({ option }: { option: TreeOption }) => {
|
||||
return {
|
||||
onclick: () => {
|
||||
ondblclick: () => {
|
||||
if (option['device']) {
|
||||
const device = option['device'] as NdmDeviceResultVO;
|
||||
selectedDevice.value = device;
|
||||
selectedKeys.value = device.id ? [device.id] : undefined; // 更新选中的树节点
|
||||
selectedDevice.value = device; // 更新选中的设备
|
||||
router.replace({
|
||||
query: {
|
||||
...route.query,
|
||||
stationCode: option['stationCode'] as string,
|
||||
deviceType: selectedTab.value,
|
||||
deviceId: device.deviceId,
|
||||
deviceDBId: device.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -196,7 +211,7 @@ const searchPattern = computed(() => {
|
||||
});
|
||||
const searchFilter = (pattern: string, node: TreeOption): boolean => {
|
||||
const { search, status } = destr<{ search: string; status: string }>(pattern);
|
||||
const device = node['device'] as NdmDeviceVO | undefined;
|
||||
const device = node['device'] as NdmDeviceResultVO | undefined;
|
||||
const { name, ipAddress, deviceStatus } = device ?? {};
|
||||
const searchMatched = (name ?? '').includes(search) || (ipAddress ?? '').includes(search);
|
||||
const statusMatched = status === '' || status === deviceStatus;
|
||||
@@ -210,14 +225,14 @@ const onClickLocateDeviceTree = () => {
|
||||
// 等待Tab切换完成后再执行滚动
|
||||
nextTick(() => {
|
||||
const inst = deviceTreeInsts.value?.at(0);
|
||||
inst?.scrollTo({ key: selectedDevice.value?.deviceId, behavior: 'smooth' });
|
||||
inst?.scrollTo({ key: selectedDevice.value?.id, behavior: 'smooth' });
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NLayout has-sider style="height: 100%">
|
||||
<NLayoutSider bordered :width="540" :collapsed-width="0" show-trigger="bar">
|
||||
<NLayoutSider bordered :width="600" :collapsed-width="0" show-trigger="bar">
|
||||
<div style="height: 100%; display: flex; flex-direction: column">
|
||||
<div style="flex-shrink: 0; padding: 12px">
|
||||
<NInput v-model:value="searchInput" placeholder="搜索设备名称或IP地址" clearable />
|
||||
@@ -256,7 +271,7 @@ const onClickLocateDeviceTree = () => {
|
||||
</div>
|
||||
</div>
|
||||
</NLayoutSider>
|
||||
<NLayoutContent :content-style="{ 'padding-left': '24px' }">
|
||||
<NLayoutContent :content-style="{ 'padding-left': '24px', 'padding-top': '6px' }">
|
||||
<NPageHeader v-if="route.query['from']" title="" @back="onClickBack">
|
||||
<template #back>
|
||||
<NIcon>
|
||||
@@ -266,7 +281,7 @@ const onClickLocateDeviceTree = () => {
|
||||
</template>
|
||||
</NPageHeader>
|
||||
<div>selectedKeys: {{ selectedKeys }}</div>
|
||||
<div>selectedDevice:</div>
|
||||
<div>selectedDevice: {{ selectedDevice?.deviceId }}</div>
|
||||
<NScrollbar style="width: 500px; height: 400px; border: solid 1px salmon">
|
||||
<pre>{{ selectedDevice }}</pre>
|
||||
</NScrollbar>
|
||||
|
||||
Reference in New Issue
Block a user