Compare commits

...

12 Commits

Author SHA1 Message Date
yangsy
b392328f37 fix: 修复数据表格标题错误 2026-01-08 15:59:29 +08:00
yangsy
c3692de19e fix: 修复当API接口定义中没有响应数据时会意外抛出空数据异常的问题 2026-01-08 15:55:28 +08:00
yangsy
c273ae21d9 fix: 未登录时启用离线开发模式后添加默认用户信息 2026-01-08 15:55:09 +08:00
yangsy
653981c0e7 fix: 修正告警页路由路径错误 2026-01-05 14:56:59 +08:00
yangsy
263dd5edfc refactor: 将请求封装重构为函数模式 2026-01-05 14:56:53 +08:00
yangsy
fd70f63fc9 fix: 修复请求实例选择逻辑错误 2026-01-05 14:56:47 +08:00
yangsy
8566b06429 feat: 上级调用日志添加更多数据
- 新增日志类型、用户所属类别、被调用设备名称列
- 优化在线站点选择逻辑
2026-01-04 15:31:31 +08:00
yangsy
a00c736f33 docs: 为NdmCallLog结构添加字段注释 2026-01-04 15:31:30 +08:00
yangsy
85a6b73473 fix: 将表单中的"操作类型"标签改为"日志类型" 2026-01-04 15:31:30 +08:00
yangsy
64c501f94c feat: 移除操作参数和操作结果列 2026-01-04 15:31:30 +08:00
yangsy
c81847ea0f docs: 为NdmVimpLog结构添加字段注释 2026-01-04 15:31:30 +08:00
yangsy
080759c544 fix: 修复操作类型列渲染错误的问题 2026-01-04 15:17:48 +08:00
20 changed files with 229 additions and 138 deletions

View File

@@ -1,8 +1,8 @@
import { useUserStore } from '@/stores'; import { useUserStore } from '@/stores';
import { getAppEnvConfig, RequestClient } from '@/utils'; import { createHttpClient, getAppEnvConfig } from '@/utils';
import type { AxiosError } from 'axios'; import type { AxiosError } from 'axios';
export const ndmClient = new RequestClient({ export const ndmClient = createHttpClient({
requestInterceptor: async (config) => { requestInterceptor: async (config) => {
const userStore = useUserStore(); const userStore = useUserStore();
const { lampAuthorization, lampClientId, lampClientSecret } = getAppEnvConfig(); const { lampAuthorization, lampClientId, lampClientSecret } = getAppEnvConfig();
@@ -25,7 +25,7 @@ export const ndmClient = new RequestClient({
const userStore = useUserStore(); const userStore = useUserStore();
await userStore.lampLogin(stationCode); await userStore.lampLogin(stationCode);
error.config.headers.token = userStore.lampLoginResultRecord?.[stationCode]?.token ?? ''; error.config.headers.token = userStore.lampLoginResultRecord?.[stationCode]?.token ?? '';
return ndmClient.requestInstance(error.config); return ndmClient.clientInstance(error.config);
} }
return Promise.reject(error); return Promise.reject(error);
}, },

View File

@@ -1,9 +1,9 @@
import router from '@/router'; import router from '@/router';
import { useUserStore } from '@/stores'; import { useUserStore } from '@/stores';
import { getAppEnvConfig, RequestClient } from '@/utils'; import { createHttpClient, getAppEnvConfig } from '@/utils';
import type { AxiosError } from 'axios'; import type { AxiosError } from 'axios';
export const userClient = new RequestClient({ export const userClient = createHttpClient({
requestInterceptor: (config) => { requestInterceptor: (config) => {
const userStore = useUserStore(); const userStore = useUserStore();
const { lampAuthorization, lampClientId, lampClientSecret } = getAppEnvConfig(); const { lampAuthorization, lampClientId, lampClientSecret } = getAppEnvConfig();

View File

@@ -2,11 +2,38 @@ import type { BaseModel, ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO
import type { Nullable } from '@/types'; import type { Nullable } from '@/types';
export interface NdmCallLog extends BaseModel { export interface NdmCallLog extends BaseModel {
/**
* 调用者国标码
*/
sourceGbId: string; sourceGbId: string;
/**
* 用户所属类别
*/
sourceType: string;
/**
* 被调用设备国标码
*/
targetGbId: string; targetGbId: string;
/**
* 被调用设备名称
*/
targetName: string;
/**
* 调用方法
*/
method: string; method: string;
/**
* message类型
*/
messageType: string; messageType: string;
/**
* 操作类型
*/
cmdType: string; cmdType: string;
/**
* 日志类型
*/
logType: string;
} }
export type NdmCallLogResultVO = Nullable<NdmCallLog>; export type NdmCallLogResultVO = Nullable<NdmCallLog>;

View File

@@ -2,18 +2,57 @@ import type { BaseModel, ReduceForSaveVO, ReduceForUpdateVO, ReduceForPageQuery
import type { Nullable } from '@/types'; import type { Nullable } from '@/types';
export interface NdmVimpLog extends BaseModel { export interface NdmVimpLog extends BaseModel {
/**
* 请求IP
*/
requestIp: string; requestIp: string;
/**
* 操作内容
*/
description: string; description: string;
/**
* 类路径
*/
classPath: string; classPath: string;
/**
* 函数名
*/
methodName: string; methodName: string;
/**
* 起始时间
*/
startTime: string; startTime: string;
/**
* 结束时间
*/
endTime: string; endTime: string;
/**
* 消耗时间
*/
consumedTime: string; consumedTime: string;
/**
* 操作参数
*/
params: string; params: string;
/**
* 操作结果
*/
result: string; result: string;
/**
* 请求类型
*/
httpMethod: string; httpMethod: string;
/**
* 请求用户
*/
userId: string; userId: string;
/**
* 日志类型
*/
logType: number; logType: number;
/**
* 目标国标码
*/
targetCode: string; targetCode: string;
} }

View File

@@ -1,5 +1,5 @@
import { ndmClient, userClient, type Station } from '@/apis'; import { ndmClient, userClient, type Station } from '@/apis';
import { unwrapResponse } from '@/utils'; import { unwrapVoidResponse } from '@/utils';
export const resetMonitorScheduleApi = async (options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { export const resetMonitorScheduleApi = async (options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
const { stationCode, signal } = options ?? {}; const { stationCode, signal } = options ?? {};
@@ -7,5 +7,5 @@ export const resetMonitorScheduleApi = async (options?: { stationCode?: Station[
const prefix = stationCode ? `/${stationCode}` : ''; const prefix = stationCode ? `/${stationCode}` : '';
const endpoint = `${prefix}/api/ndm/ndmConstant/anyTenant/resetMonitorSchedule`; const endpoint = `${prefix}/api/ndm/ndmConstant/anyTenant/resetMonitorSchedule`;
const resp = await client.get<void>(endpoint, { signal }); const resp = await client.get<void>(endpoint, { signal });
unwrapResponse(resp); unwrapVoidResponse(resp);
}; };

View File

@@ -1,5 +1,5 @@
import { ndmClient, userClient, type Station } from '@/apis'; import { ndmClient, userClient, type Station } from '@/apis';
import { unwrapResponse } from '@/utils'; import { unwrapVoidResponse } from '@/utils';
export const verifyApi = async (options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { export const verifyApi = async (options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
const { stationCode, signal } = options ?? {}; const { stationCode, signal } = options ?? {};
@@ -7,5 +7,5 @@ export const verifyApi = async (options?: { stationCode?: Station['code']; signa
const prefix = stationCode ? `/${stationCode}` : ''; const prefix = stationCode ? `/${stationCode}` : '';
const endpoint = `${prefix}/api/ndm/ndmKeepAlive/verify`; const endpoint = `${prefix}/api/ndm/ndmKeepAlive/verify`;
const resp = await client.post<void>(endpoint, {}, { retRaw: true, timeout: 5000, signal }); const resp = await client.post<void>(endpoint, {}, { retRaw: true, timeout: 5000, signal });
unwrapResponse(resp); unwrapVoidResponse(resp);
}; };

View File

@@ -10,7 +10,7 @@ import {
type PageResult, type PageResult,
type Station, type Station,
} from '@/apis'; } from '@/apis';
import { unwrapResponse } from '@/utils'; import { unwrapResponse, unwrapVoidResponse } from '@/utils';
export const pageSecurityBoxApi = async (pageQuery: PageParams<NdmSecurityBoxPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { export const pageSecurityBoxApi = async (pageQuery: PageParams<NdmSecurityBoxPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
const { stationCode, signal } = options ?? {}; const { stationCode, signal } = options ?? {};
@@ -90,7 +90,7 @@ export const probeSecurityBoxApi = async (ids: string[], options?: { stationCode
const prefix = stationCode ? `/${stationCode}` : ''; const prefix = stationCode ? `/${stationCode}` : '';
const endpoint = `${prefix}/api/ndm/ndmSecurityBox/probeByIds`; const endpoint = `${prefix}/api/ndm/ndmSecurityBox/probeByIds`;
const resp = await client.post<void>(endpoint, ids, { signal }); const resp = await client.post<void>(endpoint, ids, { signal });
unwrapResponse(resp); unwrapVoidResponse(resp);
}; };
export const turnCitcuitStatusApi = async (ipAddress: string, circuitIndex: number, status: number, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { export const turnCitcuitStatusApi = async (ipAddress: string, circuitIndex: number, status: number, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {

View File

@@ -10,11 +10,11 @@ import {
type PageResult, type PageResult,
type Station, type Station,
} from '@/apis'; } from '@/apis';
import { unwrapResponse } from '@/utils'; import { unwrapResponse, unwrapVoidResponse } from '@/utils';
export const pageSwitchApi = async (pageQuery: PageParams<NdmSwitchPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { export const pageSwitchApi = async (pageQuery: PageParams<NdmSwitchPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
const { stationCode, signal } = options ?? {}; const { stationCode, signal } = options ?? {};
const client = stationCode ? ndmClient : ndmClient; const client = stationCode ? ndmClient : userClient;
const prefix = stationCode ? `/${stationCode}` : ''; const prefix = stationCode ? `/${stationCode}` : '';
const endpoint = `${prefix}/api/ndm/ndmSwitch/page`; const endpoint = `${prefix}/api/ndm/ndmSwitch/page`;
const resp = await client.post<PageResult<NdmSwitchResultVO>>(endpoint, pageQuery, { signal }); const resp = await client.post<PageResult<NdmSwitchResultVO>>(endpoint, pageQuery, { signal });
@@ -24,7 +24,7 @@ export const pageSwitchApi = async (pageQuery: PageParams<NdmSwitchPageQuery>, o
export const detailSwitchApi = async (id: string, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { export const detailSwitchApi = async (id: string, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
const { stationCode, signal } = options ?? {}; const { stationCode, signal } = options ?? {};
const client = stationCode ? ndmClient : ndmClient; const client = stationCode ? ndmClient : userClient;
const prefix = stationCode ? `/${stationCode}` : ''; const prefix = stationCode ? `/${stationCode}` : '';
const endpoint = `${prefix}/api/ndm/ndmSwitch/detail`; const endpoint = `${prefix}/api/ndm/ndmSwitch/detail`;
const resp = await client.get<NdmSwitchResultVO>(endpoint, { params: { id }, signal }); const resp = await client.get<NdmSwitchResultVO>(endpoint, { params: { id }, signal });
@@ -34,7 +34,7 @@ export const detailSwitchApi = async (id: string, options?: { stationCode?: Stat
export const saveSwitchApi = async (saveVO: NdmSwitchSaveVO, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { export const saveSwitchApi = async (saveVO: NdmSwitchSaveVO, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
const { stationCode, signal } = options ?? {}; const { stationCode, signal } = options ?? {};
const client = stationCode ? ndmClient : ndmClient; const client = stationCode ? ndmClient : userClient;
const prefix = stationCode ? `/${stationCode}` : ''; const prefix = stationCode ? `/${stationCode}` : '';
const endpoint = `${prefix}/api/ndm/ndmSwitch`; const endpoint = `${prefix}/api/ndm/ndmSwitch`;
const resp = await client.post<NdmSwitchResultVO>(endpoint, saveVO, { signal }); const resp = await client.post<NdmSwitchResultVO>(endpoint, saveVO, { signal });
@@ -44,7 +44,7 @@ export const saveSwitchApi = async (saveVO: NdmSwitchSaveVO, options?: { station
export const updateSwitchApi = async (updateVO: NdmSwitchUpdateVO, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { export const updateSwitchApi = async (updateVO: NdmSwitchUpdateVO, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
const { stationCode, signal } = options ?? {}; const { stationCode, signal } = options ?? {};
const client = stationCode ? ndmClient : ndmClient; const client = stationCode ? ndmClient : userClient;
const prefix = stationCode ? `/${stationCode}` : ''; const prefix = stationCode ? `/${stationCode}` : '';
const endpoint = `${prefix}/api/ndm/ndmSwitch`; const endpoint = `${prefix}/api/ndm/ndmSwitch`;
const resp = await client.put<NdmSwitchResultVO>(endpoint, updateVO, { signal }); const resp = await client.put<NdmSwitchResultVO>(endpoint, updateVO, { signal });
@@ -54,7 +54,7 @@ export const updateSwitchApi = async (updateVO: NdmSwitchUpdateVO, options?: { s
export const deleteSwitchApi = async (ids: string[], options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { export const deleteSwitchApi = async (ids: string[], options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
const { stationCode, signal } = options ?? {}; const { stationCode, signal } = options ?? {};
const client = stationCode ? ndmClient : ndmClient; const client = stationCode ? ndmClient : userClient;
const prefix = stationCode ? `/${stationCode}` : ''; const prefix = stationCode ? `/${stationCode}` : '';
const endpoint = `${prefix}/api/ndm/ndmSwitch`; const endpoint = `${prefix}/api/ndm/ndmSwitch`;
const resp = await client.delete<boolean>(endpoint, ids, { signal }); const resp = await client.delete<boolean>(endpoint, ids, { signal });
@@ -64,7 +64,7 @@ export const deleteSwitchApi = async (ids: string[], options?: { stationCode?: S
export const exportSwitchApi = async (pageQuery: PageParams<NdmSwitchPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { export const exportSwitchApi = async (pageQuery: PageParams<NdmSwitchPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
const { stationCode, signal } = options ?? {}; const { stationCode, signal } = options ?? {};
const client = stationCode ? ndmClient : ndmClient; const client = stationCode ? ndmClient : userClient;
const prefix = stationCode ? `/${stationCode}` : ''; const prefix = stationCode ? `/${stationCode}` : '';
const endpoint = `${prefix}/api/ndm/ndmSwitch/defaultExportByTemplate`; const endpoint = `${prefix}/api/ndm/ndmSwitch/defaultExportByTemplate`;
const resp = await client.post<Blob>(endpoint, pageQuery, { responseType: 'blob', retRaw: true, signal }); const resp = await client.post<Blob>(endpoint, pageQuery, { responseType: 'blob', retRaw: true, signal });
@@ -86,9 +86,9 @@ export const importSwitchApi = async (file: File, options?: { stationCode?: Stat
export const probeSwitchApi = async (ids: string[], options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { export const probeSwitchApi = async (ids: string[], options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
const { stationCode, signal } = options ?? {}; const { stationCode, signal } = options ?? {};
const client = stationCode ? ndmClient : ndmClient; const client = stationCode ? ndmClient : userClient;
const prefix = stationCode ? `/${stationCode}` : ''; const prefix = stationCode ? `/${stationCode}` : '';
const endpoint = `${prefix}/api/ndm/ndmSwitch/probeByIds`; const endpoint = `${prefix}/api/ndm/ndmSwitch/probeByIds`;
const resp = await client.post<void>(endpoint, ids, { signal }); const resp = await client.post<void>(endpoint, ids, { signal });
unwrapResponse(resp); unwrapVoidResponse(resp);
}; };

View File

@@ -1,5 +1,5 @@
import { ndmClient, userClient, type ImportMsg, type NdmNvrPageQuery, type NdmNvrResultVO, type NdmNvrSaveVO, type NdmNvrUpdateVO, type PageParams, type PageResult, type Station } from '@/apis'; import { ndmClient, userClient, type ImportMsg, type NdmNvrPageQuery, type NdmNvrResultVO, type NdmNvrSaveVO, type NdmNvrUpdateVO, type PageParams, type PageResult, type Station } from '@/apis';
import { unwrapResponse } from '@/utils'; import { unwrapResponse, unwrapVoidResponse } from '@/utils';
export const pageNvrPageApi = async (pageQuery: PageParams<NdmNvrPageQuery>, options?: { stationCode: Station['code']; signal?: AbortSignal }) => { export const pageNvrPageApi = async (pageQuery: PageParams<NdmNvrPageQuery>, options?: { stationCode: Station['code']; signal?: AbortSignal }) => {
const { stationCode, signal } = options ?? {}; const { stationCode, signal } = options ?? {};
@@ -79,7 +79,7 @@ export const probeNvrApi = async (ids: string[], options?: { stationCode?: Stati
const prefix = stationCode ? `/${stationCode}` : ''; const prefix = stationCode ? `/${stationCode}` : '';
const endpoint = `${prefix}/api/ndm/ndmNvr/probeByIds`; const endpoint = `${prefix}/api/ndm/ndmNvr/probeByIds`;
const resp = await client.post<void>(endpoint, ids, { signal }); const resp = await client.post<void>(endpoint, ids, { signal });
unwrapResponse(resp); unwrapVoidResponse(resp);
}; };
export const syncNvrChannelsApi = async (options?: { stationCode?: string; signal?: AbortSignal }) => { export const syncNvrChannelsApi = async (options?: { stationCode?: string; signal?: AbortSignal }) => {
@@ -88,5 +88,5 @@ export const syncNvrChannelsApi = async (options?: { stationCode?: string; signa
const prefix = stationCode ? `/${stationCode}` : ''; const prefix = stationCode ? `/${stationCode}` : '';
const endpoint = `${prefix}/api/ndm/ndmNvr/syncNvrChannels`; const endpoint = `${prefix}/api/ndm/ndmNvr/syncNvrChannels`;
const resp = await client.get<void>(endpoint, { signal }); const resp = await client.get<void>(endpoint, { signal });
unwrapResponse(resp); unwrapVoidResponse(resp);
}; };

View File

@@ -10,7 +10,7 @@ import {
type PageResult, type PageResult,
type Station, type Station,
} from '@/apis'; } from '@/apis';
import { unwrapResponse } from '@/utils'; import { unwrapResponse, unwrapVoidResponse } from '@/utils';
export const pageDecoderApi = async (pageQuery: PageParams<NdmDecoderPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { export const pageDecoderApi = async (pageQuery: PageParams<NdmDecoderPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
const { stationCode, signal } = options ?? {}; const { stationCode, signal } = options ?? {};
@@ -90,5 +90,5 @@ export const probeDecoderApi = async (ids: string[], options?: { stationCode?: S
const prefix = stationCode ? `/${stationCode}` : ''; const prefix = stationCode ? `/${stationCode}` : '';
const endpoint = `${prefix}/api/ndm/ndmDecoder/probeByIds`; const endpoint = `${prefix}/api/ndm/ndmDecoder/probeByIds`;
const resp = await client.post<void>(endpoint, ids, { signal }); const resp = await client.post<void>(endpoint, ids, { signal });
unwrapResponse(resp); unwrapVoidResponse(resp);
}; };

View File

@@ -10,7 +10,7 @@ import {
type PageResult, type PageResult,
type Station, type Station,
} from '@/apis'; } from '@/apis';
import { unwrapResponse } from '@/utils'; import { unwrapResponse, unwrapVoidResponse } from '@/utils';
export const postNdmMediaServerPage = async (pageQuery: PageParams<NdmMediaServerPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { export const postNdmMediaServerPage = async (pageQuery: PageParams<NdmMediaServerPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
const { stationCode, signal } = options ?? {}; const { stationCode, signal } = options ?? {};
@@ -90,5 +90,5 @@ export const probeMediaServerApi = async (ids: string[], options?: { stationCode
const prefix = stationCode ? `/${stationCode}` : ''; const prefix = stationCode ? `/${stationCode}` : '';
const endpoint = `${prefix}/api/ndm/ndmMediaServer/probeByIds`; const endpoint = `${prefix}/api/ndm/ndmMediaServer/probeByIds`;
const resp = await client.post<void>(endpoint, ids, { signal }); const resp = await client.post<void>(endpoint, ids, { signal });
unwrapResponse(resp); unwrapVoidResponse(resp);
}; };

View File

@@ -10,7 +10,7 @@ import {
type PageResult, type PageResult,
type Station, type Station,
} from '@/apis'; } from '@/apis';
import { unwrapResponse } from '@/utils'; import { unwrapResponse, unwrapVoidResponse } from '@/utils';
export const pageVideoServerApi = async (pageQuery: PageParams<NdmVideoServerPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { export const pageVideoServerApi = async (pageQuery: PageParams<NdmVideoServerPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
const { stationCode, signal } = options ?? {}; const { stationCode, signal } = options ?? {};
@@ -90,5 +90,5 @@ export const probeVideoServerApi = async (ids: string[], options?: { stationCode
const prefix = stationCode ? `/${stationCode}` : ''; const prefix = stationCode ? `/${stationCode}` : '';
const endpoint = `${prefix}/api/ndm/ndmVideoServer/probeByIds`; const endpoint = `${prefix}/api/ndm/ndmVideoServer/probeByIds`;
const resp = await client.post<void>(endpoint, ids, { signal }); const resp = await client.post<void>(endpoint, ids, { signal });
unwrapResponse(resp); unwrapVoidResponse(resp);
}; };

View File

@@ -142,8 +142,8 @@ const routeToRoot = () => {
const routeToAlarmPage = () => { const routeToAlarmPage = () => {
alarmStore.clearUnreadAlarms(); alarmStore.clearUnreadAlarms();
if (route.path !== '/alarm') { if (route.path !== '/alarm/alarm-log') {
router.push({ path: '/alarm' }); router.push({ path: '/alarm/alarm-log' });
} }
}; };

View File

@@ -300,7 +300,7 @@ onBeforeUnmount(() => {
<!-- 数据表格工具栏 --> <!-- 数据表格工具栏 -->
<NFlex align="center" style="padding: 8px; flex: 0 0 auto"> <NFlex align="center" style="padding: 8px; flex: 0 0 auto">
<div style="font-size: medium">视频平台日志</div> <div style="font-size: medium">告警忽略列表</div>
<NFlex style="margin-left: auto"> <NFlex style="margin-left: auto">
<!-- <NButton type="primary" :loading="exporting" @click="() => exportTableData()">导出</NButton> --> <!-- <NButton type="primary" :loading="exporting" @click="() => exportTableData()">导出</NButton> -->
</NFlex> </NFlex>

View File

@@ -348,7 +348,7 @@ onBeforeUnmount(() => {
<!-- 数据表格工具栏 --> <!-- 数据表格工具栏 -->
<NFlex align="center" style="padding: 8px; flex: 0 0 auto"> <NFlex align="center" style="padding: 8px; flex: 0 0 auto">
<div style="font-size: medium">视频平台日志</div> <div style="font-size: medium">设备告警记录</div>
<NFlex align="center" style="margin-left: auto"> <NFlex align="center" style="margin-left: auto">
<div>实时刷新</div> <div>实时刷新</div>
<NSwitch size="small" v-model:value="realtimeRefresh" /> <NSwitch size="small" v-model:value="realtimeRefresh" />

View File

@@ -1,3 +1,35 @@
<script lang="ts">
const callLogTypeOptions: SelectOption[] = [
{ label: '视频点播', value: 10001 },
{ label: '视频回放', value: 10002 },
// { label: '停止视频回放', value: 10003 },
// { label: '回放暂停', value: 10004 },
// { label: '回放恢复', value: 10005 },
// { label: '回放倍速播放', value: 10006 },
// { label: '回放拖动播放', value: 10007 },
{ label: '云台指令', value: 10008 },
{ label: '查询录像', value: 10009 },
{ label: '下载录像', value: 10010 },
// { label: '停止下载录像', value: 10011 },
{ label: '获取预置位', value: 10012 },
{ label: '获取设备信息', value: 10013 },
{ label: '获取设备状态', value: 10014 },
{ label: '设置解码器分屏数量', value: 20001 },
{ label: '设置解码器rtsp流', value: 20002 },
{ label: '移除解码器rtsp流', value: 20003 },
// { label: '启动非报警时序', value: 30001 },
// { label: '停止非报警时序', value: 30002 },
// { label: '暂停非报警时序', value: 30003 },
// { label: '调用组切', value: 30004 },
// { label: '启动报警时序', value: 40001 },
// { label: '停止报警时序', value: 40002 },
// { label: '分页查询报警', value: 50001 },
// { label: '确认报警', value: 50002 },
// { label: '删除报警', value: 50004 },
{ label: '目录查询', value: 60001 },
];
</script>
<script setup lang="ts"> <script setup lang="ts">
import { exportCallLogApi, pageCallLogApi, type NdmCallLog, type NdmCallLogResultVO, type PageQueryExtra, type Station } from '@/apis'; import { exportCallLogApi, pageCallLogApi, type NdmCallLog, type NdmCallLogResultVO, type PageQueryExtra, type Station } from '@/apis';
import { useStationStore } from '@/stores'; import { useStationStore } from '@/stores';
@@ -27,6 +59,7 @@ import { computed, reactive, ref, watch, watchEffect } from 'vue';
interface SearchFields extends PageQueryExtra<NdmCallLog> { interface SearchFields extends PageQueryExtra<NdmCallLog> {
stationCode?: Station['code']; stationCode?: Station['code'];
logType_in: number[];
createdTime: [string, string]; createdTime: [string, string];
} }
@@ -42,11 +75,13 @@ const stationSelectOptions = computed(() => {
}); });
const searchFields = ref<SearchFields>({ const searchFields = ref<SearchFields>({
logType_in: [],
createdTime: [dayjs().startOf('date').subtract(1, 'week').format('YYYY-MM-DD HH:mm:ss'), dayjs().endOf('date').format('YYYY-MM-DD HH:mm:ss')], 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 resetSearchFields = () => { const resetSearchFields = () => {
searchFields.value = { searchFields.value = {
stationCode: stations.value.find((station) => station.online)?.code, stationCode: onlineStations.value.at(0)?.code,
logType_in: [],
createdTime: [dayjs().startOf('date').subtract(1, 'week').format('YYYY-MM-DD HH:mm:ss'), dayjs().endOf('date').format('YYYY-MM-DD HH:mm:ss')], createdTime: [dayjs().startOf('date').subtract(1, 'week').format('YYYY-MM-DD HH:mm:ss'), dayjs().endOf('date').format('YYYY-MM-DD HH:mm:ss')],
}; };
}; };
@@ -58,6 +93,7 @@ const getExtraFields = (): PageQueryExtra<NdmCallLog> => {
const method_like = searchFields.value.method_like; const method_like = searchFields.value.method_like;
const messageType_like = searchFields.value.messageType_like; const messageType_like = searchFields.value.messageType_like;
const cmdType_like = searchFields.value.cmdType_like; const cmdType_like = searchFields.value.cmdType_like;
const logType_in = searchFields.value.logType_in;
return { return {
createdTime_precisest, createdTime_precisest,
createdTime_preciseed, createdTime_preciseed,
@@ -66,6 +102,7 @@ const getExtraFields = (): PageQueryExtra<NdmCallLog> => {
method_like, method_like,
messageType_like, messageType_like,
cmdType_like, cmdType_like,
logType_in,
}; };
}; };
@@ -76,8 +113,18 @@ watch(searchFields, () => {
const tableColumns: DataTableColumns<NdmCallLogResultVO> = [ const tableColumns: DataTableColumns<NdmCallLogResultVO> = [
{ title: '时间', key: 'createdTime' }, { title: '时间', key: 'createdTime' },
{
title: '日志类型',
key: 'logType',
render: (rowData) => {
const option = callLogTypeOptions.find((option) => option.value === rowData.logType);
return `${option?.label ?? ''}`;
},
},
{ title: '调用者国标码', key: 'sourceGbId' }, { title: '调用者国标码', key: 'sourceGbId' },
{ title: '用户所属类别', key: 'sourceType' },
{ title: '被调用设备国标码', key: 'targetGbId' }, { title: '被调用设备国标码', key: 'targetGbId' },
{ title: '被调用设备名称', key: 'targetName' },
{ title: '调用方法', key: 'method' }, { title: '调用方法', key: 'method' },
{ title: '消息类型', key: 'messageType' }, { title: '消息类型', key: 'messageType' },
{ title: '操作类型', key: 'cmdType' }, { title: '操作类型', key: 'cmdType' },
@@ -252,6 +299,9 @@ onBeforeUnmount(() => {
clearable clearable
/> />
</NFormItemGi> </NFormItemGi>
<NFormItemGi :span="1" label="日志类型" label-placement="left">
<NSelect v-model:value="searchFields.logType_in" :options="callLogTypeOptions" multiple clearable />
</NFormItemGi>
<NFormItemGi span="1" label="时间" label-placement="left"> <NFormItemGi span="1" label="时间" label-placement="left">
<NDatePicker v-model:formatted-value="searchFields.createdTime" type="datetimerange" /> <NDatePicker v-model:formatted-value="searchFields.createdTime" type="datetimerange" />
</NFormItemGi> </NFormItemGi>
@@ -269,7 +319,7 @@ onBeforeUnmount(() => {
<!-- 数据表格工具栏 --> <!-- 数据表格工具栏 -->
<NFlex align="center" style="padding: 8px; flex: 0 0 auto"> <NFlex align="center" style="padding: 8px; flex: 0 0 auto">
<div style="font-size: medium">视频平台日志</div> <div style="font-size: medium">上级调用日志</div>
<NFlex style="margin-left: auto"> <NFlex style="margin-left: auto">
<NButton type="primary" :loading="exporting" @click="() => exportTableData()">导出</NButton> <NButton type="primary" :loading="exporting" @click="() => exportTableData()">导出</NButton>
</NFlex> </NFlex>

View File

@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
const vimpOperationTypeOptions: SelectOption[] = [ const vimpLogTypeOptions: SelectOption[] = [
{ label: '视频点播', value: 10001 }, { label: '视频点播', value: 10001 },
{ label: '视频回放', value: 10002 }, { label: '视频回放', value: 10002 },
// { label: '停止视频回放', value: 10003 }, // { label: '停止视频回放', value: 10003 },
@@ -34,7 +34,6 @@ import { downloadByData, parseErrorFeedback } from '@/utils';
import { useMutation } from '@tanstack/vue-query'; import { useMutation } from '@tanstack/vue-query';
import { isCancel } from 'axios'; import { isCancel } from 'axios';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import destr from 'destr';
import { import {
NButton, NButton,
NDataTable, NDataTable,
@@ -44,8 +43,6 @@ import {
NFormItemGi, NFormItemGi,
NGrid, NGrid,
NGridItem, NGridItem,
NPopover,
NScrollbar,
NSelect, NSelect,
NTag, NTag,
type DataTableColumns, type DataTableColumns,
@@ -102,56 +99,17 @@ watch(searchFields, () => {
const tableColumns: DataTableColumns<NdmVimpLogResultVO> = [ const tableColumns: DataTableColumns<NdmVimpLogResultVO> = [
{ title: '时间', key: 'createdTime' }, { title: '时间', key: 'createdTime' },
{ title: '操作类型', key: 'description' }, {
title: '操作类型',
key: 'logType',
render: (rowData) => {
const option = vimpLogTypeOptions.find((option) => option.value === rowData.logType);
return `${option?.label ?? ''}`;
},
},
{ title: '请求IP', key: 'requestIp' }, { title: '请求IP', key: 'requestIp' },
{ title: '耗时(ms)', key: 'consumedTime' }, { title: '耗时(ms)', key: 'consumedTime' },
{ title: '被调用设备', key: 'targetCode' }, { title: '被调用设备', key: 'targetCode' },
{
title: '操作参数',
key: 'params',
width: 100,
render(rowData) {
const result = JSON.stringify(destr(rowData.params), null, 2);
return h(
NPopover,
{ trigger: 'click' },
{
trigger: () => h(NButton, { size: 'tiny', text: true, type: 'primary' }, { default: () => '查看' }),
default: () =>
h(
NScrollbar,
{ style: { maxHeight: '40vh' } },
{
default: () => h('pre', {}, { default: () => result }),
},
),
},
);
},
},
{
title: '操作结果',
key: 'result',
width: 100,
render: (rowData) => {
const result = JSON.stringify(destr(rowData.result), null, 2);
return h(
NPopover,
{ trigger: 'click' },
{
trigger: () => h(NButton, { size: 'tiny', text: true, type: 'primary' }, { default: () => '查看' }),
default: () =>
h(
NScrollbar,
{ style: { maxHeight: '40vh' } },
{
default: () => h('pre', {}, { default: () => result }),
},
),
},
);
},
},
]; ];
const tableData = ref<DataTableRowData[]>([]); const tableData = ref<DataTableRowData[]>([]);
@@ -323,8 +281,8 @@ onBeforeUnmount(() => {
clearable clearable
/> />
</NFormItemGi> </NFormItemGi>
<NFormItemGi :span="1" label="操作类型" label-placement="left"> <NFormItemGi :span="1" label="日志类型" label-placement="left">
<NSelect v-model:value="searchFields.logType_in" :options="vimpOperationTypeOptions" multiple clearable /> <NSelect v-model:value="searchFields.logType_in" :options="vimpLogTypeOptions" multiple clearable />
</NFormItemGi> </NFormItemGi>
<NFormItemGi span="1" label="时间" label-placement="left"> <NFormItemGi span="1" label="时间" label-placement="left">
<NDatePicker v-model:formatted-value="searchFields.createdTime" type="datetimerange" /> <NDatePicker v-model:formatted-value="searchFields.createdTime" type="datetimerange" />

View File

@@ -45,6 +45,16 @@ export const useSettingStore = defineStore(
if (!userStore.userLoginResult.token) { if (!userStore.userLoginResult.token) {
userStore.userLoginResult.token = 'test'; userStore.userLoginResult.token = 'test';
} }
if (!userStore.userInfo) {
userStore.userInfo = {
id: '2',
username: 'lamp',
nickName: '内置超管',
mobile: '15211111110',
employeeId: '2',
tenantId: '1',
};
}
if (router.currentRoute.value.path === '/login') { if (router.currentRoute.value.path === '/login') {
router.push({ path: '/' }); router.push({ path: '/' });
} }

View File

@@ -1,54 +1,41 @@
import type { Result } from '@/types'; import type { Result } from '@/types';
import axios, { isAxiosError, type AxiosError, type AxiosInstance, type AxiosRequestConfig, type AxiosResponse, type CreateAxiosDefaults, type InternalAxiosRequestConfig } from 'axios'; import axios, { isAxiosError, type AxiosError, type AxiosRequestConfig, type AxiosResponse, type CreateAxiosDefaults, type InternalAxiosRequestConfig } from 'axios';
export type Response<T> = [err: AxiosError | null, data: T | null, resp: Result<T> | null]; export type HttpResponse<T> = [err: AxiosError | null, data: T | null, resp: Result<T> | null];
export interface RequestOptions extends CreateAxiosDefaults { export interface HttpRequestOptions extends CreateAxiosDefaults {
requestInterceptor?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>; requestInterceptor?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>;
responseInterceptor?: (resp: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>; responseInterceptor?: (resp: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>;
responseErrorInterceptor?: (error: any) => any; responseErrorInterceptor?: (error: any) => any;
} }
export class RequestClient { export const createHttpClient = (config?: HttpRequestOptions) => {
private instance: AxiosInstance; const defaultRequestInterceptor = (config: InternalAxiosRequestConfig) => config;
const defaultResponseInterceptor = (response: AxiosResponse) => response;
constructor(config?: RequestOptions) { const defaultResponseErrorInterceptor = (error: any) => {
this.instance = axios.create(config); if (isAxiosError(error)) {
if (error.status === 401) {
const requestInterceptor = config?.requestInterceptor ?? RequestClient.defaultRequestInterceptor; // 处理 401 错误
const responseInterceptor = config?.responseInterceptor ?? RequestClient.defaultResponseInterceptor;
const responseErrorInterceptor = config?.responseErrorInterceptor ?? RequestClient.defaultResponseErrorInterceptor;
this.instance.interceptors.request.use(requestInterceptor);
this.instance.interceptors.response.use(responseInterceptor, responseErrorInterceptor);
} }
if (error.status === 404) {
private static defaultRequestInterceptor(config: InternalAxiosRequestConfig) { // 处理 404 错误
return config;
} }
private static defaultResponseInterceptor(response: AxiosResponse) {
return response;
}
private static defaultResponseErrorInterceptor(error: any) {
const err = error as AxiosError;
if (err.status === 401) {
}
if (err.status === 404) {
} }
return Promise.reject(error); return Promise.reject(error);
} };
public get requestInstance(): AxiosInstance { const requestInterceptor = config?.requestInterceptor ?? defaultRequestInterceptor;
return this.instance; const responseInterceptor = config?.responseInterceptor ?? defaultResponseInterceptor;
} const responseErrorInterceptor = config?.responseErrorInterceptor ?? defaultResponseErrorInterceptor;
get<T>(url: string, options?: AxiosRequestConfig & { retRaw?: boolean }): Promise<Response<T>> { const instance = axios.create(config);
instance.interceptors.request.use(requestInterceptor);
instance.interceptors.response.use(responseInterceptor, responseErrorInterceptor);
const httpGet = <T>(url: string, options?: AxiosRequestConfig & { retRaw?: boolean }): Promise<HttpResponse<T>> => {
const { retRaw, ...reqConfig } = options ?? {}; const { retRaw, ...reqConfig } = options ?? {};
return new Promise((resolve) => { return new Promise((resolve) => {
this.instance instance
.get(url, { .get(url, {
...reqConfig, ...reqConfig,
}) })
@@ -64,12 +51,12 @@ export class RequestClient {
resolve([err as AxiosError, null, null]); resolve([err as AxiosError, null, null]);
}); });
}); });
} };
post<T>(url: string, data?: AxiosRequestConfig['data'], options?: Partial<Omit<AxiosRequestConfig, 'data'>> & { retRaw?: boolean; upload?: boolean }): Promise<Response<T>> { const httpPost = <T>(url: string, data?: AxiosRequestConfig['data'], options?: Partial<Omit<AxiosRequestConfig, 'data'>> & { retRaw?: boolean; upload?: boolean }): Promise<HttpResponse<T>> => {
const { retRaw, upload, ...reqConfig } = options ?? {}; const { retRaw, upload, ...reqConfig } = options ?? {};
return new Promise((resolve) => { return new Promise((resolve) => {
this.instance instance
.post(url, data, { headers: { 'content-type': upload ? 'multipart/form-data' : 'application/json' }, ...reqConfig }) .post(url, data, { headers: { 'content-type': upload ? 'multipart/form-data' : 'application/json' }, ...reqConfig })
.then((res) => { .then((res) => {
const resData = res.data; const resData = res.data;
@@ -83,12 +70,12 @@ export class RequestClient {
resolve([err as AxiosError, null, null]); resolve([err as AxiosError, null, null]);
}); });
}); });
} };
put<T>(url: string, data?: AxiosRequestConfig['data'], options?: Partial<Omit<AxiosRequestConfig, 'data'>>): Promise<Response<T>> { const httpPut = <T>(url: string, data?: AxiosRequestConfig['data'], options?: Partial<Omit<AxiosRequestConfig, 'data'>>): Promise<HttpResponse<T>> => {
const reqConfig = options ?? {}; const reqConfig = options ?? {};
return new Promise((resolve) => { return new Promise((resolve) => {
this.instance instance
.put<Result<T>>(url, data, { ...reqConfig }) .put<Result<T>>(url, data, { ...reqConfig })
.then((res) => { .then((res) => {
resolve([null, res.data.data, res.data]); resolve([null, res.data.data, res.data]);
@@ -97,12 +84,12 @@ export class RequestClient {
resolve([err as AxiosError, null, null]); resolve([err as AxiosError, null, null]);
}); });
}); });
} };
delete<T>(url: string, idList: string[], options?: Partial<Omit<AxiosRequestConfig, 'data'>>): Promise<Response<T>> { const httpDelete = <T>(url: string, idList: string[], options?: Partial<Omit<AxiosRequestConfig, 'data'>>): Promise<HttpResponse<T>> => {
const reqConfig = options ?? {}; const reqConfig = options ?? {};
return new Promise((resolve) => { return new Promise((resolve) => {
this.instance instance
.delete<Result<T>>(url, { ...reqConfig, data: idList }) .delete<Result<T>>(url, { ...reqConfig, data: idList })
.then((res) => { .then((res) => {
resolve([null, res.data.data, res.data]); resolve([null, res.data.data, res.data]);
@@ -111,11 +98,21 @@ export class RequestClient {
resolve([err as AxiosError, null, null]); resolve([err as AxiosError, null, null]);
}); });
}); });
} };
}
return {
get clientInstance() {
return instance;
},
get: httpGet,
post: httpPost,
put: httpPut,
delete: httpDelete,
};
};
// 从响应中解析出数据 // 从响应中解析出数据
export const unwrapResponse = <T>(resp: Response<T>) => { export const unwrapResponse = <T>(resp: HttpResponse<T>) => {
const [err, data, result] = resp; const [err, data, result] = resp;
// 如果 err 存在说明有 http 错误,那么直接抛出错误, // 如果 err 存在说明有 http 错误,那么直接抛出错误,
@@ -139,6 +136,16 @@ export const unwrapResponse = <T>(resp: Response<T>) => {
return data; return data;
}; };
// 针对没有数据的响应,直接判断是否存在错误
export const unwrapVoidResponse = (resp: HttpResponse<void>) => {
const [err, , result] = resp;
if (err) throw err;
if (result) {
const { isSuccess, path, msg, errorMsg } = result;
if (!isSuccess) throw new Error(`${path ? `${path}: ` : ''}${msg || errorMsg || '请求失败'}`);
}
};
// 从错误中解析出错误信息 // 从错误中解析出错误信息
export const parseErrorFeedback = (error: Error) => { export const parseErrorFeedback = (error: Error) => {
// 当发生 http 错误时unwrapResponse 会直接抛出错误, // 当发生 http 错误时unwrapResponse 会直接抛出错误,

View File

@@ -4,5 +4,5 @@ export * from './download';
export * from './env'; export * from './env';
export * from './format-duration'; export * from './format-duration';
export * from './random-num'; export * from './random-num';
export * from './request-client'; export * from './http-client';
export * from './sleep'; export * from './sleep';