Compare commits
10 Commits
70e3063b40
...
cbb51aa501
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbb51aa501 | ||
|
|
4ab33d2021 | ||
|
|
fa9b435a0f | ||
|
|
dfbdc6d828 | ||
|
|
5fa668acd3 | ||
|
|
2f06054e66 | ||
|
|
df3888d8b5 | ||
|
|
91a665695e | ||
|
|
0c3e9c24f9 | ||
|
|
799a5af857 |
3
.env
3
.env
@@ -15,5 +15,8 @@ VITE_LAMP_PASSWORD = fjoc(1KHP(Ls&Bje)C
|
||||
# 如果 Authorization 已存在则会直接采用, 否则会根据 clientId 和 clientSecret 生成
|
||||
VITE_LAMP_AUTHORIZATION = Y3VlZGVzX2FkbWluOmN1ZWRlc19hZG1pbl9zZWNyZXQ=
|
||||
|
||||
# 当需要重置localStorage时, 修改此变量
|
||||
VITE_STORAGE_VERSION = 1
|
||||
|
||||
# 调试授权码
|
||||
VITE_DEBUG_CODE = ndm_debug
|
||||
|
||||
@@ -7,6 +7,7 @@ import type { NdmKeyboardVO } from './video/ndm-keyboard';
|
||||
import type { NdmMediaServerVO } from './video/ndm-media-server';
|
||||
import type { NdmVideoServerVO } from './video/ndm-video-server';
|
||||
|
||||
export * from './log/ndm-call-log';
|
||||
export * from './log/ndm-device-alarm-log';
|
||||
export * from './log/ndm-icmp-log';
|
||||
export * from './log/ndm-snmp-log';
|
||||
|
||||
17
src/apis/models/device/log/ndm-call-log.ts
Normal file
17
src/apis/models/device/log/ndm-call-log.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { BaseModel, ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '../../base';
|
||||
|
||||
export interface NdmCallLogVO extends BaseModel {
|
||||
sourceGbId: string;
|
||||
targetGbId: string;
|
||||
method: string;
|
||||
messageType: string;
|
||||
cmdType: string;
|
||||
}
|
||||
|
||||
export type NdmCallLogResultVO = Partial<NdmCallLogVO>;
|
||||
|
||||
export type NdmCallLogSaveVO = Partial<Omit<NdmCallLogVO, ReduceForSaveVO>>;
|
||||
|
||||
export type NdmCallLogUpdateVO = Partial<Omit<NdmCallLogVO, ReduceForUpdateVO>>;
|
||||
|
||||
export type NdmCallLogPageQuery = Partial<Omit<NdmCallLogVO, ReduceForPageQuery>>;
|
||||
@@ -1,5 +1,6 @@
|
||||
export * from './export/ndm-icmp-export';
|
||||
|
||||
export * from './log/ndm-call-log';
|
||||
export * from './log/ndm-device-alarm-log';
|
||||
export * from './log/ndm-icmp-log';
|
||||
export * from './log/ndm-snmp-log';
|
||||
@@ -15,3 +16,5 @@ export * from './video/ndm-decoder';
|
||||
export * from './video/ndm-keyboard';
|
||||
export * from './video/ndm-media-server';
|
||||
export * from './video/ndm-video-server';
|
||||
|
||||
export * from './ndm-probe';
|
||||
|
||||
25
src/apis/requests/device/log/ndm-call-log.ts
Normal file
25
src/apis/requests/device/log/ndm-call-log.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { ndmClient } from '@/apis/client';
|
||||
import type { NdmCallLogPageQuery, NdmCallLogResultVO, PageParams, PageResult } from '@/apis/models';
|
||||
|
||||
export const postNdmCallLogPage = async (stationCode: string, pageQuery: PageParams<NdmCallLogPageQuery>) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.post<PageResult<NdmCallLogResultVO>>(`${prefix}/api/ndm/ndmCallLog/page`, pageQuery);
|
||||
const [err, callLogData] = resp;
|
||||
if (err || !callLogData) {
|
||||
throw err;
|
||||
}
|
||||
return callLogData;
|
||||
};
|
||||
|
||||
export const ndmCallLogDefaultExportByTemplate = async (stationCode: string, pageQuery: PageParams<NdmCallLogPageQuery>) => {
|
||||
const endpoint = '/api/ndm/ndmCallLog/defaultExportByTemplate';
|
||||
if (!stationCode) {
|
||||
throw new Error('请选择车站');
|
||||
}
|
||||
const resp = await ndmClient.post<Blob>(`/${stationCode}${endpoint}`, pageQuery, { responseType: 'blob', retRaw: true });
|
||||
const [err, data] = resp;
|
||||
if (err || !data) {
|
||||
throw err;
|
||||
}
|
||||
return data;
|
||||
};
|
||||
121
src/apis/requests/device/ndm-probe.ts
Normal file
121
src/apis/requests/device/ndm-probe.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import { ndmClient } from '@/apis/client';
|
||||
import type { NdmDeviceResultVO } from '@/apis/models';
|
||||
import { getNdmDecoderDetail, getNdmKeyboardDetail, getNdmMediaServerDetail, getNdmNvrDetail, getNdmSecurityBoxDetail, getNdmSwitchDetail, getNdmVideoServerDetail } from '@/apis/requests';
|
||||
import { DeviceType, tryGetDeviceTypeVal } from '@/enums/device-type';
|
||||
|
||||
export const probeNdmDecoderByIds = async (stationCode: string, ids: string[]) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.post<void>(`${prefix}/api/ndm/ndmDecoder/probeByIds`, ids);
|
||||
const [err] = resp;
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
export const probeNdmNvrByIds = async (stationCode: string, ids: string[]) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.post<void>(`${prefix}/api/ndm/ndmNvr/probeByIds`, ids);
|
||||
const [err] = resp;
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
export const probeNdmSecurityBoxByIds = async (stationCode: string, ids: string[]) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.post<void>(`${prefix}/api/ndm/ndmSecurityBox/probeByIds`, ids);
|
||||
const [err] = resp;
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
export const probeNdmMediaServerByIds = async (stationCode: string, ids: string[]) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.post<void>(`${prefix}/api/ndm/ndmMediaServer/probeByIds`, ids);
|
||||
const [err] = resp;
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
export const probeNdmSwitchByIds = async (stationCode: string, ids: string[]) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.post<void>(`${prefix}/api/ndm/ndmSwitch/probeByIds`, ids);
|
||||
const [err] = resp;
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
export const probeNdmVideoServerByIds = async (stationCode: string, ids: string[]) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.post<void>(`${prefix}/api/ndm/ndmVideoServer/probeByIds`, ids);
|
||||
const [err] = resp;
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
export const probeDeviceApi = async (stationCode: string, device: NdmDeviceResultVO) => {
|
||||
const deviceType = tryGetDeviceTypeVal(device.deviceType);
|
||||
const deviceDbId = device.id;
|
||||
if (!deviceType || !deviceDbId) {
|
||||
throw new Error('未知的设备');
|
||||
}
|
||||
if (deviceType === DeviceType.Decoder) {
|
||||
await probeNdmDecoderByIds(stationCode, [deviceDbId]);
|
||||
return;
|
||||
}
|
||||
if (deviceType === DeviceType.Nvr) {
|
||||
await probeNdmNvrByIds(stationCode, [deviceDbId]);
|
||||
return;
|
||||
}
|
||||
if (deviceType === DeviceType.SecurityBox) {
|
||||
await probeNdmSecurityBoxByIds(stationCode, [deviceDbId]);
|
||||
return;
|
||||
}
|
||||
if (deviceType === DeviceType.MediaServer) {
|
||||
await probeNdmMediaServerByIds(stationCode, [deviceDbId]);
|
||||
return;
|
||||
}
|
||||
if (deviceType === DeviceType.Switch) {
|
||||
await probeNdmSwitchByIds(stationCode, [deviceDbId]);
|
||||
return;
|
||||
}
|
||||
if (deviceType === DeviceType.VideoServer) {
|
||||
await probeNdmVideoServerByIds(stationCode, [deviceDbId]);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
export const getDeviceDetailApi = async (stationCode: string, id?: string, deviceType?: string): Promise<NdmDeviceResultVO | undefined> => {
|
||||
if (!id || !deviceType) {
|
||||
throw new Error('未知的设备');
|
||||
}
|
||||
if (deviceType === DeviceType.Camera) {
|
||||
return await getNdmVideoServerDetail(stationCode, id);
|
||||
}
|
||||
if (deviceType === DeviceType.Decoder) {
|
||||
return await getNdmDecoderDetail(stationCode, id);
|
||||
}
|
||||
if (deviceType === DeviceType.Keyboard) {
|
||||
return await getNdmKeyboardDetail(stationCode, id);
|
||||
}
|
||||
if (deviceType === DeviceType.MediaServer) {
|
||||
return await getNdmMediaServerDetail(stationCode, id);
|
||||
}
|
||||
if (deviceType === DeviceType.Nvr) {
|
||||
return await getNdmNvrDetail(stationCode, id);
|
||||
}
|
||||
if (deviceType === DeviceType.SecurityBox) {
|
||||
return await getNdmSecurityBoxDetail(stationCode, id);
|
||||
}
|
||||
if (deviceType === DeviceType.Switch) {
|
||||
return await getNdmSwitchDetail(stationCode, id);
|
||||
}
|
||||
if (deviceType === DeviceType.VideoServer) {
|
||||
return await getNdmVideoServerDetail(stationCode, id);
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -4,6 +4,16 @@ import type { PageParams, NdmSecurityBoxPageQuery, PageResult, NdmSecurityBoxRes
|
||||
export const postNdmSecurityBoxPage = async (stationCode: string, pageQuery: PageParams<NdmSecurityBoxPageQuery>, signal?: AbortSignal) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.post<PageResult<NdmSecurityBoxResultVO>>(`${prefix}/api/ndm/ndmSecurityBox/page`, pageQuery, { signal });
|
||||
const [err, ndmSecurityBox] = resp;
|
||||
if (err || !ndmSecurityBox) {
|
||||
throw err;
|
||||
}
|
||||
return ndmSecurityBox;
|
||||
};
|
||||
|
||||
export const getNdmSecurityBoxDetail = async (stationCode: string, id: string) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.get<NdmSecurityBoxResultVO>(`${prefix}/api/ndm/ndmSecurityBox/detail`, { params: { id } });
|
||||
const [err, ndmSecurityBoxData] = resp;
|
||||
if (err || !ndmSecurityBoxData) {
|
||||
throw err;
|
||||
@@ -18,7 +28,7 @@ export const putNdmSecurityBox = async (stationCode: string, updateVO: NdmSecuri
|
||||
if (err || !ndmSecurityBox) {
|
||||
throw err;
|
||||
}
|
||||
return ndmSecurityBox;
|
||||
return await getNdmSecurityBoxDetail(stationCode, ndmSecurityBox.id ?? '');
|
||||
};
|
||||
|
||||
export const turnStatus = async (stationCode: string, ipAddress: string, circuitIndex: number, status: number) => {
|
||||
|
||||
@@ -4,6 +4,16 @@ import type { PageParams, NdmSwitchPageQuery, PageResult, NdmSwitchResultVO, Ndm
|
||||
export const postNdmSwitchPage = async (stationCode: string, pageQuery: PageParams<NdmSwitchPageQuery>, signal?: AbortSignal) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.post<PageResult<NdmSwitchResultVO>>(`${prefix}/api/ndm/ndmSwitch/page`, pageQuery, { signal });
|
||||
const [err, ndmSwitch] = resp;
|
||||
if (err || !ndmSwitch) {
|
||||
throw err;
|
||||
}
|
||||
return ndmSwitch;
|
||||
};
|
||||
|
||||
export const getNdmSwitchDetail = async (stationCode: string, id: string) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.get<NdmSwitchResultVO>(`${prefix}/api/ndm/ndmSwitch/detail`, { params: { id } });
|
||||
const [err, ndmSwitchData] = resp;
|
||||
if (err || !ndmSwitchData) {
|
||||
throw err;
|
||||
@@ -18,5 +28,5 @@ export const putNdmSwitch = async (stationCode: string, updateVO: NdmSwitchUpdat
|
||||
if (err || !ndmSwitch) {
|
||||
throw err;
|
||||
}
|
||||
return ndmSwitch;
|
||||
return await getNdmSwitchDetail(stationCode, ndmSwitch.id ?? '');
|
||||
};
|
||||
|
||||
@@ -5,11 +5,21 @@ import dayjs from 'dayjs';
|
||||
export const postNdmNvrPage = async (stationCode: string, pageQuery: PageParams<NdmNvrPageQuery>, signal?: AbortSignal) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.post<PageResult<NdmNvrResultVO>>(`${prefix}/api/ndm/ndmNvr/page`, pageQuery, { signal });
|
||||
const [err, ndmNvrData] = resp;
|
||||
if (err || !ndmNvrData) {
|
||||
const [err, ndmNvr] = resp;
|
||||
if (err || !ndmNvr) {
|
||||
throw err;
|
||||
}
|
||||
return ndmNvrData;
|
||||
return ndmNvr;
|
||||
};
|
||||
|
||||
export const getNdmNvrDetail = async (stationCode: string, id: string) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.get<NdmNvrResultVO>(`${prefix}/api/ndm/ndmNvr/detail`, { params: { id } });
|
||||
const [err, ndmNvr] = resp;
|
||||
if (err || !ndmNvr) {
|
||||
throw err;
|
||||
}
|
||||
return ndmNvr;
|
||||
};
|
||||
|
||||
export const putNdmNvr = async (stationCode: string, updateVO: NdmNvrUpdateVO) => {
|
||||
@@ -19,7 +29,7 @@ export const putNdmNvr = async (stationCode: string, updateVO: NdmNvrUpdateVO) =
|
||||
if (err || !ndmNvr) {
|
||||
throw err;
|
||||
}
|
||||
return ndmNvr;
|
||||
return await getNdmNvrDetail(stationCode, ndmNvr.id ?? '');
|
||||
};
|
||||
|
||||
export const getChannelList = async (stationCode: string, ndmNvr: NdmNvrResultVO) => {
|
||||
|
||||
@@ -4,11 +4,21 @@ import type { PageParams, NdmCameraPageQuery, PageResult, NdmCameraResultVO, Ndm
|
||||
export const postNdmCameraPage = async (stationCode: string, pageQuery: PageParams<NdmCameraPageQuery>, signal?: AbortSignal) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.post<PageResult<NdmCameraResultVO>>(`${prefix}/api/ndm/ndmCamera/page`, pageQuery, { signal });
|
||||
const [err, ndmCameraData] = resp;
|
||||
if (err || !ndmCameraData) {
|
||||
const [err, ndmCamera] = resp;
|
||||
if (err || !ndmCamera) {
|
||||
throw err;
|
||||
}
|
||||
return ndmCameraData;
|
||||
return ndmCamera;
|
||||
};
|
||||
|
||||
export const getNdmCameraDetail = async (stationCode: string, id: string) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.get<NdmCameraResultVO>(`${prefix}/api/ndm/ndmCamera/detail`, { params: { id } });
|
||||
const [err, ndmCamera] = resp;
|
||||
if (err || !ndmCamera) {
|
||||
throw err;
|
||||
}
|
||||
return ndmCamera;
|
||||
};
|
||||
|
||||
export const putNdmCamera = async (stationCode: string, updateVO: NdmCameraUpdateVO) => {
|
||||
@@ -18,5 +28,5 @@ export const putNdmCamera = async (stationCode: string, updateVO: NdmCameraUpdat
|
||||
if (err || !ndmCamera) {
|
||||
throw err;
|
||||
}
|
||||
return ndmCamera;
|
||||
return await getNdmCameraDetail(stationCode, ndmCamera.id ?? '');
|
||||
};
|
||||
|
||||
@@ -4,11 +4,21 @@ import type { PageParams, NdmDecoderPageQuery, PageResult, NdmDecoderResultVO, N
|
||||
export const postNdmDecoderPage = async (stationCode: string, pageQuery: PageParams<NdmDecoderPageQuery>, signal?: AbortSignal) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.post<PageResult<NdmDecoderResultVO>>(`${prefix}/api/ndm/ndmDecoder/page`, pageQuery, { signal });
|
||||
const [err, ndmDecoderData] = resp;
|
||||
if (err || !ndmDecoderData) {
|
||||
const [err, ndmDecoder] = resp;
|
||||
if (err || !ndmDecoder) {
|
||||
throw err;
|
||||
}
|
||||
return ndmDecoderData;
|
||||
return ndmDecoder;
|
||||
};
|
||||
|
||||
export const getNdmDecoderDetail = async (stationCode: string, id: string) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.get<NdmDecoderResultVO>(`${prefix}/api/ndm/ndmDecoder/detail`, { params: { id } });
|
||||
const [err, ndmDecoder] = resp;
|
||||
if (err || !ndmDecoder) {
|
||||
throw err;
|
||||
}
|
||||
return ndmDecoder;
|
||||
};
|
||||
|
||||
export const putNdmDecoder = async (stationCode: string, updateVO: NdmDecoderUpdateVO) => {
|
||||
@@ -18,5 +28,5 @@ export const putNdmDecoder = async (stationCode: string, updateVO: NdmDecoderUpd
|
||||
if (err || !ndmDecoder) {
|
||||
throw err;
|
||||
}
|
||||
return ndmDecoder;
|
||||
return await getNdmDecoderDetail(stationCode, ndmDecoder.id ?? '');
|
||||
};
|
||||
|
||||
@@ -11,6 +11,16 @@ export const postNdmKeyboardPage = async (stationCode: string, pageQuery: PagePa
|
||||
return ndmKeyboardData;
|
||||
};
|
||||
|
||||
export const getNdmKeyboardDetail = async (stationCode: string, id: string) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.get<NdmKeyboardResultVO>(`${prefix}/api/ndm/ndmKeyboard/detail`, { params: { id } });
|
||||
const [err, ndmKeyboardData] = resp;
|
||||
if (err || !ndmKeyboardData) {
|
||||
throw err;
|
||||
}
|
||||
return ndmKeyboardData;
|
||||
};
|
||||
|
||||
export const putNdmKeyboard = async (stationCode: string, updateVO: NdmKeyboardUpdateVO) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.put<NdmKeyboardResultVO>(`${prefix}/api/ndm/ndmKeyboard`, updateVO);
|
||||
@@ -18,5 +28,5 @@ export const putNdmKeyboard = async (stationCode: string, updateVO: NdmKeyboardU
|
||||
if (err || !ndmKeyboard) {
|
||||
throw err;
|
||||
}
|
||||
return ndmKeyboard;
|
||||
return await getNdmKeyboardDetail(stationCode, ndmKeyboard.id ?? '');
|
||||
};
|
||||
|
||||
@@ -4,11 +4,21 @@ import type { PageParams, NdmMediaServerPageQuery, PageResult, NdmMediaServerRes
|
||||
export const postNdmMediaServerPage = async (stationCode: string, pageQuery: PageParams<NdmMediaServerPageQuery>, signal?: AbortSignal) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.post<PageResult<NdmMediaServerResultVO>>(`${prefix}/api/ndm/ndmMediaServer/page`, pageQuery, { signal });
|
||||
const [err, ndmMediaServerData] = resp;
|
||||
if (err || !ndmMediaServerData) {
|
||||
const [err, ndmMediaServer] = resp;
|
||||
if (err || !ndmMediaServer) {
|
||||
throw err;
|
||||
}
|
||||
return ndmMediaServerData;
|
||||
return ndmMediaServer;
|
||||
};
|
||||
|
||||
export const getNdmMediaServerDetail = async (stationCode: string, id: string) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.get<NdmMediaServerResultVO>(`${prefix}/api/ndm/ndmMediaServer/detail`, { params: { id } });
|
||||
const [err, ndmMediaServer] = resp;
|
||||
if (err || !ndmMediaServer) {
|
||||
throw err;
|
||||
}
|
||||
return ndmMediaServer;
|
||||
};
|
||||
|
||||
export const putNdmMediaServer = async (stationCode: string, updateVO: NdmMediaServerUpdateVO) => {
|
||||
@@ -18,5 +28,5 @@ export const putNdmMediaServer = async (stationCode: string, updateVO: NdmMediaS
|
||||
if (err || !ndmMediaServer) {
|
||||
throw err;
|
||||
}
|
||||
return ndmMediaServer;
|
||||
return await getNdmMediaServerDetail(stationCode, ndmMediaServer.id ?? '');
|
||||
};
|
||||
|
||||
@@ -4,11 +4,21 @@ import type { PageParams, NdmVideoServerPageQuery, PageResult, NdmVideoServerRes
|
||||
export const postNdmVideoServerPage = async (stationCode: string, pageQuery: PageParams<NdmVideoServerPageQuery>, signal?: AbortSignal) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.post<PageResult<NdmVideoServerResultVO>>(`${prefix}/api/ndm/ndmVideoServer/page`, pageQuery, { signal });
|
||||
const [err, ndmVideoServerData] = resp;
|
||||
if (err || !ndmVideoServerData) {
|
||||
const [err, ndmVideoServer] = resp;
|
||||
if (err || !ndmVideoServer) {
|
||||
throw err;
|
||||
}
|
||||
return ndmVideoServerData;
|
||||
return ndmVideoServer;
|
||||
};
|
||||
|
||||
export const getNdmVideoServerDetail = async (stationCode: string, id: string) => {
|
||||
const prefix = stationCode ? `/${stationCode}` : '';
|
||||
const resp = await ndmClient.get<NdmVideoServerResultVO>(`${prefix}/api/ndm/ndmVideoServer/detail`, { params: { id } });
|
||||
const [err, ndmVideoServer] = resp;
|
||||
if (err || !ndmVideoServer) {
|
||||
throw err;
|
||||
}
|
||||
return ndmVideoServer;
|
||||
};
|
||||
|
||||
export const putNdmVideoServer = async (stationCode: string, updateVO: NdmVideoServerUpdateVO) => {
|
||||
@@ -18,5 +28,5 @@ export const putNdmVideoServer = async (stationCode: string, updateVO: NdmVideoS
|
||||
if (err || !ndmVideoServer) {
|
||||
throw err;
|
||||
}
|
||||
return ndmVideoServer;
|
||||
return await getNdmVideoServerDetail(stationCode, ndmVideoServer.id ?? '');
|
||||
};
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
import type { Station } from '@/apis/domains';
|
||||
import { DeviceType } from '@/enums/device-type';
|
||||
import { type StationAlarmCounts, type StationDevices } from '@/composables/query';
|
||||
import { ControlOutlined } from '@vicons/antd';
|
||||
import { Video as VideoIcon } from '@vicons/carbon';
|
||||
import { MoreOutlined, EllipsisOutlined } from '@vicons/antd';
|
||||
import axios from 'axios';
|
||||
import { NCard, NTag, NButton, NIcon, useThemeVars, NSpace, NFlex, NText, NTooltip } from 'naive-ui';
|
||||
import { NCard, NTag, NButton, NIcon, useThemeVars, NFlex, NText, NTooltip, NDropdown, type DropdownOption } from 'naive-ui';
|
||||
import { toRefs, computed } from 'vue';
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -89,102 +88,106 @@ const openVideoPlatform = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const dropdownOptions: DropdownOption[] = [
|
||||
{
|
||||
label: '视频平台',
|
||||
key: 'video-platform',
|
||||
onClick: openVideoPlatform,
|
||||
},
|
||||
{
|
||||
label: '设备配置',
|
||||
key: 'device-config',
|
||||
onClick: openDeviceConfigModal,
|
||||
},
|
||||
];
|
||||
|
||||
const selectDropdownOption = (key: string, option: DropdownOption) => {
|
||||
if (typeof option['onClick'] === 'function') {
|
||||
option['onClick']();
|
||||
}
|
||||
};
|
||||
|
||||
const theme = useThemeVars();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NCard bordered hoverable size="small" class="station-card" :header-style="{ padding: `6px` }" :content-style="{ padding: `0px 6px 6px 6px` }">
|
||||
<NCard bordered hoverable size="medium" class="station-card" :header-style="{ padding: `6px` }" :content-style="{ padding: `0px 6px 6px 6px` }">
|
||||
<template #header>
|
||||
<NTooltip v-if="station.ip" trigger="click">
|
||||
<template #trigger>
|
||||
<span class="font-smaller">{{ station.name }}</span>
|
||||
<span class="font-medium">{{ station.name }}</span>
|
||||
</template>
|
||||
<span>{{ station.ip }}</span>
|
||||
</NTooltip>
|
||||
<span v-else class="font-smaller">{{ station.name }}</span>
|
||||
<span v-else class="font-medium">{{ station.name }}</span>
|
||||
</template>
|
||||
<template #header-extra>
|
||||
<NTag :type="station.online ? 'success' : 'error'" size="small">
|
||||
{{ station.online ? '在线' : '离线' }}
|
||||
</NTag>
|
||||
<NFlex :size="4">
|
||||
<NTag :type="station.online ? 'success' : 'error'" size="small">
|
||||
{{ station.online ? '在线' : '离线' }}
|
||||
</NTag>
|
||||
<NDropdown trigger="click" :options="dropdownOptions" @select="selectDropdownOption">
|
||||
<NButton quaternary size="tiny" :focusable="false">
|
||||
<NIcon :component="MoreOutlined" />
|
||||
</NButton>
|
||||
</NDropdown>
|
||||
</NFlex>
|
||||
</template>
|
||||
|
||||
<template #default>
|
||||
<NSpace vertical :size="8">
|
||||
<NFlex :justify="'flex-start'" class="actions">
|
||||
<NButton quaternary size="tiny" :focusable="false" :disabled="!station.online" @click="openVideoPlatform">
|
||||
<NIcon>
|
||||
<VideoIcon />
|
||||
</NIcon>
|
||||
<span class="btn-text">视频平台</span>
|
||||
</NButton>
|
||||
|
||||
<NButton quaternary size="tiny" :focusable="false" :disabled="!station.online" @click="openDeviceConfigModal">
|
||||
<NIcon>
|
||||
<ControlOutlined />
|
||||
</NIcon>
|
||||
<span class="btn-text">设备配置</span>
|
||||
</NButton>
|
||||
</NFlex>
|
||||
|
||||
<NFlex vertical :size="0" class="metrics" :style="{ opacity: station.online ? '1' : '0.5' }">
|
||||
<NFlex justify="space-between" align="baseline" class="metric-item">
|
||||
<NText depth="3" class="metric-label" :class="[station.online ? 'clickable' : '']" @click="station.online && openOfflineDeviceTreeModal()">设备统计</NText>
|
||||
<span class="metric-value">
|
||||
<span :style="{ color: onlineDeviceCount > 0 ? theme.successColor : '' }">{{ onlineDeviceCount }}</span>
|
||||
<NText depth="3" class="slash">/</NText>
|
||||
<span :style="{ color: offlineDeviceCount > 0 ? theme.errorColor : '' }">{{ offlineDeviceCount }}</span>
|
||||
<NText depth="3" class="slash">/</NText>
|
||||
<span>{{ deviceCount }}</span>
|
||||
<NText depth="3" class="unit">台</NText>
|
||||
</span>
|
||||
<NFlex vertical :size="6" class="metrics" :style="{ opacity: station.online ? '1' : '0.5' }">
|
||||
<NFlex vertical :size="4" class="metric-item">
|
||||
<NFlex justify="end" align="center" class="metric-line">
|
||||
<span class="font-small">{{ deviceCount }} 台设备</span>
|
||||
<NButton quaternary size="tiny" :focusable="false" @click="openOfflineDeviceTreeModal">
|
||||
<NIcon :component="EllipsisOutlined" />
|
||||
</NButton>
|
||||
</NFlex>
|
||||
|
||||
<NFlex justify="space-between" align="baseline" class="metric-item">
|
||||
<NText depth="3" class="metric-label" :class="[station.online ? 'clickable' : '']" @click="station.online && openDeviceAlarmTreeModal()">告警记录</NText>
|
||||
<span class="metric-value">
|
||||
<span>{{ alarmCount }}</span>
|
||||
<NText depth="3" class="unit">条</NText>
|
||||
<NFlex justify="end" align="center" class="metric-line">
|
||||
<span class="font-small">
|
||||
<span :style="{ color: onlineDeviceCount > 0 ? theme.successColor : '' }">在线 {{ onlineDeviceCount }} 台</span>
|
||||
<NText depth="3" class="sep">·</NText>
|
||||
<span :style="{ color: offlineDeviceCount > 0 ? theme.errorColor : '' }">离线 {{ offlineDeviceCount }} 台</span>
|
||||
</span>
|
||||
<NButton quaternary size="tiny" :focusable="false" style="visibility: hidden">
|
||||
<NIcon :component="EllipsisOutlined" />
|
||||
</NButton>
|
||||
</NFlex>
|
||||
</NFlex>
|
||||
</NSpace>
|
||||
|
||||
<NFlex justify="end" align="center" class="metric-item">
|
||||
<NFlex align="center" :size="8">
|
||||
<span class="font-small" :style="{ color: alarmCount > 0 ? theme.warningColor : '' }">今日 {{ alarmCount }} 条告警</span>
|
||||
<NButton quaternary size="tiny" :focusable="false" @click="openDeviceAlarmTreeModal">
|
||||
<NIcon :component="EllipsisOutlined" />
|
||||
</NButton>
|
||||
</NFlex>
|
||||
</NFlex>
|
||||
</NFlex>
|
||||
</template>
|
||||
</NCard>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.clickable {
|
||||
text-decoration: underline dashed;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
color: v-bind('theme.iconColorHover');
|
||||
}
|
||||
.font-medium {
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
.font-smaller {
|
||||
font-size: smaller;
|
||||
.font-small {
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
margin-left: 6px;
|
||||
.metrics {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.sep {
|
||||
margin: 0 6px;
|
||||
font-size: xx-small;
|
||||
color: v-bind('theme.textColor3');
|
||||
}
|
||||
|
||||
.metric-label {
|
||||
font-size: xx-small;
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.unit,
|
||||
.slash {
|
||||
margin-left: 4px;
|
||||
font-size: xx-small;
|
||||
.metric-line .font-small {
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -68,7 +68,7 @@ const selectedTab = ref('设备状态');
|
||||
<NTabs v-model:value="selectedTab" size="small">
|
||||
<NTabPane name="设备状态" tab="设备状态">
|
||||
<NFlex vertical>
|
||||
<DeviceHeaderCard :device="ndmCamera" />
|
||||
<DeviceHeaderCard :station-code="stationCode" :device="ndmCamera" />
|
||||
<DeviceCommonCard :common-info="commonInfo" />
|
||||
</NFlex>
|
||||
</NTabPane>
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import type { NdmDeviceResultVO } from '@/apis/models';
|
||||
import { getDeviceDetailApi, probeDeviceApi } from '@/apis/requests';
|
||||
import { DeviceType, DeviceTypeName, tryGetDeviceTypeVal, type DeviceTypeVal } from '@/enums/device-type';
|
||||
import { NButton, NCard, NFlex, NTag } from 'naive-ui';
|
||||
import { useLineDevicesStore } from '@/stores/line-devices';
|
||||
import { useMutation } from '@tanstack/vue-query';
|
||||
import { ApiOutlined, ReloadOutlined } from '@vicons/antd';
|
||||
import { NButton, NCard, NFlex, NIcon, NTag, NTooltip } from 'naive-ui';
|
||||
import { computed, toRefs } from 'vue';
|
||||
|
||||
const props = defineProps<{
|
||||
stationCode: string;
|
||||
device: NdmDeviceResultVO;
|
||||
}>();
|
||||
|
||||
// const emit = defineEmits<{}>();
|
||||
|
||||
const { device } = toRefs(props);
|
||||
const { stationCode, device } = toRefs(props);
|
||||
|
||||
const type = computed(() => {
|
||||
const deviceTypeVal = tryGetDeviceTypeVal(device.value.deviceType);
|
||||
@@ -39,6 +44,34 @@ const onClickOpenMgmtPage = () => {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const canProbe = computed(() => device.value.snmpEnabled);
|
||||
|
||||
const { mutate: probeDevice, isPending: probing } = useMutation({
|
||||
mutationFn: async () => {
|
||||
await probeDeviceApi(stationCode.value, device.value);
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
window.$message.error(error.message);
|
||||
},
|
||||
});
|
||||
|
||||
const { mutate: getDeviceDetail, isPending: loading } = useMutation({
|
||||
mutationFn: async () => {
|
||||
const { id, deviceType } = device.value;
|
||||
return await getDeviceDetailApi(stationCode.value, id, tryGetDeviceTypeVal(deviceType));
|
||||
},
|
||||
onSuccess: (device) => {
|
||||
if (device) {
|
||||
useLineDevicesStore().patch(stationCode.value, device);
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
window.$message.error(error.message);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -51,6 +84,8 @@ const onClickOpenMgmtPage = () => {
|
||||
<div>{{ name }}</div>
|
||||
<NButton v-if="canOpenMgmtPage" ghost size="tiny" type="default" :focusable="false" @click="onClickOpenMgmtPage">管理</NButton>
|
||||
</NFlex>
|
||||
</template>
|
||||
<template #default>
|
||||
<div style="font-size: small; color: #666">
|
||||
<div>
|
||||
<span>设备类型:</span>
|
||||
@@ -74,6 +109,32 @@ const onClickOpenMgmtPage = () => {
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #header-extra>
|
||||
<NTooltip v-if="canProbe" trigger="hover">
|
||||
<template #trigger>
|
||||
<NButton size="small" quaternary circle :loading="probing" @click="() => probeDevice()">
|
||||
<template #icon>
|
||||
<NIcon :component="ApiOutlined" />
|
||||
</template>
|
||||
</NButton>
|
||||
</template>
|
||||
<template #default>
|
||||
<span>获取最新诊断</span>
|
||||
</template>
|
||||
</NTooltip>
|
||||
<NTooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<NButton size="small" quaternary circle :loading="loading" @click="() => getDeviceDetail()">
|
||||
<template #icon>
|
||||
<NIcon :component="ReloadOutlined" />
|
||||
</template>
|
||||
</NButton>
|
||||
</template>
|
||||
<template #default>
|
||||
<span>刷新设备</span>
|
||||
</template>
|
||||
</NTooltip>
|
||||
</template>
|
||||
</NCard>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import type { NdmSecurityBoxCircuit } from '@/apis/domains';
|
||||
import type { NdmSecurityBoxResultVO } from '@/apis/models';
|
||||
import { rebootSecurityBox, turnStatus } from '@/apis/requests';
|
||||
import { probeDeviceApi, rebootSecurityBox as rebootSecurityBoxApi, turnStatus as turnStatusApi } from '@/apis/requests';
|
||||
import { useMutation } from '@tanstack/vue-query';
|
||||
import { PowerOutline, FlashOutline } from '@vicons/ionicons5';
|
||||
import { NCard, NGrid, NGridItem, NPopover, NSwitch, NIcon, NFlex, NPopconfirm, NButton } from 'naive-ui';
|
||||
import { computed, toRefs } from 'vue';
|
||||
import { ref, toRefs, watch } from 'vue';
|
||||
|
||||
/**
|
||||
* 安防箱电路状态卡片组件
|
||||
@@ -24,18 +25,18 @@ const props = defineProps<{
|
||||
|
||||
const { stationCode, ndmSecurityBox, circuits } = toRefs(props);
|
||||
|
||||
const validCircuits = computed(() => {
|
||||
if (!circuits.value || circuits.value.length === 0) {
|
||||
return [];
|
||||
}
|
||||
return circuits.value;
|
||||
});
|
||||
const localCircuits = ref<NdmSecurityBoxCircuit[]>([]);
|
||||
|
||||
watch(
|
||||
circuits,
|
||||
(newValue) => {
|
||||
localCircuits.value = newValue?.map((circuit) => ({ ...circuit })) ?? [];
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* 获取电路状态样式类
|
||||
* @param circuit 电路信息
|
||||
* @returns CSS类名
|
||||
*/
|
||||
const getCircuitStatusClass = (circuit: NdmSecurityBoxCircuit) => {
|
||||
if (circuit.status === 1) {
|
||||
return 'circuit-on';
|
||||
@@ -44,12 +45,6 @@ const getCircuitStatusClass = (circuit: NdmSecurityBoxCircuit) => {
|
||||
}
|
||||
return 'circuit-unknown';
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取电路状态文本
|
||||
* @param circuit 电路信息
|
||||
* @returns 状态文本
|
||||
*/
|
||||
const getCircuitStatusText = (circuit: NdmSecurityBoxCircuit) => {
|
||||
if (circuit.status === 1) {
|
||||
return '开启';
|
||||
@@ -59,58 +54,65 @@ const getCircuitStatusText = (circuit: NdmSecurityBoxCircuit) => {
|
||||
return '未知';
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理电路开关切换
|
||||
* @param circuitIndex 电路索引
|
||||
* @param newStatus 新状态
|
||||
*/
|
||||
const handleCircuitToggle = async (circuitIndex: number, newStatus: boolean) => {
|
||||
if (!ndmSecurityBox.value.ipAddress) {
|
||||
window.$message.error('设备IP地址不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { mutate: turnStatus, isPending: turning } = useMutation({
|
||||
mutationFn: async (params: { circuitIndex: number; newStatus: boolean }) => {
|
||||
const { circuitIndex, newStatus } = params;
|
||||
if (!ndmSecurityBox.value.ipAddress) {
|
||||
throw new Error('设备IP地址不存在');
|
||||
}
|
||||
const status = newStatus ? 1 : 0;
|
||||
await turnStatus(stationCode.value, ndmSecurityBox.value.ipAddress, circuitIndex, status);
|
||||
window.$message.success(`电路${circuitIndex + 1}${newStatus ? '开启' : '关闭'}成功 下次更新诊断数据时将刷新状态`);
|
||||
} catch (error) {
|
||||
window.$message.error(`电路${circuitIndex + 1}操作失败`);
|
||||
console.error('电路开关操作失败:', error);
|
||||
}
|
||||
};
|
||||
await turnStatusApi(stationCode.value, ndmSecurityBox.value.ipAddress, circuitIndex, status);
|
||||
await probeDeviceApi(stationCode.value, ndmSecurityBox.value);
|
||||
return status;
|
||||
},
|
||||
onSuccess: (status, params) => {
|
||||
if (localCircuits.value) {
|
||||
const circuit = localCircuits.value.at(params.circuitIndex);
|
||||
if (circuit) {
|
||||
circuit.status = status;
|
||||
localCircuits.value.splice(params.circuitIndex, 1, circuit);
|
||||
}
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
window.$message.error(error.message);
|
||||
},
|
||||
});
|
||||
|
||||
const onClickReboot = async () => {
|
||||
if (!ndmSecurityBox.value.ipAddress) {
|
||||
window.$message.error('设备IP地址不存在');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await rebootSecurityBox(stationCode.value, ndmSecurityBox.value.ipAddress);
|
||||
const { mutate: rebootSecurityBox, isPending: rebooting } = useMutation({
|
||||
mutationFn: async () => {
|
||||
if (!ndmSecurityBox.value.ipAddress) {
|
||||
throw new Error('设备IP地址不存在');
|
||||
}
|
||||
await rebootSecurityBoxApi(stationCode.value, ndmSecurityBox.value.ipAddress);
|
||||
},
|
||||
onSuccess: () => {
|
||||
window.$message.success('设备重启成功');
|
||||
} catch (error) {
|
||||
window.$message.error('设备重启失败');
|
||||
console.error('设备重启失败:', error);
|
||||
}
|
||||
};
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
window.$message.error(error.message);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NCard v-if="validCircuits.length > 0" size="small" hoverable>
|
||||
<NCard v-if="localCircuits.length > 0" size="small" hoverable>
|
||||
<template #header>
|
||||
<NFlex :align="'center'">
|
||||
<div>电路状态</div>
|
||||
<NPopconfirm :positive-text="'确认'" :negative-text="'取消'" @positive-click="onClickReboot">
|
||||
<NPopconfirm :positive-text="'确认'" :negative-text="'取消'" @positive-click="() => rebootSecurityBox()">
|
||||
<template #trigger>
|
||||
<NButton secondary size="small">重合闸</NButton>
|
||||
<NButton secondary size="small" :loading="rebooting">重合闸</NButton>
|
||||
</template>
|
||||
确定要执行重合闸操作吗?此操作将重启安防箱设备。
|
||||
</NPopconfirm>
|
||||
</NFlex>
|
||||
</template>
|
||||
<div class="circuit-layout">
|
||||
<NGrid :cols="Math.min(validCircuits.length, 4)" :x-gap="12" :y-gap="12" class="circuit-grid">
|
||||
<NGridItem v-for="(circuit, index) in validCircuits" :key="index">
|
||||
<NGrid :cols="Math.min(localCircuits.length, 4)" :x-gap="12" :y-gap="12" class="circuit-grid">
|
||||
<NGridItem v-for="(circuit, index) in localCircuits" :key="index">
|
||||
<!-- 电路信息弹窗 -->
|
||||
<NPopover trigger="hover" placement="top">
|
||||
<template #trigger>
|
||||
@@ -126,9 +128,9 @@ const onClickReboot = async () => {
|
||||
<span class="status-text">{{ getCircuitStatusText(circuit) }}</span>
|
||||
</div>
|
||||
<div class="circuit-control">
|
||||
<NPopconfirm :positive-text="'确认'" :negative-text="'取消'" @positive-click="() => handleCircuitToggle(index, circuit.status !== 1)">
|
||||
<NPopconfirm :positive-text="'确认'" :negative-text="'取消'" @positive-click="() => turnStatus({ circuitIndex: index, newStatus: circuit.status !== 1 })">
|
||||
<template #trigger>
|
||||
<NSwitch :value="circuit.status === 1" size="small" />
|
||||
<NSwitch :value="circuit.status === 1" size="small" :loading="turning" />
|
||||
</template>
|
||||
确定要{{ circuit.status === 1 ? '关闭' : '开启' }}电路{{ index + 1 }}吗?
|
||||
</NPopconfirm>
|
||||
|
||||
@@ -48,7 +48,7 @@ const selectedTab = ref('设备状态');
|
||||
<NTabs v-model:value="selectedTab" size="small">
|
||||
<NTabPane name="设备状态" tab="设备状态">
|
||||
<NFlex vertical>
|
||||
<DeviceHeaderCard :device="ndmDecoder" />
|
||||
<DeviceHeaderCard :station-code="stationCode" :device="ndmDecoder" />
|
||||
<DeviceCommonCard :common-info="commonInfo" />
|
||||
<DeviceHardwareCard :cpu-usage="cpuUsage" :mem-usage="memUsage" />
|
||||
</NFlex>
|
||||
|
||||
@@ -24,7 +24,7 @@ const selectedTab = ref('设备状态');
|
||||
<NTabs v-model:value="selectedTab" size="small">
|
||||
<NTabPane name="设备状态" tab="设备状态">
|
||||
<NFlex vertical>
|
||||
<DeviceHeaderCard :device="ndmKeyboard" />
|
||||
<DeviceHeaderCard :station-code="stationCode" :device="ndmKeyboard" />
|
||||
</NFlex>
|
||||
</NTabPane>
|
||||
<NTabPane name="历史诊断" tab="历史诊断">
|
||||
|
||||
@@ -58,7 +58,7 @@ const selectedTab = ref('设备状态');
|
||||
<NTabs v-model:value="selectedTab" size="small">
|
||||
<NTabPane name="设备状态" tab="设备状态">
|
||||
<NFlex vertical>
|
||||
<DeviceHeaderCard :device="ndmNvr" />
|
||||
<DeviceHeaderCard :station-code="stationCode" :device="ndmNvr" />
|
||||
<DeviceCommonCard :common-info="commonInfo" />
|
||||
<DeviceHardwareCard :cpu-usage="cpuUsage" :mem-usage="memUsage" />
|
||||
<NvrDiskCard :disk-health="diskHealth" :group-info-list="groupInfoList" />
|
||||
|
||||
@@ -57,7 +57,7 @@ const selectedTab = ref('设备状态');
|
||||
<NTabs v-model:value="selectedTab" size="small">
|
||||
<NTabPane name="设备状态" tab="设备状态">
|
||||
<NFlex vertical>
|
||||
<DeviceHeaderCard :device="ndmSecurityBox" />
|
||||
<DeviceHeaderCard :station-code="stationCode" :device="ndmSecurityBox" />
|
||||
<DeviceCommonCard :common-info="commonInfo" />
|
||||
<DeviceHardwareCard :cpu-usage="cpuUsage" :mem-usage="memUsage" />
|
||||
<SecurityBoxInfoCard :fan-speeds="fanSpeeds" :temperature="temperature" :humidity="humidity" :switches="switches" />
|
||||
|
||||
@@ -39,7 +39,7 @@ const selectedTab = ref('设备状态');
|
||||
<NTabs v-model:value="selectedTab" size="small">
|
||||
<NTabPane name="设备状态">
|
||||
<NFlex vertical>
|
||||
<DeviceHeaderCard :device="ndmServer" />
|
||||
<DeviceHeaderCard :station-code="stationCode" :device="ndmServer" />
|
||||
<DeviceHardwareCard :cpu-usage="cpuUsage" :mem-usage="memUsage" :disk-usage="diskUsage" :running-time="runningTime" />
|
||||
</NFlex>
|
||||
</NTabPane>
|
||||
|
||||
@@ -40,7 +40,7 @@ const selectedTab = ref('设备状态');
|
||||
<NTabs v-model:value="selectedTab" size="small">
|
||||
<NTabPane name="设备状态">
|
||||
<NFlex vertical>
|
||||
<DeviceHeaderCard :device="ndmSwitch" />
|
||||
<DeviceHeaderCard :station-code="stationCode" :device="ndmSwitch" />
|
||||
<DeviceHardwareCard :cpu-usage="cpuUsage" :mem-usage="memUsage" />
|
||||
<SwitchPortCard :port-info-list="portInfoList" />
|
||||
</NFlex>
|
||||
|
||||
@@ -20,7 +20,7 @@ const route = useRoute();
|
||||
const show = defineModel<boolean>('show');
|
||||
|
||||
const layoutStore = useLayoutStore();
|
||||
const { stationLayoutGridCols } = storeToRefs(layoutStore);
|
||||
const { stationGridColumns } = storeToRefs(layoutStore);
|
||||
const queryControlStore = useQueryControlStore();
|
||||
const { stationVerifyMode } = storeToRefs(queryControlStore);
|
||||
|
||||
@@ -73,10 +73,10 @@ useEventListener('keydown', (event) => {
|
||||
<NFormItem label="深色模式" label-placement="left">
|
||||
<ThemeSwitch />
|
||||
</NFormItem>
|
||||
<template v-if="route.path === '/dashboard'">
|
||||
<template v-if="route.path === '/station'">
|
||||
<NDivider>布局</NDivider>
|
||||
<NFormItem label="车站列数" label-placement="left">
|
||||
<NInputNumber v-model:value="stationLayoutGridCols" :min="1" :max="10" />
|
||||
<NInputNumber v-model:value="stationGridColumns" :min="1" :max="10" />
|
||||
</NFormItem>
|
||||
</template>
|
||||
<template v-if="debugEnabled">
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import type { VersionInfo } from '@/apis/domains/version-info';
|
||||
import { useQuery } from '@tanstack/vue-query';
|
||||
import axios from 'axios';
|
||||
import { useThemeVars } from 'naive-ui';
|
||||
import { h, ref, watch } from 'vue';
|
||||
|
||||
export function useVersionCheckQuery() {
|
||||
const localVersionInfo = ref<VersionInfo>();
|
||||
const dialogShow = ref<boolean>(false);
|
||||
const themeVars = useThemeVars();
|
||||
|
||||
const { data: remoteVersionInfo, dataUpdatedAt } = useQuery({
|
||||
queryKey: ['version-check'],
|
||||
@@ -25,7 +27,10 @@ export function useVersionCheckQuery() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (localVersionInfo.value.version !== newVersionInfo.version && !dialogShow.value) {
|
||||
const { version: localVersion, buildTime: localBuildTime } = localVersionInfo.value;
|
||||
const { version: remoteVersion, buildTime: remoteBuildTime } = newVersionInfo;
|
||||
|
||||
if ((localVersion !== remoteVersion || localBuildTime !== remoteBuildTime) && !dialogShow.value) {
|
||||
dialogShow.value = true;
|
||||
window.$dialog.info({
|
||||
title: '发现新版本',
|
||||
@@ -34,6 +39,7 @@ export function useVersionCheckQuery() {
|
||||
h('div', {}, { default: () => `当前版本:${localVersionInfo.value?.version}` }),
|
||||
h('div', {}, { default: () => `最新版本:${newVersionInfo.version}` }),
|
||||
h('div', {}, { default: () => '请点击刷新页面以更新' }),
|
||||
h('div', { style: { marginTop: '8px', fontWeight: '700', color: themeVars.value.warningColor } }, { default: () => '⚠️ 注意,更新后可能需要重新登录!' }),
|
||||
]),
|
||||
positiveText: '刷新页面',
|
||||
maskClosable: false,
|
||||
|
||||
@@ -15,8 +15,7 @@ import { useCurrentAlarmsStore } from '@/stores/current-alarms';
|
||||
import { useUserStore } from '@/stores/user';
|
||||
import { Client as StompClient } from '@stomp/stompjs';
|
||||
import { useIsFetching } from '@tanstack/vue-query';
|
||||
import { AlertFilled, /* AreaChartOutlined, */ FileTextFilled, HomeFilled, LogoutOutlined, SettingOutlined, VideoCameraFilled } from '@vicons/antd';
|
||||
import { ChevronDown, Debug } from '@vicons/carbon';
|
||||
import { AlertFilled, BugFilled, CaretDownFilled, EnvironmentFilled, /* AreaChartOutlined, */ FileTextFilled, FundFilled, HddFilled, LogoutOutlined, SettingOutlined } from '@vicons/antd';
|
||||
import type { AxiosError } from 'axios';
|
||||
import { destr } from 'destr';
|
||||
import { NBadge, NButton, NDropdown, NFlex, NIcon, NLayout, NLayoutContent, NLayoutFooter, NLayoutHeader, NLayoutSider, NMenu, NScrollbar, type DropdownOption, type MenuOption } from 'naive-ui';
|
||||
@@ -98,17 +97,22 @@ const router = useRouter();
|
||||
|
||||
const menuOptions = ref<MenuOption[]>([
|
||||
{
|
||||
label: () => h(RouterLink, { to: '/dashboard' }, { default: () => '今日数据看板' }),
|
||||
label: () => h(RouterLink, { to: '/dashboard' }, { default: () => '全线总概览' }),
|
||||
key: '/dashboard',
|
||||
icon: renderIcon(HomeFilled),
|
||||
icon: renderIcon(FundFilled),
|
||||
},
|
||||
{
|
||||
label: () => h(RouterLink, { to: '/device' }, { default: () => '设备诊断数据' }),
|
||||
label: () => h(RouterLink, { to: '/station' }, { default: () => '车站状态' }),
|
||||
key: '/station',
|
||||
icon: renderIcon(EnvironmentFilled),
|
||||
},
|
||||
{
|
||||
label: () => h(RouterLink, { to: '/device' }, { default: () => '设备诊断' }),
|
||||
key: '/device',
|
||||
icon: renderIcon(VideoCameraFilled),
|
||||
icon: renderIcon(HddFilled),
|
||||
},
|
||||
{
|
||||
label: () => h(RouterLink, { to: '/alarm' }, { default: () => '设备告警记录' }),
|
||||
label: () => h(RouterLink, { to: '/alarm' }, { default: () => '设备告警' }),
|
||||
key: '/alarm',
|
||||
icon: renderIcon(AlertFilled),
|
||||
},
|
||||
@@ -118,20 +122,24 @@ const menuOptions = ref<MenuOption[]>([
|
||||
// icon: renderIcon(AreaChartOutlined),
|
||||
// },
|
||||
{
|
||||
label: () => h(RouterLink, { to: '/log/vimp-log' }, { default: () => '视频平台日志' }), // '系统日志记录'
|
||||
key: '/log/vimp-log',
|
||||
label: '系统日志',
|
||||
key: '/log',
|
||||
icon: renderIcon(FileTextFilled),
|
||||
// children: [
|
||||
// {
|
||||
// label: () => h(RouterLink, { to: '/log/vimp-log' }, { default: () => '视频平台日志' }),
|
||||
// key: '/log/vimp-log',
|
||||
// },
|
||||
// ],
|
||||
children: [
|
||||
{
|
||||
label: () => h(RouterLink, { to: '/log/vimp-log' }, { default: () => '视频平台日志' }),
|
||||
key: '/log/vimp-log',
|
||||
},
|
||||
{
|
||||
label: () => h(RouterLink, { to: '/log/call-log' }, { default: () => '上级调用日志' }),
|
||||
key: '/log/call-log',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: () => h(RouterLink, { to: '/debug' }, { default: () => '调试' }),
|
||||
key: '/debug',
|
||||
icon: renderIcon(Debug),
|
||||
icon: renderIcon(BugFilled),
|
||||
show: import.meta.env.DEV,
|
||||
},
|
||||
]);
|
||||
@@ -195,15 +203,13 @@ const openSettingsDrawer = () => {
|
||||
<span>{{ userInfo?.nickName ?? '' }}</span>
|
||||
</template>
|
||||
<template #icon>
|
||||
<NIcon :component="ChevronDown" />
|
||||
<NIcon :component="CaretDownFilled" />
|
||||
</template>
|
||||
</NButton>
|
||||
</NDropdown>
|
||||
<NButton :focusable="false" quaternary @click="openSettingsDrawer" style="height: 100%">
|
||||
<template #icon>
|
||||
<NIcon>
|
||||
<SettingOutlined />
|
||||
</NIcon>
|
||||
<NIcon :component="SettingOutlined" />
|
||||
</template>
|
||||
</NButton>
|
||||
</NFlex>
|
||||
@@ -217,9 +223,7 @@ const openSettingsDrawer = () => {
|
||||
<NBadge :value="currentAlarmCount">
|
||||
<NButton secondary strong @click="toAlarmPage">
|
||||
<template #icon>
|
||||
<NIcon>
|
||||
<AlertFilled />
|
||||
</NIcon>
|
||||
<NIcon :component="AlertFilled" />
|
||||
</template>
|
||||
</NButton>
|
||||
</NBadge>
|
||||
|
||||
10
src/main.ts
10
src/main.ts
@@ -1,13 +1,21 @@
|
||||
import { getAppEnvConfig } from '@/utils/env';
|
||||
import { VueQueryPlugin } from '@tanstack/vue-query';
|
||||
import { createApp } from 'vue';
|
||||
import { createPinia } from 'pinia';
|
||||
import persist from 'pinia-plugin-persistedstate';
|
||||
import { VueQueryPlugin } from '@tanstack/vue-query';
|
||||
|
||||
import App from './App.vue';
|
||||
import router from './router';
|
||||
|
||||
import '@/styles/reset.scss';
|
||||
|
||||
const { storageVersion } = getAppEnvConfig();
|
||||
const localStorageVersion = window.localStorage.getItem('ndm-storage-version');
|
||||
if (localStorageVersion !== storageVersion) {
|
||||
window.localStorage.clear();
|
||||
window.localStorage.setItem('ndm-storage-version', storageVersion);
|
||||
}
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
app.use(createPinia().use(persist));
|
||||
|
||||
256
src/pages/call-log-page.vue
Normal file
256
src/pages/call-log-page.vue
Normal file
@@ -0,0 +1,256 @@
|
||||
<script setup lang="ts">
|
||||
import type { NdmCallLogResultVO, NdmCallLogVO, PageQueryExtra } from '@/apis/models';
|
||||
import { ndmCallLogDefaultExportByTemplate, postNdmCallLogPage } from '@/apis/requests';
|
||||
import { useStationStore } from '@/stores/station';
|
||||
import { downloadByData } from '@/utils/download';
|
||||
import { useMutation } from '@tanstack/vue-query';
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
NButton,
|
||||
NDataTable,
|
||||
NDatePicker,
|
||||
NForm,
|
||||
NFormItemGi,
|
||||
NGrid,
|
||||
NGridItem,
|
||||
NInput,
|
||||
NSelect,
|
||||
NSpace,
|
||||
NTag,
|
||||
type DataTableColumns,
|
||||
type DataTableRowData,
|
||||
type PaginationProps,
|
||||
type SelectOption,
|
||||
} from 'naive-ui';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { computed, h, reactive, ref, watch, watchEffect } from 'vue';
|
||||
|
||||
const stationStore = useStationStore();
|
||||
const { stationList, onlineStationList } = storeToRefs(stationStore);
|
||||
|
||||
const stationSelectOptions = computed(() => {
|
||||
return stationList.value.map<SelectOption>((station) => ({
|
||||
label: station.name,
|
||||
value: station.code,
|
||||
disabled: !station.online,
|
||||
}));
|
||||
});
|
||||
|
||||
type SearchFields = PageQueryExtra<NdmCallLogVO> & { stationCode?: string; createdTime: [string, string] };
|
||||
|
||||
const searchFields = reactive<SearchFields>({
|
||||
stationCode: undefined as string | undefined,
|
||||
sourceGbId_like: undefined,
|
||||
targetGbId_like: undefined,
|
||||
method_like: undefined,
|
||||
messageType_like: undefined,
|
||||
cmdType_like: undefined,
|
||||
createdTime: [dayjs().startOf('date').subtract(1, 'week').format('YYYY-MM-DD HH:mm:ss'), dayjs().endOf('date').format('YYYY-MM-DD HH:mm:ss')] as [string, string],
|
||||
});
|
||||
const resetSearchFields = () => {
|
||||
searchFields.stationCode = stationList.value.find((station) => station.online)?.code;
|
||||
searchFields.sourceGbId_like = undefined;
|
||||
searchFields.targetGbId_like = undefined;
|
||||
searchFields.method_like = undefined;
|
||||
searchFields.messageType_like = undefined;
|
||||
searchFields.cmdType_like = undefined;
|
||||
searchFields.createdTime = [dayjs().startOf('date').subtract(1, 'week').format('YYYY-MM-DD HH:mm:ss'), dayjs().endOf('date').format('YYYY-MM-DD HH:mm:ss')];
|
||||
};
|
||||
const getExtraFields = () => {
|
||||
const createdTime_precisest = searchFields.createdTime[0];
|
||||
const createdTime_preciseed = searchFields.createdTime[1];
|
||||
const sourceGbId_like = searchFields.sourceGbId_like;
|
||||
const targetGbId_like = searchFields.targetGbId_like;
|
||||
const method_like = searchFields.method_like;
|
||||
const messageType_like = searchFields.messageType_like;
|
||||
const cmdType_like = searchFields.cmdType_like;
|
||||
return {
|
||||
createdTime_precisest,
|
||||
createdTime_preciseed,
|
||||
sourceGbId_like,
|
||||
targetGbId_like,
|
||||
method_like,
|
||||
messageType_like,
|
||||
cmdType_like,
|
||||
};
|
||||
};
|
||||
|
||||
const searchFieldsChanged = ref(false);
|
||||
watch(searchFields, () => {
|
||||
searchFieldsChanged.value = true;
|
||||
});
|
||||
|
||||
const tableColumns: DataTableColumns<NdmCallLogResultVO> = [
|
||||
{ title: '时间', key: 'createdTime' },
|
||||
{ title: '调用者国标码', key: 'sourceGbId' },
|
||||
{ title: '被调用设备国标码', key: 'targetGbId' },
|
||||
{ title: '调用方法', key: 'method' },
|
||||
{ title: '消息类型', key: 'messageType' },
|
||||
{ title: '操作类型', key: 'cmdType' },
|
||||
];
|
||||
|
||||
const tableData = ref<DataTableRowData[]>([]);
|
||||
|
||||
const tablePagination = reactive<PaginationProps>({
|
||||
showSizePicker: true,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
pageSizes: [5, 10, 20, 50, 80, 100],
|
||||
itemCount: 0,
|
||||
prefix: ({ itemCount }) => {
|
||||
return h('div', {}, { default: () => `共${itemCount}条` });
|
||||
},
|
||||
onUpdatePage: (page: number) => {
|
||||
tablePagination.page = page;
|
||||
getCallLogList();
|
||||
},
|
||||
onUpdatePageSize: (pageSize: number) => {
|
||||
tablePagination.pageSize = pageSize;
|
||||
tablePagination.page = 1;
|
||||
getCallLogList();
|
||||
},
|
||||
});
|
||||
|
||||
const { mutate: getCallLogList, isPending: tableLoading } = useMutation({
|
||||
mutationFn: async () => {
|
||||
if (!searchFields.stationCode) throw Error('请选择车站');
|
||||
const res = await postNdmCallLogPage(searchFields.stationCode, {
|
||||
model: {},
|
||||
extra: getExtraFields(),
|
||||
current: tablePagination.page ?? 1,
|
||||
size: tablePagination.pageSize ?? 10,
|
||||
order: 'descending',
|
||||
sort: 'id',
|
||||
});
|
||||
return res;
|
||||
},
|
||||
onSuccess: (res) => {
|
||||
const { records, size, total } = res;
|
||||
tablePagination.pageSize = parseInt(size);
|
||||
tablePagination.itemCount = parseInt(total);
|
||||
tableData.value = records;
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
window.$message.error(error.message);
|
||||
},
|
||||
});
|
||||
|
||||
const onClickReset = () => {
|
||||
resetSearchFields();
|
||||
tablePagination.page = 1;
|
||||
tablePagination.pageSize = 10;
|
||||
tablePagination.itemCount = 0;
|
||||
getCallLogList();
|
||||
};
|
||||
const onClickQuery = () => {
|
||||
if (searchFieldsChanged.value) {
|
||||
tablePagination.page = 1;
|
||||
tablePagination.pageSize = 10;
|
||||
searchFieldsChanged.value = false;
|
||||
}
|
||||
getCallLogList();
|
||||
};
|
||||
|
||||
const { mutate: exportTableData, isPending: exporting } = useMutation({
|
||||
mutationFn: async () => {
|
||||
if (!searchFields.stationCode) throw Error('请选择车站');
|
||||
const data = await ndmCallLogDefaultExportByTemplate(searchFields.stationCode, {
|
||||
model: {},
|
||||
extra: getExtraFields(),
|
||||
current: tablePagination.page ?? 1,
|
||||
size: tablePagination.pageSize ?? 10,
|
||||
order: 'descending',
|
||||
sort: 'id',
|
||||
});
|
||||
return data;
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
const time = dayjs().format('YYYY-MM-DD_HH-mm-ss');
|
||||
downloadByData(data, `上级调用日志_${time}.xlsx`);
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
window.$message.error(error.message);
|
||||
},
|
||||
});
|
||||
|
||||
const defaultStation = computed(() => onlineStationList.value.at(0));
|
||||
watchEffect(() => {
|
||||
if (defaultStation.value?.code && !searchFields.stationCode) {
|
||||
searchFields.stationCode = defaultStation.value.code;
|
||||
getCallLogList();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- 容器:上下布局,表格自适应剩余高度 -->
|
||||
<div style="height: 100%; display: flex; flex-direction: column">
|
||||
<!-- 查询面板 -->
|
||||
<div style="flex: 0 0 auto; padding: 8px">
|
||||
<NForm>
|
||||
<NGrid :cols="3" :x-gap="24">
|
||||
<NFormItemGi :span="1" label="车站" label-placement="left">
|
||||
<NSelect
|
||||
v-model:value="searchFields.stationCode"
|
||||
:options="stationSelectOptions"
|
||||
:render-label="
|
||||
(option: SelectOption) => {
|
||||
return [
|
||||
h(NTag, { type: option.disabled ? 'error' : 'success', size: 'tiny' }, { default: () => (option.disabled ? '离线' : '在线') }),
|
||||
h('span', {}, { default: () => `${option.label}` }),
|
||||
];
|
||||
}
|
||||
"
|
||||
:multiple="false"
|
||||
clearable
|
||||
/>
|
||||
</NFormItemGi>
|
||||
<NFormItemGi :span="1" label="调用者国标码" label-placement="left">
|
||||
<NInput v-model:value="searchFields.sourceGbId_like" placeholder="请输入调用者国标码" clearable />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi :span="1" label="被调用设备国标码" label-placement="left">
|
||||
<NInput v-model:value="searchFields.targetGbId_like" placeholder="请输入被调用设备国标码" clearable />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi :span="1" label="调用方法" label-placement="left">
|
||||
<NInput v-model:value="searchFields.method_like" placeholder="请输入调用方法" clearable />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi :span="1" label="消息类型" label-placement="left">
|
||||
<NInput v-model:value="searchFields.messageType_like" placeholder="请输入消息类型" clearable />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi :span="1" label="操作类型" label-placement="left">
|
||||
<NInput v-model:value="searchFields.cmdType_like" placeholder="请输入操作类型" clearable />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi :span="1" label="时间" label-placement="left">
|
||||
<NDatePicker v-model:formatted-value="searchFields.createdTime" type="datetimerange" @update:value="undefined" />
|
||||
</NFormItemGi>
|
||||
</NGrid>
|
||||
<!-- 按钮 -->
|
||||
<NGrid :cols="1">
|
||||
<NGridItem>
|
||||
<NSpace>
|
||||
<NButton @click="onClickReset">重置</NButton>
|
||||
<NButton type="primary" :loading="tableLoading" @click="onClickQuery">查询</NButton>
|
||||
</NSpace>
|
||||
</NGridItem>
|
||||
</NGrid>
|
||||
</NForm>
|
||||
</div>
|
||||
|
||||
<!-- 工具栏:横向、右对齐按钮) -->
|
||||
<div style="flex: 0 0 auto; display: flex; align-items: center; padding: 8px">
|
||||
<div style="font-size: medium">视频平台日志</div>
|
||||
<NSpace style="margin-left: auto">
|
||||
<NButton type="primary" :loading="exporting" @click="() => exportTableData()">导出</NButton>
|
||||
</NSpace>
|
||||
</div>
|
||||
|
||||
<!-- 表格区域:填满剩余空间 -->
|
||||
<div style="flex: 1 1 auto; min-height: 0; padding: 8px">
|
||||
<NDataTable remote :columns="tableColumns" :data="tableData" :pagination="tablePagination" :loading="tableLoading" :single-line="false" flex-height style="height: 100%" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
@@ -1,35 +1,23 @@
|
||||
<script setup lang="ts">
|
||||
import type { Station } from '@/apis/domains';
|
||||
import { ndmExportDevices } from '@/apis/requests';
|
||||
import { useLineAlarmsQuery, useLineDevicesQuery } from '@/composables/query';
|
||||
import { useLayoutStore } from '@/stores/layout';
|
||||
import { useLineAlarmsStore } from '@/stores/line-alarms';
|
||||
import { useLineDevicesStore } from '@/stores/line-devices';
|
||||
import { useStationStore } from '@/stores/station';
|
||||
import { downloadByData } from '@/utils/download';
|
||||
import { useMutation } from '@tanstack/vue-query';
|
||||
import { NGrid, NGi } from 'naive-ui';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ref, watch } from 'vue';
|
||||
import { watch } from 'vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import DeviceAlarmDetailModal from '@/components/dashboard-page/device-alarm-detail-modal.vue';
|
||||
import DeviceParamsConfigModal from '@/components/dashboard-page/device-params-config-modal.vue';
|
||||
import DeviceStatisticCard from '@/components/dashboard-page/device-statistic-card.vue';
|
||||
import OfflineDeviceDetailModal from '@/components/dashboard-page/offline-device-detail-modal.vue';
|
||||
import StationCard from '@/components/dashboard-page/station-card.vue';
|
||||
|
||||
const stationStore = useStationStore();
|
||||
const { stationList } = storeToRefs(stationStore);
|
||||
const lineDevicesStore = useLineDevicesStore();
|
||||
const { lineDevices } = storeToRefs(lineDevicesStore);
|
||||
const lineAlarmsStore = useLineAlarmsStore();
|
||||
const { lineAlarmCounts } = storeToRefs(lineAlarmsStore);
|
||||
|
||||
const { error: lineDevicesQueryError } = useLineDevicesQuery();
|
||||
const { error: lineAlarmsQueryError } = useLineAlarmsQuery();
|
||||
const layoutStore = useLayoutStore();
|
||||
const { stationLayoutGridCols } = storeToRefs(layoutStore);
|
||||
|
||||
watch([lineDevicesQueryError, lineAlarmsQueryError], ([newLineDevicesQueryError, newLineAlarmsQueryError]) => {
|
||||
if (newLineDevicesQueryError) {
|
||||
@@ -61,23 +49,6 @@ const { mutate: exportDevices, isPending: exporting } = useMutation({
|
||||
window.$message.error(error.message);
|
||||
},
|
||||
});
|
||||
|
||||
const selectedStation = ref<Station>();
|
||||
const offlineDeviceTreeModalShow = ref(false);
|
||||
const deviceAlarmTreeModalShow = ref(false);
|
||||
const deviceParamsConfigModalShow = ref(false);
|
||||
const openOfflineDeviceDetailModal = (station: Station) => {
|
||||
selectedStation.value = station;
|
||||
offlineDeviceTreeModalShow.value = true;
|
||||
};
|
||||
const openDeviceAlarmDetailModal = (station: Station) => {
|
||||
selectedStation.value = station;
|
||||
deviceAlarmTreeModalShow.value = true;
|
||||
};
|
||||
const openDeviceParamsConfigModal = (station: Station) => {
|
||||
selectedStation.value = station;
|
||||
deviceParamsConfigModalShow.value = true;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -89,26 +60,6 @@ const openDeviceParamsConfigModal = (station: Station) => {
|
||||
@export-online="() => exportDevices({ status: '10' })"
|
||||
@export-offline="() => exportDevices({ status: '20' })"
|
||||
/>
|
||||
|
||||
<NGrid :cols="stationLayoutGridCols" :x-gap="6" :y-gap="6" style="padding: 8px">
|
||||
<NGi v-for="station in stationList" :key="station.code">
|
||||
<StationCard
|
||||
:station="station"
|
||||
:station-devices="lineDevices[station.code]"
|
||||
:station-alarm-counts="lineAlarmCounts[station.code]"
|
||||
@open-offline-device-detail-modal="openOfflineDeviceDetailModal"
|
||||
@open-device-alarm-detail-modal="openDeviceAlarmDetailModal"
|
||||
@open-device-params-config-modal="openDeviceParamsConfigModal"
|
||||
/>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
|
||||
<!-- 离线设备详情对话框 -->
|
||||
<OfflineDeviceDetailModal v-model:show="offlineDeviceTreeModalShow" :station="selectedStation" :station-devices="selectedStation?.code ? lineDevices[selectedStation.code] : undefined" />
|
||||
<!-- 设备告警详情对话框 -->
|
||||
<DeviceAlarmDetailModal v-model:show="deviceAlarmTreeModalShow" :station="selectedStation" :station-alarm-counts="selectedStation?.code ? lineAlarmCounts[selectedStation.code] : undefined" />
|
||||
<!-- 设备配置面板对话框 -->
|
||||
<DeviceParamsConfigModal v-model:show="deviceParamsConfigModalShow" :station="selectedStation" />
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
78
src/pages/station-page.vue
Normal file
78
src/pages/station-page.vue
Normal file
@@ -0,0 +1,78 @@
|
||||
<script setup lang="ts">
|
||||
import type { Station } from '@/apis/domains';
|
||||
import { useLineAlarmsQuery, useLineDevicesQuery } from '@/composables/query';
|
||||
import { useLayoutStore } from '@/stores/layout';
|
||||
import { useLineAlarmsStore } from '@/stores/line-alarms';
|
||||
import { useLineDevicesStore } from '@/stores/line-devices';
|
||||
import { useStationStore } from '@/stores/station';
|
||||
import { NGrid, NGi } from 'naive-ui';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
import DeviceAlarmDetailModal from '@/components/dashboard-page/device-alarm-detail-modal.vue';
|
||||
import DeviceParamsConfigModal from '@/components/dashboard-page/device-params-config-modal.vue';
|
||||
import OfflineDeviceDetailModal from '@/components/dashboard-page/offline-device-detail-modal.vue';
|
||||
import StationCard from '@/components/dashboard-page/station-card.vue';
|
||||
|
||||
const stationStore = useStationStore();
|
||||
const { stationList } = storeToRefs(stationStore);
|
||||
const lineDevicesStore = useLineDevicesStore();
|
||||
const { lineDevices } = storeToRefs(lineDevicesStore);
|
||||
const lineAlarmsStore = useLineAlarmsStore();
|
||||
const { lineAlarmCounts } = storeToRefs(lineAlarmsStore);
|
||||
|
||||
const { error: lineDevicesQueryError } = useLineDevicesQuery();
|
||||
const { error: lineAlarmsQueryError } = useLineAlarmsQuery();
|
||||
const layoutStore = useLayoutStore();
|
||||
const { stationGridColumns } = storeToRefs(layoutStore);
|
||||
|
||||
watch([lineDevicesQueryError, lineAlarmsQueryError], ([newLineDevicesQueryError, newLineAlarmsQueryError]) => {
|
||||
if (newLineDevicesQueryError) {
|
||||
window.$message.error(newLineDevicesQueryError.message);
|
||||
}
|
||||
if (newLineAlarmsQueryError) {
|
||||
window.$message.error(newLineAlarmsQueryError.message);
|
||||
}
|
||||
});
|
||||
|
||||
const selectedStation = ref<Station>();
|
||||
const offlineDeviceTreeModalShow = ref(false);
|
||||
const deviceAlarmTreeModalShow = ref(false);
|
||||
const deviceParamsConfigModalShow = ref(false);
|
||||
const openOfflineDeviceDetailModal = (station: Station) => {
|
||||
selectedStation.value = station;
|
||||
offlineDeviceTreeModalShow.value = true;
|
||||
};
|
||||
const openDeviceAlarmDetailModal = (station: Station) => {
|
||||
selectedStation.value = station;
|
||||
deviceAlarmTreeModalShow.value = true;
|
||||
};
|
||||
const openDeviceParamsConfigModal = (station: Station) => {
|
||||
selectedStation.value = station;
|
||||
deviceParamsConfigModalShow.value = true;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NGrid :cols="stationGridColumns" :x-gap="6" :y-gap="6" style="padding: 8px">
|
||||
<NGi v-for="station in stationList" :key="station.code">
|
||||
<StationCard
|
||||
:station="station"
|
||||
:station-devices="lineDevices[station.code]"
|
||||
:station-alarm-counts="lineAlarmCounts[station.code]"
|
||||
@open-offline-device-detail-modal="openOfflineDeviceDetailModal"
|
||||
@open-device-alarm-detail-modal="openDeviceAlarmDetailModal"
|
||||
@open-device-params-config-modal="openDeviceParamsConfigModal"
|
||||
/>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
|
||||
<!-- 离线设备详情对话框 -->
|
||||
<OfflineDeviceDetailModal v-model:show="offlineDeviceTreeModalShow" :station="selectedStation" :station-devices="selectedStation?.code ? lineDevices[selectedStation.code] : undefined" />
|
||||
<!-- 设备告警详情对话框 -->
|
||||
<DeviceAlarmDetailModal v-model:show="deviceAlarmTreeModalShow" :station="selectedStation" :station-alarm-counts="selectedStation?.code ? lineAlarmCounts[selectedStation.code] : undefined" />
|
||||
<!-- 设备配置面板对话框 -->
|
||||
<DeviceParamsConfigModal v-model:show="deviceParamsConfigModalShow" :station="selectedStation" />
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
@@ -76,6 +76,7 @@ const searchFields = reactive({
|
||||
const resetSearchFields = () => {
|
||||
searchFields.stationCode = stationList.value.find((station) => station.online)?.code;
|
||||
searchFields.logType_in = [];
|
||||
searchFields.createdTime = [dayjs().startOf('date').subtract(1, 'week').format('YYYY-MM-DD HH:mm:ss'), dayjs().endOf('date').format('YYYY-MM-DD HH:mm:ss')];
|
||||
};
|
||||
const getExtraFields = () => {
|
||||
const logType_in = searchFields.logType_in.length > 0 ? [...searchFields.logType_in] : undefined;
|
||||
|
||||
@@ -17,6 +17,10 @@ const router = createRouter({
|
||||
path: 'dashboard',
|
||||
component: () => import('@/pages/dashboard-page.vue'),
|
||||
},
|
||||
{
|
||||
path: 'station',
|
||||
component: () => import('@/pages/station-page.vue'),
|
||||
},
|
||||
{
|
||||
path: 'device',
|
||||
component: () => import('@/pages/device-page.vue'),
|
||||
@@ -31,12 +35,15 @@ const router = createRouter({
|
||||
},
|
||||
{
|
||||
path: 'log',
|
||||
redirect: '/log/vimp-log',
|
||||
children: [
|
||||
{
|
||||
path: 'vimp-log',
|
||||
component: () => import('@/pages/vimp-log-page.vue'),
|
||||
},
|
||||
{
|
||||
path: 'call-log',
|
||||
component: () => import('@/pages/call-log-page.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -62,32 +69,30 @@ const router = createRouter({
|
||||
|
||||
const whiteList = ['/debug'];
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
router.beforeEach((to) => {
|
||||
const userStore = useUserStore();
|
||||
const isAuthed = !!userStore.userLoginResult?.token;
|
||||
|
||||
// 放行白名单
|
||||
const inWhiteList = whiteList.some((path) => to.path.startsWith(path));
|
||||
if (inWhiteList) {
|
||||
next();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 已登录用户不允许进入登录页(手动访问 /login 会重定向到首页)
|
||||
if (to.path === '/login') {
|
||||
if (isAuthed) {
|
||||
next({ path: '/' });
|
||||
return { path: '/' };
|
||||
} else {
|
||||
next();
|
||||
return true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 其它路由按登录态控制
|
||||
if (!isAuthed) {
|
||||
next('/login');
|
||||
} else {
|
||||
next();
|
||||
// 其它路由按登录态控制
|
||||
if (!isAuthed) {
|
||||
return { path: '/login' };
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ import { ref } from 'vue';
|
||||
export const useLayoutStore = defineStore(
|
||||
'ndm-layout-store',
|
||||
() => {
|
||||
const stationLayoutGridCols = ref(8);
|
||||
const stationGridColumns = ref(6);
|
||||
|
||||
return {
|
||||
stationLayoutGridCols,
|
||||
stationGridColumns,
|
||||
};
|
||||
},
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ export const getAppEnvConfig = () => {
|
||||
VITE_LAMP_PASSWORD,
|
||||
VITE_LAMP_AUTHORIZATION,
|
||||
VITE_DEBUG_CODE,
|
||||
VITE_STORAGE_VERSION,
|
||||
} = env;
|
||||
return {
|
||||
requestInterval: Number.parseInt(VITE_REQUEST_INTERVAL as string),
|
||||
@@ -20,5 +21,6 @@ export const getAppEnvConfig = () => {
|
||||
lampPassword: VITE_LAMP_PASSWORD as string,
|
||||
lampAuthorization: VITE_LAMP_AUTHORIZATION as string,
|
||||
debugCode: VITE_DEBUG_CODE as string,
|
||||
storageVersion: VITE_STORAGE_VERSION as string,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user