feat: 新增多厂商安防箱支持并重构相关逻辑
- 新增安防箱适配器模块,统一封装不同厂商的设备操作逻辑 - 拆分原有安防箱API为beidian、ningtech两个厂商的专属实现 - 扩展安防箱诊断信息接口,补充设备ID、版本等元数据字段 - 更新安防箱设备卡片组件,支持自动识别厂商并适配空开控制逻辑
This commit is contained in:
@@ -12,8 +12,14 @@ export interface NdmSecurityBoxDiagInfo {
|
|||||||
];
|
];
|
||||||
stCommonInfo?: {
|
stCommonInfo?: {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
内存使用率?: string;
|
设备ID?: string; // 'NTBoxMetro'
|
||||||
CPU使用率?: string;
|
软件版本?: string; // 'V0101'
|
||||||
|
设备厂商?: string; // 'NingTech'
|
||||||
|
设备别名?: string; // 'SUN-IBOX'
|
||||||
|
设备型号?: string; // 'SUN-IBOX'
|
||||||
|
硬件版本?: string; // 'V0101'
|
||||||
|
内存使用率?: string; // '18'
|
||||||
|
CPU使用率?: string; // '1'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,22 +93,46 @@ export const probeSecurityBoxApi = async (ids: string[], options?: { stationCode
|
|||||||
unwrapVoidResponse(resp);
|
unwrapVoidResponse(resp);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const turnCitcuitStatusApi = async (ipAddress: string, circuitIndex: number, status: number, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
// beidian安防箱切换空开状态
|
||||||
|
export const turnCircuitStatusBeidianApi = async (community: string, ipAddress: string, circuitIndex: number, status: number, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : userClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const endpoint = `${prefix}/api/ndm/ndmSecurityBox/turnStatus`;
|
const endpoint = `${prefix}/api/ndm/ndmSecurityBox/turnStatus`;
|
||||||
const resp = await client.post<boolean>(endpoint, { community: 'public', ipAddress, circuit: `${circuitIndex}`, status }, { signal });
|
const resp = await client.post<boolean>(endpoint, { community, ipAddress, circuit: `${circuitIndex}`, status }, { signal });
|
||||||
const data = unwrapResponse(resp);
|
const data = unwrapResponse(resp);
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const rebootSecurityBoxApi = async (ipAddress: string, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
// beidian安防箱重启
|
||||||
|
export const rebootSecurityBoxBeidianApi = async (community: string, ipAddress: string, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : userClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const endpoint = `${prefix}/api/ndm/ndmSecurityBox/reboot`;
|
const endpoint = `${prefix}/api/ndm/ndmSecurityBox/reboot`;
|
||||||
const resp = await client.post<boolean>(endpoint, { community: 'public', ipAddress }, { signal });
|
const resp = await client.post<boolean>(endpoint, { community, ipAddress }, { signal });
|
||||||
|
const data = unwrapResponse(resp);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ningtech安防箱切换空开状态
|
||||||
|
export const turnCircuitStatusNingTechApi = async (community: string, ipAddress: string, circuitIndex: number, status: number, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
|
const { stationCode, signal } = options ?? {};
|
||||||
|
const client = stationCode ? ndmClient : userClient;
|
||||||
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
|
const endpoint = `${prefix}/api/ndm/ndmSecurityBox/turnStatusNingTech`;
|
||||||
|
const resp = await client.post<boolean>(endpoint, { community, ipAddress, circuit: `${circuitIndex}`, status }, { signal });
|
||||||
|
const data = unwrapResponse(resp);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ningtech安防箱重启
|
||||||
|
export const rebootSecurityBoxNingTechApi = async (community: string, ipAddress: string, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
|
const { stationCode, signal } = options ?? {};
|
||||||
|
const client = stationCode ? ndmClient : userClient;
|
||||||
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
|
const endpoint = `${prefix}/api/ndm/ndmSecurityBox/rebootNingTech`;
|
||||||
|
const resp = await client.post<boolean>(endpoint, { community, ipAddress }, { signal });
|
||||||
const data = unwrapResponse(resp);
|
const data = unwrapResponse(resp);
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|||||||
+21
-7
@@ -2,8 +2,6 @@
|
|||||||
import {
|
import {
|
||||||
detailDeviceApi,
|
detailDeviceApi,
|
||||||
probeDeviceApi,
|
probeDeviceApi,
|
||||||
rebootSecurityBoxApi,
|
|
||||||
turnCitcuitStatusApi,
|
|
||||||
updateDeviceApi,
|
updateDeviceApi,
|
||||||
type LinkDescription,
|
type LinkDescription,
|
||||||
type NdmDeviceResultVO,
|
type NdmDeviceResultVO,
|
||||||
@@ -16,6 +14,7 @@ import { SecurityBoxCircuitLinkModal } from '@/components';
|
|||||||
import { usePermission } from '@/composables';
|
import { usePermission } from '@/composables';
|
||||||
import { SELECT_DEVICE_FN_INJECTION_KEY } from '@/constants';
|
import { SELECT_DEVICE_FN_INJECTION_KEY } from '@/constants';
|
||||||
import { PERMISSION_TYPE_LITERALS } from '@/enums';
|
import { PERMISSION_TYPE_LITERALS } from '@/enums';
|
||||||
|
import { normalizeSecurityBoxWriteCommunity, dispatchRebootSecurityBoxApi, dispatchTurnCircuitStatusApi, normalizeSecurityBoxCircuitIndex } from '@/helpers';
|
||||||
import { useDeviceStore, useSettingStore } from '@/stores';
|
import { useDeviceStore, useSettingStore } from '@/stores';
|
||||||
import { parseErrorFeedback } from '@/utils';
|
import { parseErrorFeedback } from '@/utils';
|
||||||
import { useMutation } from '@tanstack/vue-query';
|
import { useMutation } from '@tanstack/vue-query';
|
||||||
@@ -31,6 +30,7 @@ import { computed, inject, ref, toRefs } from 'vue';
|
|||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
ndmDevice: NdmSecurityBoxResultVO;
|
ndmDevice: NdmSecurityBoxResultVO;
|
||||||
station: Station;
|
station: Station;
|
||||||
|
vendor?: string;
|
||||||
circuits?: NdmSecurityBoxCircuit[];
|
circuits?: NdmSecurityBoxCircuit[];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ const { useLocalDB } = storeToRefs(settingStore);
|
|||||||
|
|
||||||
const { hasPermission } = usePermission();
|
const { hasPermission } = usePermission();
|
||||||
|
|
||||||
const { ndmDevice, station, circuits } = toRefs(props);
|
const { ndmDevice, station, vendor, circuits } = toRefs(props);
|
||||||
|
|
||||||
const showCard = computed(() => !!circuits.value && circuits.value.length > 0);
|
const showCard = computed(() => !!circuits.value && circuits.value.length > 0);
|
||||||
|
|
||||||
@@ -52,6 +52,10 @@ const localCircuits = ref<NdmSecurityBoxCircuit[]>([]);
|
|||||||
|
|
||||||
watchImmediate(circuits, (newCircuits) => {
|
watchImmediate(circuits, (newCircuits) => {
|
||||||
localCircuits.value = newCircuits?.map((circuit) => ({ ...circuit })) ?? [];
|
localCircuits.value = newCircuits?.map((circuit) => ({ ...circuit })) ?? [];
|
||||||
|
const circuitCount = ndmDevice.value.circuitCount;
|
||||||
|
if (!!circuitCount) {
|
||||||
|
localCircuits.value = localCircuits.value.slice(0, circuitCount);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const getCircuitStatusTagType = (circuit: NdmSecurityBoxCircuit): TagProps['type'] => {
|
const getCircuitStatusTagType = (circuit: NdmSecurityBoxCircuit): TagProps['type'] => {
|
||||||
@@ -79,13 +83,19 @@ const { mutate: turnStatus, isPending: turning } = useMutation({
|
|||||||
window.$loadingBar.start();
|
window.$loadingBar.start();
|
||||||
|
|
||||||
const { circuitIndex, newStatus } = params;
|
const { circuitIndex, newStatus } = params;
|
||||||
if (!ndmDevice.value.ipAddress) {
|
const community = normalizeSecurityBoxWriteCommunity(ndmDevice.value, vendor.value);
|
||||||
|
const ipAddress = ndmDevice.value.ipAddress;
|
||||||
|
if (!ipAddress) {
|
||||||
throw new Error('设备IP地址不存在');
|
throw new Error('设备IP地址不存在');
|
||||||
}
|
}
|
||||||
const status = newStatus ? 1 : 0;
|
const status = newStatus ? 1 : 0;
|
||||||
|
|
||||||
const stationCode = station.value.code;
|
const stationCode = station.value.code;
|
||||||
const signal = abortController.value.signal;
|
const signal = abortController.value.signal;
|
||||||
await turnCitcuitStatusApi(ndmDevice.value.ipAddress, circuitIndex, status, { stationCode, signal });
|
|
||||||
|
const turnCircuitStatusApi = dispatchTurnCircuitStatusApi(vendor.value);
|
||||||
|
const normalizedCircuitIndex = normalizeSecurityBoxCircuitIndex(circuitIndex, vendor.value);
|
||||||
|
await turnCircuitStatusApi(community, ipAddress, normalizedCircuitIndex, status, { stationCode, signal });
|
||||||
await probeDeviceApi(ndmDevice.value, { stationCode, signal });
|
await probeDeviceApi(ndmDevice.value, { stationCode, signal });
|
||||||
return status;
|
return status;
|
||||||
},
|
},
|
||||||
@@ -110,13 +120,17 @@ const { mutate: reboot, isPending: rebooting } = useMutation({
|
|||||||
|
|
||||||
window.$loadingBar.start();
|
window.$loadingBar.start();
|
||||||
|
|
||||||
if (!ndmDevice.value.ipAddress) {
|
const community = normalizeSecurityBoxWriteCommunity(ndmDevice.value, vendor.value);
|
||||||
|
const ipAddress = ndmDevice.value.ipAddress;
|
||||||
|
if (!ipAddress) {
|
||||||
throw new Error('设备IP地址不存在');
|
throw new Error('设备IP地址不存在');
|
||||||
}
|
}
|
||||||
|
|
||||||
const stationCode = station.value.code;
|
const stationCode = station.value.code;
|
||||||
const signal = abortController.value.signal;
|
const signal = abortController.value.signal;
|
||||||
await rebootSecurityBoxApi(ndmDevice.value.ipAddress, { stationCode, signal });
|
|
||||||
|
const rebootSecurityBoxApi = dispatchRebootSecurityBoxApi(vendor.value);
|
||||||
|
await rebootSecurityBoxApi(community, ipAddress, { stationCode, signal });
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
window.$loadingBar.finish();
|
window.$loadingBar.finish();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { NdmSecurityBoxDiagInfo, NdmSecurityBoxResultVO, Station } from '@/apis';
|
import type { NdmSecurityBoxDiagInfo, NdmSecurityBoxResultVO, Station } from '@/apis';
|
||||||
import { DeviceCommonCard, DeviceHardwareCard, DeviceHeaderCard, SecurityBoxCircuitCard, SecurityBoxEnvCard, type DeviceCommonCardProps } from '@/components';
|
import { DeviceCommonCard, DeviceHardwareCard, DeviceHeaderCard, SecurityBoxCircuitCard, SecurityBoxEnvCard, type DeviceCommonCardProps } from '@/components';
|
||||||
|
import { SECURITY_BOX_VENDOR_LITERALS } from '@/helpers';
|
||||||
import destr from 'destr';
|
import destr from 'destr';
|
||||||
import { NFlex } from 'naive-ui';
|
import { NFlex } from 'naive-ui';
|
||||||
import { computed, toRefs } from 'vue';
|
import { computed, toRefs } from 'vue';
|
||||||
@@ -19,6 +20,20 @@ const lastDiagInfo = computed(() => {
|
|||||||
return result as NdmSecurityBoxDiagInfo;
|
return result as NdmSecurityBoxDiagInfo;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 解析安防箱厂商
|
||||||
|
const vendor = computed(() => {
|
||||||
|
// 先读取诊断信息中的 stCommonInfo 中的设备厂商
|
||||||
|
if (!!lastDiagInfo.value?.stCommonInfo?.设备厂商) {
|
||||||
|
return lastDiagInfo.value.stCommonInfo.设备厂商.trim().toLocaleLowerCase();
|
||||||
|
}
|
||||||
|
// 如果 stCommonInfo 中没有设备厂商,再读取 ndmDevice 中的 manufacturer
|
||||||
|
if (!!ndmDevice.value.manufacturer) {
|
||||||
|
return ndmDevice.value.manufacturer.trim().toLocaleLowerCase();
|
||||||
|
}
|
||||||
|
// 如果 ndmDevice 中也没有 manufacturer,返回 beidian 作为兜底
|
||||||
|
return SECURITY_BOX_VENDOR_LITERALS.beidian;
|
||||||
|
});
|
||||||
|
|
||||||
const commonInfo = computed<DeviceCommonCardProps['commonInfo']>(() => {
|
const commonInfo = computed<DeviceCommonCardProps['commonInfo']>(() => {
|
||||||
const { stCommonInfo } = lastDiagInfo.value ?? {};
|
const { stCommonInfo } = lastDiagInfo.value ?? {};
|
||||||
const { 设备ID, 软件版本, 设备厂商, 设备别名, 设备型号, 硬件版本 } = stCommonInfo ?? {};
|
const { 设备ID, 软件版本, 设备厂商, 设备别名, 设备型号, 硬件版本 } = stCommonInfo ?? {};
|
||||||
@@ -55,7 +70,7 @@ const circuits = computed(() => lastDiagInfo.value?.info?.at(0)?.circuits);
|
|||||||
<DeviceCommonCard :common-info="commonInfo" />
|
<DeviceCommonCard :common-info="commonInfo" />
|
||||||
<DeviceHardwareCard :cpu-usage="cpuUsage" :mem-usage="memUsage" />
|
<DeviceHardwareCard :cpu-usage="cpuUsage" :mem-usage="memUsage" />
|
||||||
<SecurityBoxEnvCard :fan-speeds="fanSpeeds" :temperature="temperature" :humidity="humidity" :switches="switches" />
|
<SecurityBoxEnvCard :fan-speeds="fanSpeeds" :temperature="temperature" :humidity="humidity" :switches="switches" />
|
||||||
<SecurityBoxCircuitCard :ndm-device="ndmDevice" :station="station" :circuits="circuits" />
|
<SecurityBoxCircuitCard :ndm-device="ndmDevice" :station="station" :vendor="vendor" :circuits="circuits" />
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from './nvr';
|
export * from './nvr';
|
||||||
|
export * from './security-box';
|
||||||
export * from './switch';
|
export * from './switch';
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import { rebootSecurityBoxBeidianApi, rebootSecurityBoxNingTechApi, turnCircuitStatusBeidianApi, turnCircuitStatusNingTechApi, type NdmSecurityBoxResultVO } from '@/apis';
|
||||||
|
import { objectEntries } from '@vueuse/core';
|
||||||
|
|
||||||
|
const UNSUPPORTED_SECURITY_BOX_VENDOR = '不支持的安防箱厂商';
|
||||||
|
|
||||||
|
export const SECURITY_BOX_VENDOR_LITERALS = {
|
||||||
|
beidian: 'beidian',
|
||||||
|
ningtech: 'ningtech',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type SecurityBoxVendor = keyof typeof SECURITY_BOX_VENDOR_LITERALS;
|
||||||
|
|
||||||
|
export const resolveSecurityBoxVendor = (vendor?: string) => {
|
||||||
|
const entry = objectEntries(SECURITY_BOX_VENDOR_LITERALS).find(([, value]) => value === vendor);
|
||||||
|
return entry?.at(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const normalizeSecurityBoxWriteCommunity = (ndmDevice: NdmSecurityBoxResultVO, vendor?: string) => {
|
||||||
|
const resolved = resolveSecurityBoxVendor(vendor);
|
||||||
|
if (resolved === SECURITY_BOX_VENDOR_LITERALS.beidian) {
|
||||||
|
const community = ndmDevice.community;
|
||||||
|
if (!community) throw new Error('团体字符串不存在');
|
||||||
|
return community;
|
||||||
|
}
|
||||||
|
if (resolved === SECURITY_BOX_VENDOR_LITERALS.ningtech) {
|
||||||
|
const community = ndmDevice.writeCommunity;
|
||||||
|
if (!community) throw new Error('团体字符串(写)不存在');
|
||||||
|
return community;
|
||||||
|
}
|
||||||
|
throw new Error(UNSUPPORTED_SECURITY_BOX_VENDOR);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const normalizeSecurityBoxCircuitIndex = (index: number, vendor?: string) => {
|
||||||
|
const resolved = resolveSecurityBoxVendor(vendor);
|
||||||
|
if (resolved === SECURITY_BOX_VENDOR_LITERALS.beidian) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
if (resolved === SECURITY_BOX_VENDOR_LITERALS.ningtech) {
|
||||||
|
return index + 1;
|
||||||
|
}
|
||||||
|
throw new Error(UNSUPPORTED_SECURITY_BOX_VENDOR);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const dispatchTurnCircuitStatusApi = (vendor?: string) => {
|
||||||
|
const resolved = resolveSecurityBoxVendor(vendor);
|
||||||
|
if (resolved === SECURITY_BOX_VENDOR_LITERALS.beidian) {
|
||||||
|
return turnCircuitStatusBeidianApi;
|
||||||
|
}
|
||||||
|
if (resolved === SECURITY_BOX_VENDOR_LITERALS.ningtech) {
|
||||||
|
return turnCircuitStatusNingTechApi;
|
||||||
|
}
|
||||||
|
throw new Error(UNSUPPORTED_SECURITY_BOX_VENDOR);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const dispatchRebootSecurityBoxApi = (vendor?: string) => {
|
||||||
|
const resolved = resolveSecurityBoxVendor(vendor);
|
||||||
|
if (resolved === SECURITY_BOX_VENDOR_LITERALS.beidian) {
|
||||||
|
return rebootSecurityBoxBeidianApi;
|
||||||
|
}
|
||||||
|
if (resolved === SECURITY_BOX_VENDOR_LITERALS.ningtech) {
|
||||||
|
return rebootSecurityBoxNingTechApi;
|
||||||
|
}
|
||||||
|
throw new Error(UNSUPPORTED_SECURITY_BOX_VENDOR);
|
||||||
|
};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './adapter';
|
||||||
Reference in New Issue
Block a user