feat: 扩展设备树功能

- 支持控制是否同步路由参数
- 支持配置允许的事件类型 (select/manage)
- 支持自定义设备节点前缀按钮文字
- 支持向外暴露设备选择逻辑
- 不再封装跳转设备逻辑,由外部实现
- 在车站模式下也支持选择设备
This commit is contained in:
yangsy
2025-12-24 22:57:41 +08:00
parent f99fe0f68e
commit ed2a4f78ff
6 changed files with 101 additions and 60 deletions

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { initStationDevices, type NdmDeviceResultVO, type NdmNvrResultVO, type Station } from '@/apis';
import { useDeviceTree } from '@/composables';
import { useDeviceTree, type UseDeviceTreeReturn } from '@/composables';
import { DEVICE_TYPE_NAMES, DEVICE_TYPE_LITERALS, tryGetDeviceType, type DeviceType } from '@/enums';
import { isNvrCluster } from '@/helpers';
import { useDeviceStore, useStationStore } from '@/stores';
@@ -30,14 +30,33 @@ import { storeToRefs } from 'pinia';
import { computed, h, nextTick, onBeforeUnmount, ref, toRefs, useTemplateRef, watch, type CSSProperties } from 'vue';
const props = defineProps<{
station?: Station; // 支持渲染指定车站的设备树
/**
* 支持渲染指定车站的设备树
*/
station?: Station;
/**
* 允许的事件类型
*
* - `select`:允许选择设备
* - `manage`:允许右键菜单管理设备
*/
events?: ('select' | 'manage')[];
/**
* 是否同步路由参数
*/
syncRoute?: boolean;
/**
* 设备节点的前缀按钮文字
*/
devicePrefixLabel?: string;
}>();
const emit = defineEmits<{
selectDevice: [device: NdmDeviceResultVO, stationCode: Station['code']];
afterSelectDevice: [device: NdmDeviceResultVO, stationCode: Station['code']];
exposeSelectDeviceFn: [selectDeviceFn: UseDeviceTreeReturn['selectDevice']];
}>();
const { station } = toRefs(props);
const { station, events, syncRoute, devicePrefixLabel } = toRefs(props);
const themeVars = useThemeVars();
@@ -47,22 +66,25 @@ const {
selectedDeviceType,
selectedDevice,
selectDevice,
routeDevice,
// 设备管理
exportDevice,
exportDeviceTemplate,
importDevice,
deleteDevice,
} = useDeviceTree();
} = useDeviceTree({
syncRoute: computed(() => !!syncRoute.value),
});
// 将 `selectDevice` 函数暴露给父组件
emit('exposeSelectDeviceFn', selectDevice);
const onSelectDevice = (device: NdmDeviceResultVO, stationCode: Station['code']) => {
selectDevice(device, stationCode);
emit('selectDevice', device, stationCode);
};
// 仅当事件列表包含 `select` 时才触发选择事件
if (!events.value) return;
if (!events.value.includes('select')) return;
const onRouteDevice = (device: NdmDeviceResultVO, stationCode: Station['code']) => {
routeDevice(device, stationCode, { path: '/device' });
emit('selectDevice', device, stationCode);
selectDevice(device, stationCode);
emit('afterSelectDevice', device, stationCode);
};
const stationStore = useStationStore();
@@ -187,20 +209,20 @@ const nodeProps: TreeProps['nodeProps'] = ({ option }) => {
onDblclick: (payload) => {
if (option['device']) {
payload.stopPropagation();
const device = option['device'] as NdmDeviceResultVO;
const stationCode = option['stationCode'] as Station['code'];
// 区分是否需要跳转路由
// 当 props.station 存在时,说明当前是单独渲染车站的设备树,需要跳转路由到设备诊断页面
if (!station.value) {
onSelectDevice(device, stationCode);
} else {
onRouteDevice(device, stationCode);
}
onSelectDevice(device, stationCode);
}
},
onContextmenu: (payload) => {
payload.stopPropagation();
payload.preventDefault();
// 仅当事件列表包含 `manage` 时才显示右键菜单
if (!events.value?.includes('manage')) return;
const { clientX, clientY } = payload;
const stationCode = option['stationCode'] as Station['code'];
const deviceType = option['deviceType'] as DeviceType | undefined;
@@ -231,6 +253,7 @@ const renderIcmpStatistics = (onlineCount: number, offlineCount: number, count:
};
const renderDeviceNodePrefix = (device: NdmDeviceResultVO, stationCode: Station['code']) => {
const renderViewDeviceButton = (device: NdmDeviceResultVO, stationCode: string) => {
if (!devicePrefixLabel.value) return null;
return h(
NButton,
{
@@ -242,17 +265,11 @@ const renderDeviceNodePrefix = (device: NdmDeviceResultVO, stationCode: Station[
} as CSSProperties,
onClick: (e: MouseEvent) => {
e.stopPropagation();
// 选择设备
// 区分是否需要跳转路由
// 当 props.station 存在时,说明当前是单独渲染车站的设备树,需要跳转路由到设备诊断页面
if (!station.value) {
onSelectDevice(device, stationCode);
} else {
onRouteDevice(device, stationCode);
}
onSelectDevice(device, stationCode);
},
},
() => '查看',
() => devicePrefixLabel.value,
);
};
const renderDeviceStatusTag = (device: NdmDeviceResultVO) => {
@@ -529,6 +546,7 @@ watch(selectedDevice, async () => {
virtual-scroll
:data="stationDeviceTreeData"
:animated="animated"
:selected-keys="selectedKeys"
:show-irrelevant-nodes="false"
:pattern="searchPattern"
:filter="searchFilter"