feat: 添加视频服务器双机热备状态
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
export interface HighAvailable {
|
||||
pyip: string;
|
||||
vip: string;
|
||||
changeDate: string;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './diag';
|
||||
export * from './high-available';
|
||||
export * from './link-description';
|
||||
export * from './station';
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
import { ndmClient, userClient, type MediaServerStatus, type SendRtpInfo, type Station } from '@/apis';
|
||||
import { unwrapResponse } from '@/utils';
|
||||
import { ndmClient, userClient, type HighAvailable, type MediaServerStatus, type SendRtpInfo, type Station } from '@/apis';
|
||||
import { unwrapNullableResponse, unwrapResponse } from '@/utils';
|
||||
import destr from 'destr';
|
||||
|
||||
// {
|
||||
// "code": 0,
|
||||
// "data": "{pyip:\"10.18.128.14\",vip:\"10.18.128.6\",changeDate:\"2026-03-23 15:55:00\"}",
|
||||
// "msg": "ok",
|
||||
// "path": null,
|
||||
// "extra": null,
|
||||
// "timestamp": "1774421387908",
|
||||
// "errorMsg": "",
|
||||
// "isSuccess": true
|
||||
// }
|
||||
export const getHighAvailableApi = async (options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||
const { stationCode, signal } = options ?? {};
|
||||
const client = stationCode ? ndmClient : userClient;
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const endpoint = `${prefix}/api/ndm/ndmServiceAvailable/highAvailable/get`;
|
||||
const resp = await client.get<string | null>(endpoint, { signal });
|
||||
const data = unwrapNullableResponse(resp);
|
||||
return destr<HighAvailable | null>(data);
|
||||
};
|
||||
|
||||
export const getAllPushApi = async (options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||
const { stationCode, signal } = options ?? {};
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import ServerAlive from './server-alive.vue';
|
||||
import ServerCard from './server-card.vue';
|
||||
import ServerCurrentDiag from './server-current-diag.vue';
|
||||
import ServerHighAvailable from './server-high-available.vue';
|
||||
import ServerHistoryDiag from './server-history-diag.vue';
|
||||
import ServerStreamPush from './server-stream-push.vue';
|
||||
import ServerUpdate from './server-update.vue';
|
||||
|
||||
export { ServerAlive, ServerCard, ServerCurrentDiag, ServerHistoryDiag, ServerUpdate, ServerStreamPush };
|
||||
export { ServerAlive, ServerCard, ServerCurrentDiag, ServerHighAvailable, ServerHistoryDiag, ServerUpdate, ServerStreamPush };
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { type NdmServerDiagInfo, type NdmServerResultVO, type Station } from '@/apis';
|
||||
import { DeviceHardwareCard, DeviceHeaderCard, ServerAlive, ServerStreamPush } from '@/components';
|
||||
import { DeviceHardwareCard, DeviceHeaderCard, ServerAlive, ServerHighAvailable, ServerStreamPush } from '@/components';
|
||||
import destr from 'destr';
|
||||
import { NFlex } from 'naive-ui';
|
||||
import { computed, toRefs } from 'vue';
|
||||
@@ -27,6 +27,7 @@ const runningTime = computed(() => lastDiagInfo.value?.commInfo?.系统运行时
|
||||
|
||||
<template>
|
||||
<NFlex vertical>
|
||||
<ServerHighAvailable :ndm-device="ndmDevice" :station="station" />
|
||||
<DeviceHeaderCard :ndm-device="ndmDevice" :station="station" />
|
||||
<DeviceHardwareCard running-time-label="服务器运行时间" :cpu-usage="cpuUsage" :mem-usage="memUsage" :disk-usage="diskUsage" :running-time="runningTime" />
|
||||
<ServerAlive :ndm-device="ndmDevice" :station="station" />
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<script setup lang="ts">
|
||||
import { getHighAvailableApi, type NdmServerResultVO, type Station } from '@/apis';
|
||||
import { DEVICE_TYPE_LITERALS, tryGetDeviceType } from '@/enums';
|
||||
import { useSettingStore } from '@/stores';
|
||||
import { useQuery, useQueryClient } from '@tanstack/vue-query';
|
||||
import { NAlert, NCard, NFlex } from 'naive-ui';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { computed, toRefs, watch } from 'vue';
|
||||
|
||||
const props = defineProps<{
|
||||
ndmDevice: NdmServerResultVO;
|
||||
station: Station;
|
||||
}>();
|
||||
|
||||
const settingStore = useSettingStore();
|
||||
const { activeRequests } = storeToRefs(settingStore);
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { ndmDevice, station } = toRefs(props);
|
||||
|
||||
const deviceType = computed(() => tryGetDeviceType(ndmDevice.value.deviceType));
|
||||
|
||||
const isVideoServer = computed(() => deviceType.value === DEVICE_TYPE_LITERALS.ndmVideoServer);
|
||||
|
||||
const SERVER_HIGH_AVAILABLE_QUERY_KEY = 'server-high-available-query';
|
||||
|
||||
const deviceUniqueKey = computed(() => [station.value.code, ndmDevice.value.id]);
|
||||
|
||||
const { data: highAvailable } = useQuery({
|
||||
queryKey: computed(() => [SERVER_HIGH_AVAILABLE_QUERY_KEY, deviceUniqueKey.value, ndmDevice.value.lastDiagTime]),
|
||||
enabled: computed(() => activeRequests.value && isVideoServer.value),
|
||||
refetchInterval: 30 * 1000,
|
||||
gcTime: 0,
|
||||
queryFn: async ({ signal }) => {
|
||||
const highAvailable = await getHighAvailableApi({ stationCode: station.value.code, signal });
|
||||
return highAvailable;
|
||||
},
|
||||
});
|
||||
watch(activeRequests, (active) => {
|
||||
if (!active) {
|
||||
queryClient.cancelQueries({ queryKey: [SERVER_HIGH_AVAILABLE_QUERY_KEY] });
|
||||
}
|
||||
});
|
||||
|
||||
const showCard = computed(() => {
|
||||
const { pyip: physicalIp } = highAvailable.value ?? {};
|
||||
const ipAddressMatched = physicalIp === ndmDevice.value.ipAddress;
|
||||
return isVideoServer.value && ipAddressMatched;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NAlert v-if="showCard && !!highAvailable" :bordered="false" type="success">
|
||||
<template #header>
|
||||
<NFlex :align="'center'">
|
||||
<div>正在提供服务</div>
|
||||
<NFlex :align="'center'" style="font-size: smaller">
|
||||
<div>虚拟IP: {{ highAvailable.vip }}</div>
|
||||
<div>启用时间: {{ highAvailable.changeDate }}</div>
|
||||
</NFlex>
|
||||
</NFlex>
|
||||
</template>
|
||||
</NAlert>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -136,6 +136,17 @@ export const unwrapResponse = <T>(resp: HttpResponse<T>) => {
|
||||
return data;
|
||||
};
|
||||
|
||||
export const unwrapNullableResponse = <T>(resp: HttpResponse<T>) => {
|
||||
const [err, data, result] = resp;
|
||||
if (err) throw err;
|
||||
if (result) {
|
||||
const { isSuccess, path, msg, errorMsg } = result;
|
||||
if (!isSuccess) throw new Error(`${path ? `${path}: ` : ''}${msg || errorMsg || '请求失败'}`);
|
||||
}
|
||||
if (data === undefined) throw new Error('响应数据不存在');
|
||||
return data;
|
||||
};
|
||||
|
||||
// 针对没有数据的响应,直接判断是否存在错误
|
||||
export const unwrapVoidResponse = (resp: HttpResponse<void>) => {
|
||||
const [err, , result] = resp;
|
||||
|
||||
Reference in New Issue
Block a user