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 生成
|
# 如果 Authorization 已存在则会直接采用, 否则会根据 clientId 和 clientSecret 生成
|
||||||
VITE_LAMP_AUTHORIZATION = Y3VlZGVzX2FkbWluOmN1ZWRlc19hZG1pbl9zZWNyZXQ=
|
VITE_LAMP_AUTHORIZATION = Y3VlZGVzX2FkbWluOmN1ZWRlc19hZG1pbl9zZWNyZXQ=
|
||||||
|
|
||||||
|
# 当需要重置localStorage时, 修改此变量
|
||||||
|
VITE_STORAGE_VERSION = 1
|
||||||
|
|
||||||
# 调试授权码
|
# 调试授权码
|
||||||
VITE_DEBUG_CODE = ndm_debug
|
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 { NdmMediaServerVO } from './video/ndm-media-server';
|
||||||
import type { NdmVideoServerVO } from './video/ndm-video-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-device-alarm-log';
|
||||||
export * from './log/ndm-icmp-log';
|
export * from './log/ndm-icmp-log';
|
||||||
export * from './log/ndm-snmp-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 './export/ndm-icmp-export';
|
||||||
|
|
||||||
|
export * from './log/ndm-call-log';
|
||||||
export * from './log/ndm-device-alarm-log';
|
export * from './log/ndm-device-alarm-log';
|
||||||
export * from './log/ndm-icmp-log';
|
export * from './log/ndm-icmp-log';
|
||||||
export * from './log/ndm-snmp-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-keyboard';
|
||||||
export * from './video/ndm-media-server';
|
export * from './video/ndm-media-server';
|
||||||
export * from './video/ndm-video-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) => {
|
export const postNdmSecurityBoxPage = async (stationCode: string, pageQuery: PageParams<NdmSecurityBoxPageQuery>, signal?: AbortSignal) => {
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const resp = await ndmClient.post<PageResult<NdmSecurityBoxResultVO>>(`${prefix}/api/ndm/ndmSecurityBox/page`, pageQuery, { signal });
|
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;
|
const [err, ndmSecurityBoxData] = resp;
|
||||||
if (err || !ndmSecurityBoxData) {
|
if (err || !ndmSecurityBoxData) {
|
||||||
throw err;
|
throw err;
|
||||||
@@ -18,7 +28,7 @@ export const putNdmSecurityBox = async (stationCode: string, updateVO: NdmSecuri
|
|||||||
if (err || !ndmSecurityBox) {
|
if (err || !ndmSecurityBox) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
return ndmSecurityBox;
|
return await getNdmSecurityBoxDetail(stationCode, ndmSecurityBox.id ?? '');
|
||||||
};
|
};
|
||||||
|
|
||||||
export const turnStatus = async (stationCode: string, ipAddress: string, circuitIndex: number, status: number) => {
|
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) => {
|
export const postNdmSwitchPage = async (stationCode: string, pageQuery: PageParams<NdmSwitchPageQuery>, signal?: AbortSignal) => {
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const resp = await ndmClient.post<PageResult<NdmSwitchResultVO>>(`${prefix}/api/ndm/ndmSwitch/page`, pageQuery, { signal });
|
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;
|
const [err, ndmSwitchData] = resp;
|
||||||
if (err || !ndmSwitchData) {
|
if (err || !ndmSwitchData) {
|
||||||
throw err;
|
throw err;
|
||||||
@@ -18,5 +28,5 @@ export const putNdmSwitch = async (stationCode: string, updateVO: NdmSwitchUpdat
|
|||||||
if (err || !ndmSwitch) {
|
if (err || !ndmSwitch) {
|
||||||
throw err;
|
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) => {
|
export const postNdmNvrPage = async (stationCode: string, pageQuery: PageParams<NdmNvrPageQuery>, signal?: AbortSignal) => {
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const resp = await ndmClient.post<PageResult<NdmNvrResultVO>>(`${prefix}/api/ndm/ndmNvr/page`, pageQuery, { signal });
|
const resp = await ndmClient.post<PageResult<NdmNvrResultVO>>(`${prefix}/api/ndm/ndmNvr/page`, pageQuery, { signal });
|
||||||
const [err, ndmNvrData] = resp;
|
const [err, ndmNvr] = resp;
|
||||||
if (err || !ndmNvrData) {
|
if (err || !ndmNvr) {
|
||||||
throw err;
|
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) => {
|
export const putNdmNvr = async (stationCode: string, updateVO: NdmNvrUpdateVO) => {
|
||||||
@@ -19,7 +29,7 @@ export const putNdmNvr = async (stationCode: string, updateVO: NdmNvrUpdateVO) =
|
|||||||
if (err || !ndmNvr) {
|
if (err || !ndmNvr) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
return ndmNvr;
|
return await getNdmNvrDetail(stationCode, ndmNvr.id ?? '');
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getChannelList = async (stationCode: string, ndmNvr: NdmNvrResultVO) => {
|
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) => {
|
export const postNdmCameraPage = async (stationCode: string, pageQuery: PageParams<NdmCameraPageQuery>, signal?: AbortSignal) => {
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const resp = await ndmClient.post<PageResult<NdmCameraResultVO>>(`${prefix}/api/ndm/ndmCamera/page`, pageQuery, { signal });
|
const resp = await ndmClient.post<PageResult<NdmCameraResultVO>>(`${prefix}/api/ndm/ndmCamera/page`, pageQuery, { signal });
|
||||||
const [err, ndmCameraData] = resp;
|
const [err, ndmCamera] = resp;
|
||||||
if (err || !ndmCameraData) {
|
if (err || !ndmCamera) {
|
||||||
throw err;
|
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) => {
|
export const putNdmCamera = async (stationCode: string, updateVO: NdmCameraUpdateVO) => {
|
||||||
@@ -18,5 +28,5 @@ export const putNdmCamera = async (stationCode: string, updateVO: NdmCameraUpdat
|
|||||||
if (err || !ndmCamera) {
|
if (err || !ndmCamera) {
|
||||||
throw err;
|
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) => {
|
export const postNdmDecoderPage = async (stationCode: string, pageQuery: PageParams<NdmDecoderPageQuery>, signal?: AbortSignal) => {
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const resp = await ndmClient.post<PageResult<NdmDecoderResultVO>>(`${prefix}/api/ndm/ndmDecoder/page`, pageQuery, { signal });
|
const resp = await ndmClient.post<PageResult<NdmDecoderResultVO>>(`${prefix}/api/ndm/ndmDecoder/page`, pageQuery, { signal });
|
||||||
const [err, ndmDecoderData] = resp;
|
const [err, ndmDecoder] = resp;
|
||||||
if (err || !ndmDecoderData) {
|
if (err || !ndmDecoder) {
|
||||||
throw err;
|
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) => {
|
export const putNdmDecoder = async (stationCode: string, updateVO: NdmDecoderUpdateVO) => {
|
||||||
@@ -18,5 +28,5 @@ export const putNdmDecoder = async (stationCode: string, updateVO: NdmDecoderUpd
|
|||||||
if (err || !ndmDecoder) {
|
if (err || !ndmDecoder) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
return ndmDecoder;
|
return await getNdmDecoderDetail(stationCode, ndmDecoder.id ?? '');
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,6 +11,16 @@ export const postNdmKeyboardPage = async (stationCode: string, pageQuery: PagePa
|
|||||||
return ndmKeyboardData;
|
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) => {
|
export const putNdmKeyboard = async (stationCode: string, updateVO: NdmKeyboardUpdateVO) => {
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const resp = await ndmClient.put<NdmKeyboardResultVO>(`${prefix}/api/ndm/ndmKeyboard`, updateVO);
|
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) {
|
if (err || !ndmKeyboard) {
|
||||||
throw err;
|
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) => {
|
export const postNdmMediaServerPage = async (stationCode: string, pageQuery: PageParams<NdmMediaServerPageQuery>, signal?: AbortSignal) => {
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const resp = await ndmClient.post<PageResult<NdmMediaServerResultVO>>(`${prefix}/api/ndm/ndmMediaServer/page`, pageQuery, { signal });
|
const resp = await ndmClient.post<PageResult<NdmMediaServerResultVO>>(`${prefix}/api/ndm/ndmMediaServer/page`, pageQuery, { signal });
|
||||||
const [err, ndmMediaServerData] = resp;
|
const [err, ndmMediaServer] = resp;
|
||||||
if (err || !ndmMediaServerData) {
|
if (err || !ndmMediaServer) {
|
||||||
throw err;
|
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) => {
|
export const putNdmMediaServer = async (stationCode: string, updateVO: NdmMediaServerUpdateVO) => {
|
||||||
@@ -18,5 +28,5 @@ export const putNdmMediaServer = async (stationCode: string, updateVO: NdmMediaS
|
|||||||
if (err || !ndmMediaServer) {
|
if (err || !ndmMediaServer) {
|
||||||
throw err;
|
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) => {
|
export const postNdmVideoServerPage = async (stationCode: string, pageQuery: PageParams<NdmVideoServerPageQuery>, signal?: AbortSignal) => {
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const resp = await ndmClient.post<PageResult<NdmVideoServerResultVO>>(`${prefix}/api/ndm/ndmVideoServer/page`, pageQuery, { signal });
|
const resp = await ndmClient.post<PageResult<NdmVideoServerResultVO>>(`${prefix}/api/ndm/ndmVideoServer/page`, pageQuery, { signal });
|
||||||
const [err, ndmVideoServerData] = resp;
|
const [err, ndmVideoServer] = resp;
|
||||||
if (err || !ndmVideoServerData) {
|
if (err || !ndmVideoServer) {
|
||||||
throw err;
|
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) => {
|
export const putNdmVideoServer = async (stationCode: string, updateVO: NdmVideoServerUpdateVO) => {
|
||||||
@@ -18,5 +28,5 @@ export const putNdmVideoServer = async (stationCode: string, updateVO: NdmVideoS
|
|||||||
if (err || !ndmVideoServer) {
|
if (err || !ndmVideoServer) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
return ndmVideoServer;
|
return await getNdmVideoServerDetail(stationCode, ndmVideoServer.id ?? '');
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,10 +2,9 @@
|
|||||||
import type { Station } from '@/apis/domains';
|
import type { Station } from '@/apis/domains';
|
||||||
import { DeviceType } from '@/enums/device-type';
|
import { DeviceType } from '@/enums/device-type';
|
||||||
import { type StationAlarmCounts, type StationDevices } from '@/composables/query';
|
import { type StationAlarmCounts, type StationDevices } from '@/composables/query';
|
||||||
import { ControlOutlined } from '@vicons/antd';
|
import { MoreOutlined, EllipsisOutlined } from '@vicons/antd';
|
||||||
import { Video as VideoIcon } from '@vicons/carbon';
|
|
||||||
import axios from 'axios';
|
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';
|
import { toRefs, computed } from 'vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
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();
|
const theme = useThemeVars();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<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>
|
<template #header>
|
||||||
<NTooltip v-if="station.ip" trigger="click">
|
<NTooltip v-if="station.ip" trigger="click">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<span class="font-smaller">{{ station.name }}</span>
|
<span class="font-medium">{{ station.name }}</span>
|
||||||
</template>
|
</template>
|
||||||
<span>{{ station.ip }}</span>
|
<span>{{ station.ip }}</span>
|
||||||
</NTooltip>
|
</NTooltip>
|
||||||
<span v-else class="font-smaller">{{ station.name }}</span>
|
<span v-else class="font-medium">{{ station.name }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #header-extra>
|
<template #header-extra>
|
||||||
|
<NFlex :size="4">
|
||||||
<NTag :type="station.online ? 'success' : 'error'" size="small">
|
<NTag :type="station.online ? 'success' : 'error'" size="small">
|
||||||
{{ station.online ? '在线' : '离线' }}
|
{{ station.online ? '在线' : '离线' }}
|
||||||
</NTag>
|
</NTag>
|
||||||
|
<NDropdown trigger="click" :options="dropdownOptions" @select="selectDropdownOption">
|
||||||
|
<NButton quaternary size="tiny" :focusable="false">
|
||||||
|
<NIcon :component="MoreOutlined" />
|
||||||
|
</NButton>
|
||||||
|
</NDropdown>
|
||||||
|
</NFlex>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #default>
|
<template #default>
|
||||||
<NSpace vertical :size="8">
|
<NFlex vertical :size="6" class="metrics" :style="{ opacity: station.online ? '1' : '0.5' }">
|
||||||
<NFlex :justify="'flex-start'" class="actions">
|
<NFlex vertical :size="4" class="metric-item">
|
||||||
<NButton quaternary size="tiny" :focusable="false" :disabled="!station.online" @click="openVideoPlatform">
|
<NFlex justify="end" align="center" class="metric-line">
|
||||||
<NIcon>
|
<span class="font-small">{{ deviceCount }} 台设备</span>
|
||||||
<VideoIcon />
|
<NButton quaternary size="tiny" :focusable="false" @click="openOfflineDeviceTreeModal">
|
||||||
</NIcon>
|
<NIcon :component="EllipsisOutlined" />
|
||||||
<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>
|
</NButton>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
|
<NFlex justify="end" align="center" class="metric-line">
|
||||||
<NFlex vertical :size="0" class="metrics" :style="{ opacity: station.online ? '1' : '0.5' }">
|
<span class="font-small">
|
||||||
<NFlex justify="space-between" align="baseline" class="metric-item">
|
<span :style="{ color: onlineDeviceCount > 0 ? theme.successColor : '' }">在线 {{ onlineDeviceCount }} 台</span>
|
||||||
<NText depth="3" class="metric-label" :class="[station.online ? 'clickable' : '']" @click="station.online && openOfflineDeviceTreeModal()">设备统计</NText>
|
<NText depth="3" class="sep">·</NText>
|
||||||
<span class="metric-value">
|
<span :style="{ color: offlineDeviceCount > 0 ? theme.errorColor : '' }">离线 {{ offlineDeviceCount }} 台</span>
|
||||||
<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>
|
</span>
|
||||||
|
<NButton quaternary size="tiny" :focusable="false" style="visibility: hidden">
|
||||||
|
<NIcon :component="EllipsisOutlined" />
|
||||||
|
</NButton>
|
||||||
|
</NFlex>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
|
|
||||||
<NFlex justify="space-between" align="baseline" class="metric-item">
|
<NFlex justify="end" align="center" class="metric-item">
|
||||||
<NText depth="3" class="metric-label" :class="[station.online ? 'clickable' : '']" @click="station.online && openDeviceAlarmTreeModal()">告警记录</NText>
|
<NFlex align="center" :size="8">
|
||||||
<span class="metric-value">
|
<span class="font-small" :style="{ color: alarmCount > 0 ? theme.warningColor : '' }">今日 {{ alarmCount }} 条告警</span>
|
||||||
<span>{{ alarmCount }}</span>
|
<NButton quaternary size="tiny" :focusable="false" @click="openDeviceAlarmTreeModal">
|
||||||
<NText depth="3" class="unit">条</NText>
|
<NIcon :component="EllipsisOutlined" />
|
||||||
</span>
|
</NButton>
|
||||||
|
</NFlex>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</NSpace>
|
|
||||||
</template>
|
</template>
|
||||||
</NCard>
|
</NCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.clickable {
|
.font-medium {
|
||||||
text-decoration: underline dashed;
|
font-size: medium;
|
||||||
cursor: pointer;
|
|
||||||
transition: color 0.2s ease;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: v-bind('theme.iconColorHover');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.font-smaller {
|
.font-small {
|
||||||
font-size: smaller;
|
font-size: small;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-text {
|
.metrics {
|
||||||
margin-left: 6px;
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sep {
|
||||||
|
margin: 0 6px;
|
||||||
font-size: xx-small;
|
font-size: xx-small;
|
||||||
color: v-bind('theme.textColor3');
|
color: v-bind('theme.textColor3');
|
||||||
}
|
}
|
||||||
|
|
||||||
.metric-label {
|
.metric-line .font-small {
|
||||||
font-size: xx-small;
|
white-space: nowrap;
|
||||||
}
|
|
||||||
|
|
||||||
.metric-value {
|
|
||||||
font-size: small;
|
|
||||||
}
|
|
||||||
|
|
||||||
.unit,
|
|
||||||
.slash {
|
|
||||||
margin-left: 4px;
|
|
||||||
font-size: xx-small;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ const selectedTab = ref('设备状态');
|
|||||||
<NTabs v-model:value="selectedTab" size="small">
|
<NTabs v-model:value="selectedTab" size="small">
|
||||||
<NTabPane name="设备状态" tab="设备状态">
|
<NTabPane name="设备状态" tab="设备状态">
|
||||||
<NFlex vertical>
|
<NFlex vertical>
|
||||||
<DeviceHeaderCard :device="ndmCamera" />
|
<DeviceHeaderCard :station-code="stationCode" :device="ndmCamera" />
|
||||||
<DeviceCommonCard :common-info="commonInfo" />
|
<DeviceCommonCard :common-info="commonInfo" />
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</NTabPane>
|
</NTabPane>
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { NdmDeviceResultVO } from '@/apis/models';
|
import type { NdmDeviceResultVO } from '@/apis/models';
|
||||||
|
import { getDeviceDetailApi, probeDeviceApi } from '@/apis/requests';
|
||||||
import { DeviceType, DeviceTypeName, tryGetDeviceTypeVal, type DeviceTypeVal } from '@/enums/device-type';
|
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';
|
import { computed, toRefs } from 'vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
stationCode: string;
|
||||||
device: NdmDeviceResultVO;
|
device: NdmDeviceResultVO;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// const emit = defineEmits<{}>();
|
// const emit = defineEmits<{}>();
|
||||||
|
|
||||||
const { device } = toRefs(props);
|
const { stationCode, device } = toRefs(props);
|
||||||
|
|
||||||
const type = computed(() => {
|
const type = computed(() => {
|
||||||
const deviceTypeVal = tryGetDeviceTypeVal(device.value.deviceType);
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -51,6 +84,8 @@ const onClickOpenMgmtPage = () => {
|
|||||||
<div>{{ name }}</div>
|
<div>{{ name }}</div>
|
||||||
<NButton v-if="canOpenMgmtPage" ghost size="tiny" type="default" :focusable="false" @click="onClickOpenMgmtPage">管理</NButton>
|
<NButton v-if="canOpenMgmtPage" ghost size="tiny" type="default" :focusable="false" @click="onClickOpenMgmtPage">管理</NButton>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
|
</template>
|
||||||
|
<template #default>
|
||||||
<div style="font-size: small; color: #666">
|
<div style="font-size: small; color: #666">
|
||||||
<div>
|
<div>
|
||||||
<span>设备类型:</span>
|
<span>设备类型:</span>
|
||||||
@@ -74,6 +109,32 @@ const onClickOpenMgmtPage = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</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>
|
</NCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { NdmSecurityBoxCircuit } from '@/apis/domains';
|
import type { NdmSecurityBoxCircuit } from '@/apis/domains';
|
||||||
import type { NdmSecurityBoxResultVO } from '@/apis/models';
|
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 { PowerOutline, FlashOutline } from '@vicons/ionicons5';
|
||||||
import { NCard, NGrid, NGridItem, NPopover, NSwitch, NIcon, NFlex, NPopconfirm, NButton } from 'naive-ui';
|
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 { stationCode, ndmSecurityBox, circuits } = toRefs(props);
|
||||||
|
|
||||||
const validCircuits = computed(() => {
|
const localCircuits = ref<NdmSecurityBoxCircuit[]>([]);
|
||||||
if (!circuits.value || circuits.value.length === 0) {
|
|
||||||
return [];
|
watch(
|
||||||
}
|
circuits,
|
||||||
return circuits.value;
|
(newValue) => {
|
||||||
});
|
localCircuits.value = newValue?.map((circuit) => ({ ...circuit })) ?? [];
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取电路状态样式类
|
|
||||||
* @param circuit 电路信息
|
|
||||||
* @returns CSS类名
|
|
||||||
*/
|
|
||||||
const getCircuitStatusClass = (circuit: NdmSecurityBoxCircuit) => {
|
const getCircuitStatusClass = (circuit: NdmSecurityBoxCircuit) => {
|
||||||
if (circuit.status === 1) {
|
if (circuit.status === 1) {
|
||||||
return 'circuit-on';
|
return 'circuit-on';
|
||||||
@@ -44,12 +45,6 @@ const getCircuitStatusClass = (circuit: NdmSecurityBoxCircuit) => {
|
|||||||
}
|
}
|
||||||
return 'circuit-unknown';
|
return 'circuit-unknown';
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取电路状态文本
|
|
||||||
* @param circuit 电路信息
|
|
||||||
* @returns 状态文本
|
|
||||||
*/
|
|
||||||
const getCircuitStatusText = (circuit: NdmSecurityBoxCircuit) => {
|
const getCircuitStatusText = (circuit: NdmSecurityBoxCircuit) => {
|
||||||
if (circuit.status === 1) {
|
if (circuit.status === 1) {
|
||||||
return '开启';
|
return '开启';
|
||||||
@@ -59,58 +54,65 @@ const getCircuitStatusText = (circuit: NdmSecurityBoxCircuit) => {
|
|||||||
return '未知';
|
return '未知';
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
const { mutate: turnStatus, isPending: turning } = useMutation({
|
||||||
* 处理电路开关切换
|
mutationFn: async (params: { circuitIndex: number; newStatus: boolean }) => {
|
||||||
* @param circuitIndex 电路索引
|
const { circuitIndex, newStatus } = params;
|
||||||
* @param newStatus 新状态
|
|
||||||
*/
|
|
||||||
const handleCircuitToggle = async (circuitIndex: number, newStatus: boolean) => {
|
|
||||||
if (!ndmSecurityBox.value.ipAddress) {
|
if (!ndmSecurityBox.value.ipAddress) {
|
||||||
window.$message.error('设备IP地址不存在');
|
throw new Error('设备IP地址不存在');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
const status = newStatus ? 1 : 0;
|
const status = newStatus ? 1 : 0;
|
||||||
await turnStatus(stationCode.value, ndmSecurityBox.value.ipAddress, circuitIndex, status);
|
await turnStatusApi(stationCode.value, ndmSecurityBox.value.ipAddress, circuitIndex, status);
|
||||||
window.$message.success(`电路${circuitIndex + 1}${newStatus ? '开启' : '关闭'}成功 下次更新诊断数据时将刷新状态`);
|
await probeDeviceApi(stationCode.value, ndmSecurityBox.value);
|
||||||
} catch (error) {
|
return status;
|
||||||
window.$message.error(`电路${circuitIndex + 1}操作失败`);
|
},
|
||||||
console.error('电路开关操作失败:', error);
|
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 () => {
|
const { mutate: rebootSecurityBox, isPending: rebooting } = useMutation({
|
||||||
|
mutationFn: async () => {
|
||||||
if (!ndmSecurityBox.value.ipAddress) {
|
if (!ndmSecurityBox.value.ipAddress) {
|
||||||
window.$message.error('设备IP地址不存在');
|
throw new Error('设备IP地址不存在');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
try {
|
await rebootSecurityBoxApi(stationCode.value, ndmSecurityBox.value.ipAddress);
|
||||||
await rebootSecurityBox(stationCode.value, ndmSecurityBox.value.ipAddress);
|
},
|
||||||
|
onSuccess: () => {
|
||||||
window.$message.success('设备重启成功');
|
window.$message.success('设备重启成功');
|
||||||
} catch (error) {
|
},
|
||||||
window.$message.error('设备重启失败');
|
onError: (error) => {
|
||||||
console.error('设备重启失败:', error);
|
console.error(error);
|
||||||
}
|
window.$message.error(error.message);
|
||||||
};
|
},
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NCard v-if="validCircuits.length > 0" size="small" hoverable>
|
<NCard v-if="localCircuits.length > 0" size="small" hoverable>
|
||||||
<template #header>
|
<template #header>
|
||||||
<NFlex :align="'center'">
|
<NFlex :align="'center'">
|
||||||
<div>电路状态</div>
|
<div>电路状态</div>
|
||||||
<NPopconfirm :positive-text="'确认'" :negative-text="'取消'" @positive-click="onClickReboot">
|
<NPopconfirm :positive-text="'确认'" :negative-text="'取消'" @positive-click="() => rebootSecurityBox()">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<NButton secondary size="small">重合闸</NButton>
|
<NButton secondary size="small" :loading="rebooting">重合闸</NButton>
|
||||||
</template>
|
</template>
|
||||||
确定要执行重合闸操作吗?此操作将重启安防箱设备。
|
确定要执行重合闸操作吗?此操作将重启安防箱设备。
|
||||||
</NPopconfirm>
|
</NPopconfirm>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</template>
|
</template>
|
||||||
<div class="circuit-layout">
|
<div class="circuit-layout">
|
||||||
<NGrid :cols="Math.min(validCircuits.length, 4)" :x-gap="12" :y-gap="12" class="circuit-grid">
|
<NGrid :cols="Math.min(localCircuits.length, 4)" :x-gap="12" :y-gap="12" class="circuit-grid">
|
||||||
<NGridItem v-for="(circuit, index) in validCircuits" :key="index">
|
<NGridItem v-for="(circuit, index) in localCircuits" :key="index">
|
||||||
<!-- 电路信息弹窗 -->
|
<!-- 电路信息弹窗 -->
|
||||||
<NPopover trigger="hover" placement="top">
|
<NPopover trigger="hover" placement="top">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
@@ -126,9 +128,9 @@ const onClickReboot = async () => {
|
|||||||
<span class="status-text">{{ getCircuitStatusText(circuit) }}</span>
|
<span class="status-text">{{ getCircuitStatusText(circuit) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="circuit-control">
|
<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>
|
<template #trigger>
|
||||||
<NSwitch :value="circuit.status === 1" size="small" />
|
<NSwitch :value="circuit.status === 1" size="small" :loading="turning" />
|
||||||
</template>
|
</template>
|
||||||
确定要{{ circuit.status === 1 ? '关闭' : '开启' }}电路{{ index + 1 }}吗?
|
确定要{{ circuit.status === 1 ? '关闭' : '开启' }}电路{{ index + 1 }}吗?
|
||||||
</NPopconfirm>
|
</NPopconfirm>
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ const selectedTab = ref('设备状态');
|
|||||||
<NTabs v-model:value="selectedTab" size="small">
|
<NTabs v-model:value="selectedTab" size="small">
|
||||||
<NTabPane name="设备状态" tab="设备状态">
|
<NTabPane name="设备状态" tab="设备状态">
|
||||||
<NFlex vertical>
|
<NFlex vertical>
|
||||||
<DeviceHeaderCard :device="ndmDecoder" />
|
<DeviceHeaderCard :station-code="stationCode" :device="ndmDecoder" />
|
||||||
<DeviceCommonCard :common-info="commonInfo" />
|
<DeviceCommonCard :common-info="commonInfo" />
|
||||||
<DeviceHardwareCard :cpu-usage="cpuUsage" :mem-usage="memUsage" />
|
<DeviceHardwareCard :cpu-usage="cpuUsage" :mem-usage="memUsage" />
|
||||||
</NFlex>
|
</NFlex>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const selectedTab = ref('设备状态');
|
|||||||
<NTabs v-model:value="selectedTab" size="small">
|
<NTabs v-model:value="selectedTab" size="small">
|
||||||
<NTabPane name="设备状态" tab="设备状态">
|
<NTabPane name="设备状态" tab="设备状态">
|
||||||
<NFlex vertical>
|
<NFlex vertical>
|
||||||
<DeviceHeaderCard :device="ndmKeyboard" />
|
<DeviceHeaderCard :station-code="stationCode" :device="ndmKeyboard" />
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</NTabPane>
|
</NTabPane>
|
||||||
<NTabPane name="历史诊断" tab="历史诊断">
|
<NTabPane name="历史诊断" tab="历史诊断">
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ const selectedTab = ref('设备状态');
|
|||||||
<NTabs v-model:value="selectedTab" size="small">
|
<NTabs v-model:value="selectedTab" size="small">
|
||||||
<NTabPane name="设备状态" tab="设备状态">
|
<NTabPane name="设备状态" tab="设备状态">
|
||||||
<NFlex vertical>
|
<NFlex vertical>
|
||||||
<DeviceHeaderCard :device="ndmNvr" />
|
<DeviceHeaderCard :station-code="stationCode" :device="ndmNvr" />
|
||||||
<DeviceCommonCard :common-info="commonInfo" />
|
<DeviceCommonCard :common-info="commonInfo" />
|
||||||
<DeviceHardwareCard :cpu-usage="cpuUsage" :mem-usage="memUsage" />
|
<DeviceHardwareCard :cpu-usage="cpuUsage" :mem-usage="memUsage" />
|
||||||
<NvrDiskCard :disk-health="diskHealth" :group-info-list="groupInfoList" />
|
<NvrDiskCard :disk-health="diskHealth" :group-info-list="groupInfoList" />
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ const selectedTab = ref('设备状态');
|
|||||||
<NTabs v-model:value="selectedTab" size="small">
|
<NTabs v-model:value="selectedTab" size="small">
|
||||||
<NTabPane name="设备状态" tab="设备状态">
|
<NTabPane name="设备状态" tab="设备状态">
|
||||||
<NFlex vertical>
|
<NFlex vertical>
|
||||||
<DeviceHeaderCard :device="ndmSecurityBox" />
|
<DeviceHeaderCard :station-code="stationCode" :device="ndmSecurityBox" />
|
||||||
<DeviceCommonCard :common-info="commonInfo" />
|
<DeviceCommonCard :common-info="commonInfo" />
|
||||||
<DeviceHardwareCard :cpu-usage="cpuUsage" :mem-usage="memUsage" />
|
<DeviceHardwareCard :cpu-usage="cpuUsage" :mem-usage="memUsage" />
|
||||||
<SecurityBoxInfoCard :fan-speeds="fanSpeeds" :temperature="temperature" :humidity="humidity" :switches="switches" />
|
<SecurityBoxInfoCard :fan-speeds="fanSpeeds" :temperature="temperature" :humidity="humidity" :switches="switches" />
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ const selectedTab = ref('设备状态');
|
|||||||
<NTabs v-model:value="selectedTab" size="small">
|
<NTabs v-model:value="selectedTab" size="small">
|
||||||
<NTabPane name="设备状态">
|
<NTabPane name="设备状态">
|
||||||
<NFlex vertical>
|
<NFlex vertical>
|
||||||
<DeviceHeaderCard :device="ndmServer" />
|
<DeviceHeaderCard :station-code="stationCode" :device="ndmServer" />
|
||||||
<DeviceHardwareCard :cpu-usage="cpuUsage" :mem-usage="memUsage" :disk-usage="diskUsage" :running-time="runningTime" />
|
<DeviceHardwareCard :cpu-usage="cpuUsage" :mem-usage="memUsage" :disk-usage="diskUsage" :running-time="runningTime" />
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</NTabPane>
|
</NTabPane>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ const selectedTab = ref('设备状态');
|
|||||||
<NTabs v-model:value="selectedTab" size="small">
|
<NTabs v-model:value="selectedTab" size="small">
|
||||||
<NTabPane name="设备状态">
|
<NTabPane name="设备状态">
|
||||||
<NFlex vertical>
|
<NFlex vertical>
|
||||||
<DeviceHeaderCard :device="ndmSwitch" />
|
<DeviceHeaderCard :station-code="stationCode" :device="ndmSwitch" />
|
||||||
<DeviceHardwareCard :cpu-usage="cpuUsage" :mem-usage="memUsage" />
|
<DeviceHardwareCard :cpu-usage="cpuUsage" :mem-usage="memUsage" />
|
||||||
<SwitchPortCard :port-info-list="portInfoList" />
|
<SwitchPortCard :port-info-list="portInfoList" />
|
||||||
</NFlex>
|
</NFlex>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const route = useRoute();
|
|||||||
const show = defineModel<boolean>('show');
|
const show = defineModel<boolean>('show');
|
||||||
|
|
||||||
const layoutStore = useLayoutStore();
|
const layoutStore = useLayoutStore();
|
||||||
const { stationLayoutGridCols } = storeToRefs(layoutStore);
|
const { stationGridColumns } = storeToRefs(layoutStore);
|
||||||
const queryControlStore = useQueryControlStore();
|
const queryControlStore = useQueryControlStore();
|
||||||
const { stationVerifyMode } = storeToRefs(queryControlStore);
|
const { stationVerifyMode } = storeToRefs(queryControlStore);
|
||||||
|
|
||||||
@@ -73,10 +73,10 @@ useEventListener('keydown', (event) => {
|
|||||||
<NFormItem label="深色模式" label-placement="left">
|
<NFormItem label="深色模式" label-placement="left">
|
||||||
<ThemeSwitch />
|
<ThemeSwitch />
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<template v-if="route.path === '/dashboard'">
|
<template v-if="route.path === '/station'">
|
||||||
<NDivider>布局</NDivider>
|
<NDivider>布局</NDivider>
|
||||||
<NFormItem label="车站列数" label-placement="left">
|
<NFormItem label="车站列数" label-placement="left">
|
||||||
<NInputNumber v-model:value="stationLayoutGridCols" :min="1" :max="10" />
|
<NInputNumber v-model:value="stationGridColumns" :min="1" :max="10" />
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="debugEnabled">
|
<template v-if="debugEnabled">
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import type { VersionInfo } from '@/apis/domains/version-info';
|
import type { VersionInfo } from '@/apis/domains/version-info';
|
||||||
import { useQuery } from '@tanstack/vue-query';
|
import { useQuery } from '@tanstack/vue-query';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import { useThemeVars } from 'naive-ui';
|
||||||
import { h, ref, watch } from 'vue';
|
import { h, ref, watch } from 'vue';
|
||||||
|
|
||||||
export function useVersionCheckQuery() {
|
export function useVersionCheckQuery() {
|
||||||
const localVersionInfo = ref<VersionInfo>();
|
const localVersionInfo = ref<VersionInfo>();
|
||||||
const dialogShow = ref<boolean>(false);
|
const dialogShow = ref<boolean>(false);
|
||||||
|
const themeVars = useThemeVars();
|
||||||
|
|
||||||
const { data: remoteVersionInfo, dataUpdatedAt } = useQuery({
|
const { data: remoteVersionInfo, dataUpdatedAt } = useQuery({
|
||||||
queryKey: ['version-check'],
|
queryKey: ['version-check'],
|
||||||
@@ -25,7 +27,10 @@ export function useVersionCheckQuery() {
|
|||||||
return;
|
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;
|
dialogShow.value = true;
|
||||||
window.$dialog.info({
|
window.$dialog.info({
|
||||||
title: '发现新版本',
|
title: '发现新版本',
|
||||||
@@ -34,6 +39,7 @@ export function useVersionCheckQuery() {
|
|||||||
h('div', {}, { default: () => `当前版本:${localVersionInfo.value?.version}` }),
|
h('div', {}, { default: () => `当前版本:${localVersionInfo.value?.version}` }),
|
||||||
h('div', {}, { default: () => `最新版本:${newVersionInfo.version}` }),
|
h('div', {}, { default: () => `最新版本:${newVersionInfo.version}` }),
|
||||||
h('div', {}, { default: () => '请点击刷新页面以更新' }),
|
h('div', {}, { default: () => '请点击刷新页面以更新' }),
|
||||||
|
h('div', { style: { marginTop: '8px', fontWeight: '700', color: themeVars.value.warningColor } }, { default: () => '⚠️ 注意,更新后可能需要重新登录!' }),
|
||||||
]),
|
]),
|
||||||
positiveText: '刷新页面',
|
positiveText: '刷新页面',
|
||||||
maskClosable: false,
|
maskClosable: false,
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ import { useCurrentAlarmsStore } from '@/stores/current-alarms';
|
|||||||
import { useUserStore } from '@/stores/user';
|
import { useUserStore } from '@/stores/user';
|
||||||
import { Client as StompClient } from '@stomp/stompjs';
|
import { Client as StompClient } from '@stomp/stompjs';
|
||||||
import { useIsFetching } from '@tanstack/vue-query';
|
import { useIsFetching } from '@tanstack/vue-query';
|
||||||
import { AlertFilled, /* AreaChartOutlined, */ FileTextFilled, HomeFilled, LogoutOutlined, SettingOutlined, VideoCameraFilled } from '@vicons/antd';
|
import { AlertFilled, BugFilled, CaretDownFilled, EnvironmentFilled, /* AreaChartOutlined, */ FileTextFilled, FundFilled, HddFilled, LogoutOutlined, SettingOutlined } from '@vicons/antd';
|
||||||
import { ChevronDown, Debug } from '@vicons/carbon';
|
|
||||||
import type { AxiosError } from 'axios';
|
import type { AxiosError } from 'axios';
|
||||||
import { destr } from 'destr';
|
import { destr } from 'destr';
|
||||||
import { NBadge, NButton, NDropdown, NFlex, NIcon, NLayout, NLayoutContent, NLayoutFooter, NLayoutHeader, NLayoutSider, NMenu, NScrollbar, type DropdownOption, type MenuOption } from 'naive-ui';
|
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[]>([
|
const menuOptions = ref<MenuOption[]>([
|
||||||
{
|
{
|
||||||
label: () => h(RouterLink, { to: '/dashboard' }, { default: () => '今日数据看板' }),
|
label: () => h(RouterLink, { to: '/dashboard' }, { default: () => '全线总概览' }),
|
||||||
key: '/dashboard',
|
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',
|
key: '/device',
|
||||||
icon: renderIcon(VideoCameraFilled),
|
icon: renderIcon(HddFilled),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: () => h(RouterLink, { to: '/alarm' }, { default: () => '设备告警记录' }),
|
label: () => h(RouterLink, { to: '/alarm' }, { default: () => '设备告警' }),
|
||||||
key: '/alarm',
|
key: '/alarm',
|
||||||
icon: renderIcon(AlertFilled),
|
icon: renderIcon(AlertFilled),
|
||||||
},
|
},
|
||||||
@@ -118,20 +122,24 @@ const menuOptions = ref<MenuOption[]>([
|
|||||||
// icon: renderIcon(AreaChartOutlined),
|
// icon: renderIcon(AreaChartOutlined),
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
label: () => h(RouterLink, { to: '/log/vimp-log' }, { default: () => '视频平台日志' }), // '系统日志记录'
|
label: '系统日志',
|
||||||
key: '/log/vimp-log',
|
key: '/log',
|
||||||
icon: renderIcon(FileTextFilled),
|
icon: renderIcon(FileTextFilled),
|
||||||
// children: [
|
children: [
|
||||||
// {
|
{
|
||||||
// label: () => h(RouterLink, { to: '/log/vimp-log' }, { default: () => '视频平台日志' }),
|
label: () => h(RouterLink, { to: '/log/vimp-log' }, { default: () => '视频平台日志' }),
|
||||||
// key: '/log/vimp-log',
|
key: '/log/vimp-log',
|
||||||
// },
|
},
|
||||||
// ],
|
{
|
||||||
|
label: () => h(RouterLink, { to: '/log/call-log' }, { default: () => '上级调用日志' }),
|
||||||
|
key: '/log/call-log',
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: () => h(RouterLink, { to: '/debug' }, { default: () => '调试' }),
|
label: () => h(RouterLink, { to: '/debug' }, { default: () => '调试' }),
|
||||||
key: '/debug',
|
key: '/debug',
|
||||||
icon: renderIcon(Debug),
|
icon: renderIcon(BugFilled),
|
||||||
show: import.meta.env.DEV,
|
show: import.meta.env.DEV,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@@ -195,15 +203,13 @@ const openSettingsDrawer = () => {
|
|||||||
<span>{{ userInfo?.nickName ?? '' }}</span>
|
<span>{{ userInfo?.nickName ?? '' }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="ChevronDown" />
|
<NIcon :component="CaretDownFilled" />
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
</NDropdown>
|
</NDropdown>
|
||||||
<NButton :focusable="false" quaternary @click="openSettingsDrawer" style="height: 100%">
|
<NButton :focusable="false" quaternary @click="openSettingsDrawer" style="height: 100%">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon>
|
<NIcon :component="SettingOutlined" />
|
||||||
<SettingOutlined />
|
|
||||||
</NIcon>
|
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
@@ -217,9 +223,7 @@ const openSettingsDrawer = () => {
|
|||||||
<NBadge :value="currentAlarmCount">
|
<NBadge :value="currentAlarmCount">
|
||||||
<NButton secondary strong @click="toAlarmPage">
|
<NButton secondary strong @click="toAlarmPage">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon>
|
<NIcon :component="AlertFilled" />
|
||||||
<AlertFilled />
|
|
||||||
</NIcon>
|
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
</NBadge>
|
</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 { createApp } from 'vue';
|
||||||
import { createPinia } from 'pinia';
|
import { createPinia } from 'pinia';
|
||||||
import persist from 'pinia-plugin-persistedstate';
|
import persist from 'pinia-plugin-persistedstate';
|
||||||
import { VueQueryPlugin } from '@tanstack/vue-query';
|
|
||||||
|
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
import router from './router';
|
import router from './router';
|
||||||
|
|
||||||
import '@/styles/reset.scss';
|
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);
|
const app = createApp(App);
|
||||||
|
|
||||||
app.use(createPinia().use(persist));
|
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">
|
<script setup lang="ts">
|
||||||
import type { Station } from '@/apis/domains';
|
|
||||||
import { ndmExportDevices } from '@/apis/requests';
|
import { ndmExportDevices } from '@/apis/requests';
|
||||||
import { useLineAlarmsQuery, useLineDevicesQuery } from '@/composables/query';
|
import { useLineAlarmsQuery, useLineDevicesQuery } from '@/composables/query';
|
||||||
import { useLayoutStore } from '@/stores/layout';
|
|
||||||
import { useLineAlarmsStore } from '@/stores/line-alarms';
|
|
||||||
import { useLineDevicesStore } from '@/stores/line-devices';
|
import { useLineDevicesStore } from '@/stores/line-devices';
|
||||||
import { useStationStore } from '@/stores/station';
|
import { useStationStore } from '@/stores/station';
|
||||||
import { downloadByData } from '@/utils/download';
|
import { downloadByData } from '@/utils/download';
|
||||||
import { useMutation } from '@tanstack/vue-query';
|
import { useMutation } from '@tanstack/vue-query';
|
||||||
import { NGrid, NGi } from 'naive-ui';
|
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { ref, watch } from 'vue';
|
import { watch } from 'vue';
|
||||||
import dayjs from 'dayjs';
|
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 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 stationStore = useStationStore();
|
||||||
const { stationList } = storeToRefs(stationStore);
|
const { stationList } = storeToRefs(stationStore);
|
||||||
const lineDevicesStore = useLineDevicesStore();
|
const lineDevicesStore = useLineDevicesStore();
|
||||||
const { lineDevices } = storeToRefs(lineDevicesStore);
|
const { lineDevices } = storeToRefs(lineDevicesStore);
|
||||||
const lineAlarmsStore = useLineAlarmsStore();
|
|
||||||
const { lineAlarmCounts } = storeToRefs(lineAlarmsStore);
|
|
||||||
|
|
||||||
const { error: lineDevicesQueryError } = useLineDevicesQuery();
|
const { error: lineDevicesQueryError } = useLineDevicesQuery();
|
||||||
const { error: lineAlarmsQueryError } = useLineAlarmsQuery();
|
const { error: lineAlarmsQueryError } = useLineAlarmsQuery();
|
||||||
const layoutStore = useLayoutStore();
|
|
||||||
const { stationLayoutGridCols } = storeToRefs(layoutStore);
|
|
||||||
|
|
||||||
watch([lineDevicesQueryError, lineAlarmsQueryError], ([newLineDevicesQueryError, newLineAlarmsQueryError]) => {
|
watch([lineDevicesQueryError, lineAlarmsQueryError], ([newLineDevicesQueryError, newLineAlarmsQueryError]) => {
|
||||||
if (newLineDevicesQueryError) {
|
if (newLineDevicesQueryError) {
|
||||||
@@ -61,23 +49,6 @@ const { mutate: exportDevices, isPending: exporting } = useMutation({
|
|||||||
window.$message.error(error.message);
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -89,26 +60,6 @@ const openDeviceParamsConfigModal = (station: Station) => {
|
|||||||
@export-online="() => exportDevices({ status: '10' })"
|
@export-online="() => exportDevices({ status: '10' })"
|
||||||
@export-offline="() => exportDevices({ status: '20' })"
|
@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>
|
</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 = () => {
|
const resetSearchFields = () => {
|
||||||
searchFields.stationCode = stationList.value.find((station) => station.online)?.code;
|
searchFields.stationCode = stationList.value.find((station) => station.online)?.code;
|
||||||
searchFields.logType_in = [];
|
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 getExtraFields = () => {
|
||||||
const logType_in = searchFields.logType_in.length > 0 ? [...searchFields.logType_in] : undefined;
|
const logType_in = searchFields.logType_in.length > 0 ? [...searchFields.logType_in] : undefined;
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ const router = createRouter({
|
|||||||
path: 'dashboard',
|
path: 'dashboard',
|
||||||
component: () => import('@/pages/dashboard-page.vue'),
|
component: () => import('@/pages/dashboard-page.vue'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'station',
|
||||||
|
component: () => import('@/pages/station-page.vue'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'device',
|
path: 'device',
|
||||||
component: () => import('@/pages/device-page.vue'),
|
component: () => import('@/pages/device-page.vue'),
|
||||||
@@ -31,12 +35,15 @@ const router = createRouter({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'log',
|
path: 'log',
|
||||||
redirect: '/log/vimp-log',
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'vimp-log',
|
path: 'vimp-log',
|
||||||
component: () => import('@/pages/vimp-log-page.vue'),
|
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'];
|
const whiteList = ['/debug'];
|
||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to) => {
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const isAuthed = !!userStore.userLoginResult?.token;
|
const isAuthed = !!userStore.userLoginResult?.token;
|
||||||
|
|
||||||
// 放行白名单
|
// 放行白名单
|
||||||
const inWhiteList = whiteList.some((path) => to.path.startsWith(path));
|
const inWhiteList = whiteList.some((path) => to.path.startsWith(path));
|
||||||
if (inWhiteList) {
|
if (inWhiteList) {
|
||||||
next();
|
return true;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 已登录用户不允许进入登录页(手动访问 /login 会重定向到首页)
|
// 已登录用户不允许进入登录页(手动访问 /login 会重定向到首页)
|
||||||
if (to.path === '/login') {
|
if (to.path === '/login') {
|
||||||
if (isAuthed) {
|
if (isAuthed) {
|
||||||
next({ path: '/' });
|
return { path: '/' };
|
||||||
} else {
|
} else {
|
||||||
next();
|
return true;
|
||||||
}
|
}
|
||||||
return;
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
// 其它路由按登录态控制
|
// 其它路由按登录态控制
|
||||||
if (!isAuthed) {
|
if (!isAuthed) {
|
||||||
next('/login');
|
return { path: '/login' };
|
||||||
} else {
|
} else {
|
||||||
next();
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import { ref } from 'vue';
|
|||||||
export const useLayoutStore = defineStore(
|
export const useLayoutStore = defineStore(
|
||||||
'ndm-layout-store',
|
'ndm-layout-store',
|
||||||
() => {
|
() => {
|
||||||
const stationLayoutGridCols = ref(8);
|
const stationGridColumns = ref(6);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
stationLayoutGridCols,
|
stationGridColumns,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ export const getAppEnvConfig = () => {
|
|||||||
VITE_LAMP_PASSWORD,
|
VITE_LAMP_PASSWORD,
|
||||||
VITE_LAMP_AUTHORIZATION,
|
VITE_LAMP_AUTHORIZATION,
|
||||||
VITE_DEBUG_CODE,
|
VITE_DEBUG_CODE,
|
||||||
|
VITE_STORAGE_VERSION,
|
||||||
} = env;
|
} = env;
|
||||||
return {
|
return {
|
||||||
requestInterval: Number.parseInt(VITE_REQUEST_INTERVAL as string),
|
requestInterval: Number.parseInt(VITE_REQUEST_INTERVAL as string),
|
||||||
@@ -20,5 +21,6 @@ export const getAppEnvConfig = () => {
|
|||||||
lampPassword: VITE_LAMP_PASSWORD as string,
|
lampPassword: VITE_LAMP_PASSWORD as string,
|
||||||
lampAuthorization: VITE_LAMP_AUTHORIZATION as string,
|
lampAuthorization: VITE_LAMP_AUTHORIZATION as string,
|
||||||
debugCode: VITE_DEBUG_CODE as string,
|
debugCode: VITE_DEBUG_CODE as string,
|
||||||
|
storageVersion: VITE_STORAGE_VERSION as string,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user