6 Commits

Author SHA1 Message Date
yangsy f78d3b32c0 feat(vimp): 新增资源面板组件并修正导入拼写错误
修复vimp页面资源面板组件的导入文件名拼写错误,新增的资源面板支持多标签资源分类、折叠展开切换以及对应标签页的搜索过滤功能。
2026-06-09 15:34:45 +08:00
yangsy ad9a0011a5 feat(vimp): 新增摄像头和告警通道的全局索引记录及构建方法
在摄像头、告警的Pinia存储中新增对应的数据记录与构建函数,并在渠道查询组合式函数中调用生成全局索引映射数据
2026-06-09 13:17:59 +08:00
yangsy 8403a41cef feat(settings-drawer): 为调试码输入框添加自动聚焦功能
更新了相关导入,添加输入框模板引用并在调试模态框打开时自动聚焦输入框
2026-06-09 13:16:33 +08:00
yangsy e8aa9b96f8 refactor(vimp): 重命名设备查询为通道查询并更新相关引用
- 新增 vimp 常量文件,定义查询键 VIMP_CHANNELS_QUERY_KEY
- 重命名设备中心查询组合式函数为通道查询组合式函数
- 更新 alarm-tree.vue 和 camera-tree.vue 中的查询调用
- 优化通道数据排序与存储更新流程
2026-06-08 14:40:58 +08:00
yangsy 6f14370751 refactor(vimp): 拆分站点模型为 VimpRawSite / VimpSite 并归一化 online 字段
- 将 VimpStation 重命名为 VimpSite,统一"站点"语义贯穿全模块
- 新增 VimpRawSite 表示 /catalog/allDevice 接口原样数据,online 字段可选
- 抽离 normalizeVimpSite 纯函数,集中处理 online 字段缺失时的默认值
- catalogAllDeviceApi 入参改为 VimpRawSite[],出参统一归一化为 VimpSite[] | null
- 下游 store、composable、树节点类型同步从 VimpStation 切换到 VimpSite
- 内部业务模型保持 online: boolean 必填,避免缺失字段沿调用链向下传播
2026-06-08 13:38:38 +08:00
yangsy 6fed499d78 feat(vimp客户端): 补充完整请求方法并添加统一认证与错误处理
- 新增VimpRequestOptions配置接口,支持自定义请求、响应及错误拦截器
- 补充get、put、delete请求方法并封装统一响应格式
- 添加默认请求拦截器自动携带公共认证参数
- 实现401错误拦截,超时自动跳转登录页并重置用户状态
2026-06-04 22:06:49 +08:00
17 changed files with 215 additions and 39 deletions
@@ -13,9 +13,27 @@ import destr from 'destr';
import { isFunction } from 'es-toolkit'; import { isFunction } from 'es-toolkit';
import localforage from 'localforage'; import localforage from 'localforage';
import { DownloadIcon, Trash2Icon, UploadIcon } from 'lucide-vue-next'; import { DownloadIcon, Trash2Icon, UploadIcon } from 'lucide-vue-next';
import { NButton, NButtonGroup, NDivider, NDrawer, NDrawerContent, NDropdown, NFlex, NFormItem, NIcon, NInput, NInputNumber, NModal, NSwitch, NText, NTooltip, type DropdownOption } from 'naive-ui'; import {
NButton,
NButtonGroup,
NDivider,
NDrawer,
NDrawerContent,
NDropdown,
NFlex,
NFormItem,
NIcon,
NInput,
NInputNumber,
NModal,
NSwitch,
NText,
NTooltip,
type DropdownOption,
type InputInst,
} from 'naive-ui';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { computed, ref, watch } from 'vue'; import { computed, nextTick, ref, useTemplateRef, watch } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
const router = useRouter(); const router = useRouter();
@@ -149,8 +167,14 @@ useEventListener('keydown', (event) => {
}); });
const expectToShowDebugCodeInput = ref(false); const expectToShowDebugCodeInput = ref(false);
const debugCodeInputRef = useTemplateRef<InputInst>('debug-code-input-ref');
const onModalAfterEnter = () => { const onModalAfterEnter = () => {
expectToShowDebugCodeInput.value = !debugMode.value; expectToShowDebugCodeInput.value = !debugMode.value;
if (expectToShowDebugCodeInput.value) {
nextTick(() => {
debugCodeInputRef.value?.focus();
});
}
}; };
const onModalAfterLeave = () => { const onModalAfterLeave = () => {
expectToShowDebugCodeInput.value = false; expectToShowDebugCodeInput.value = false;
@@ -412,7 +436,7 @@ const onClickVersion = () => {
<NText v-else>确认关闭调试模式</NText> <NText v-else>确认关闭调试模式</NText>
</template> </template>
<template #default> <template #default>
<NInput v-if="expectToShowDebugCodeInput" v-model:value="debugCode" placeholder="输入调试码" @keyup.enter="enableDebugMode" /> <NInput ref="debug-code-input-ref" v-if="expectToShowDebugCodeInput" v-model:value="debugCode" placeholder="输入调试码" @keyup.enter="enableDebugMode" />
</template> </template>
<template #action> <template #action>
<NButton @click="showDebugCodeModal = false">取消</NButton> <NButton @click="showDebugCodeModal = false">取消</NButton>
+110 -3
View File
@@ -1,9 +1,59 @@
import type { AxiosError, AxiosRequestConfig, CreateAxiosDefaults } from 'axios'; import type { AxiosError, AxiosRequestConfig, AxiosResponse, CreateAxiosDefaults, InternalAxiosRequestConfig } from 'axios';
import axios from 'axios'; import axios, { isAxiosError } from 'axios';
import type { VimpResponse, VimpResult } from '../../types'; import type { VimpResponse, VimpResult } from '../../types';
import { useUserStore } from '@/stores';
import { getAppEnvConfig } from '@/utils';
import router from '@/router';
export interface VimpRequestOptions extends CreateAxiosDefaults {
requestInterceptor?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>;
responseInterceptor?: (resp: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>;
responseErrorInterceptor?: (error: any) => any;
}
export const createVimpClient = (config?: VimpRequestOptions) => {
const defaultRequestInterceptor = (config: InternalAxiosRequestConfig) => config;
const defaultResponseInterceptor = (response: AxiosResponse) => response;
const defaultResponseErrorInterceptor = (error: any) => {
if (isAxiosError(error)) {
if (error.status === 401) {
// 处理 401 错误
}
if (error.status === 404) {
// 处理 404 错误
}
}
return Promise.reject(error);
};
const requestInterceptor = config?.requestInterceptor ?? defaultRequestInterceptor;
const responseInterceptor = config?.responseInterceptor ?? defaultResponseInterceptor;
const responseErrorInterceptor = config?.responseErrorInterceptor ?? defaultResponseErrorInterceptor;
export const createVimpClient = (config?: CreateAxiosDefaults) => {
const instance = axios.create(config); const instance = axios.create(config);
instance.interceptors.request.use(requestInterceptor);
instance.interceptors.response.use(responseInterceptor, responseErrorInterceptor);
const vimpGet = <T>(url: string, options?: AxiosRequestConfig & { retRaw?: boolean }): Promise<VimpResponse<T>> => {
const { retRaw, ...reqConfig } = options ?? {};
return new Promise((resolve) => {
instance
.get(url, {
...reqConfig,
})
.then((res) => {
if (retRaw) {
resolve([null, res.data as T, null]);
} else {
const resData = res.data as VimpResult<T>;
resolve([null, resData.data, resData]);
}
})
.catch((err) => {
resolve([err as AxiosError, null, null]);
});
});
};
const vimpPost = <T>(url: string, data?: AxiosRequestConfig['data'], options?: Partial<Omit<AxiosRequestConfig, 'data'>> & { retRaw?: boolean; upload?: boolean }): Promise<VimpResponse<T>> => { const vimpPost = <T>(url: string, data?: AxiosRequestConfig['data'], options?: Partial<Omit<AxiosRequestConfig, 'data'>> & { retRaw?: boolean; upload?: boolean }): Promise<VimpResponse<T>> => {
const { retRaw, upload, ...reqConfig } = options ?? {}; const { retRaw, upload, ...reqConfig } = options ?? {};
@@ -24,9 +74,40 @@ export const createVimpClient = (config?: CreateAxiosDefaults) => {
}); });
}; };
const httpPut = <T>(url: string, data?: AxiosRequestConfig['data'], options?: Partial<Omit<AxiosRequestConfig, 'data'>>): Promise<VimpResponse<T>> => {
const reqConfig = options ?? {};
return new Promise((resolve) => {
instance
.put<VimpResult<T>>(url, data, { ...reqConfig })
.then((res) => {
resolve([null, res.data.data, res.data]);
})
.catch((err) => {
resolve([err as AxiosError, null, null]);
});
});
};
const httpDelete = <T>(url: string, idList: string[], options?: Partial<Omit<AxiosRequestConfig, 'data'>>): Promise<VimpResponse<T>> => {
const reqConfig = options ?? {};
return new Promise((resolve) => {
instance
.delete<VimpResult<T>>(url, { ...reqConfig, data: idList })
.then((res) => {
resolve([null, res.data.data, res.data]);
})
.catch((err) => {
resolve([err as AxiosError, null, null]);
});
});
};
return { return {
instance, instance,
get: vimpGet,
post: vimpPost, post: vimpPost,
put: httpPut,
delete: httpDelete,
}; };
}; };
@@ -42,4 +123,30 @@ export const unwrapVimpResponse = <T>(resp: VimpResponse<T>) => {
export const vimpClient = createVimpClient({ export const vimpClient = createVimpClient({
baseURL: `/vimp/api/client`, baseURL: `/vimp/api/client`,
requestInterceptor: (config) => {
const userStore = useUserStore();
const { lampAuthorization, lampClientId, lampClientSecret } = getAppEnvConfig();
const newAuthorization = window.btoa(`${lampClientId}:${lampClientSecret}`);
const authorization = lampAuthorization.trim() !== '' ? lampAuthorization : newAuthorization;
config.headers.set('accept-language', 'zh-CN,zh;q=0.9');
config.headers.set('accept', 'application/json, text/plain, */*');
config.headers.set('Applicationid', '');
config.headers.set('Tenantid', '1');
config.headers.set('Authorization', authorization);
config.headers.set('token', userStore.userLoginResult?.token ?? '');
return config;
},
responseInterceptor: (response) => {
return response;
},
responseErrorInterceptor: (error) => {
const err = error as AxiosError;
if (err.response?.status === 401) {
window.$message.error('登录超时,请重新登录');
const userStore = useUserStore();
userStore.resetStore();
router.push({ path: '/login' });
}
return Promise.reject(error);
},
}); });
+1 -1
View File
@@ -1,2 +1,2 @@
export * from './vimp-channel'; export * from './vimp-channel';
export * from './vimp-station'; export * from './vimp-site';
+17
View File
@@ -0,0 +1,17 @@
export interface VimpRawSite {
code: string;
name: string;
online?: boolean;
}
export interface VimpSite {
code: string;
name: string;
online: boolean;
}
export const normalizeVimpSite = (site: VimpRawSite): VimpSite => ({
code: site.code,
name: site.name,
online: site.online ?? true,
});
@@ -1,5 +0,0 @@
export interface VimpStation {
code: string;
name: string;
online: boolean;
}
@@ -1,11 +1,11 @@
import { unwrapVimpResponse, vimpClient } from '../client'; import { unwrapVimpResponse, vimpClient } from '../client';
import type { VimpStation } from '../model'; import { normalizeVimpSite, type VimpRawSite } from '../model';
export const catalogAllDeviceApi = async (options?: { signal?: AbortSignal }) => { export const catalogAllDeviceApi = async (options?: { signal?: AbortSignal }) => {
const { signal } = options ?? {}; const { signal } = options ?? {};
const client = vimpClient; const client = vimpClient;
const endpoint = `/catalog/allDevice`; const endpoint = `/catalog/allDevice`;
const resp = await client.post<VimpStation[]>(endpoint, {}, { signal }); const resp = await client.post<VimpRawSite[]>(endpoint, {}, { signal });
const data = unwrapVimpResponse(resp); const data = unwrapVimpResponse(resp);
return data; return data?.map(normalizeVimpSite) ?? null;
}; };
+2 -2
View File
@@ -3,11 +3,11 @@ import { NIcon, NTabPane, NTabs, NTree, type TreeOverrideNodeClickBehavior, type
import { h, type CSSProperties } from 'vue'; import { h, type CSSProperties } from 'vue';
import { useAlarmStore, useResourcePanelStore } from '../stores'; import { useAlarmStore, useResourcePanelStore } from '../stores';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useDeviceCenterQuery } from '../composables'; import { useChannelsQuery } from '../composables';
import { isAlarmNode, isAlarmSiteNode, isAlarmAreaNode } from '../types'; import { isAlarmNode, isAlarmSiteNode, isAlarmAreaNode } from '../types';
import { SirenIcon } from 'lucide-vue-next'; import { SirenIcon } from 'lucide-vue-next';
const { isLoading } = useDeviceCenterQuery(); const { isLoading } = useChannelsQuery();
const alarmStore = useAlarmStore(); const alarmStore = useAlarmStore();
const { lineTabPanes } = storeToRefs(alarmStore); const { lineTabPanes } = storeToRefs(alarmStore);
+2 -2
View File
@@ -3,13 +3,13 @@ import { NIcon, NTabPane, NTabs, NTree, type TreeOverrideNodeClickBehavior, type
import { h, type CSSProperties } from 'vue'; import { h, type CSSProperties } from 'vue';
import { useCameraStore, useResourcePanelStore } from '../stores'; import { useCameraStore, useResourcePanelStore } from '../stores';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useDeviceCenterQuery } from '../composables'; import { useChannelsQuery } from '../composables';
import { isCameraNode, isCameraSiteNode, isCameraAreaNode } from '../types'; import { isCameraNode, isCameraSiteNode, isCameraAreaNode } from '../types';
import PtzCamera from './icon/ptz-camera.vue'; import PtzCamera from './icon/ptz-camera.vue';
import HemiPtzCamera from './icon/hemi-ptz-camera.vue'; import HemiPtzCamera from './icon/hemi-ptz-camera.vue';
import BulletCamera from './icon/bullet-camera.vue'; import BulletCamera from './icon/bullet-camera.vue';
const { isLoading } = useDeviceCenterQuery(); const { isLoading } = useChannelsQuery();
const cameraStore = useCameraStore(); const cameraStore = useCameraStore();
const { lineTabPanes } = storeToRefs(cameraStore); const { lineTabPanes } = storeToRefs(cameraStore);
+1 -1
View File
@@ -1 +1 @@
export * from './use-device-center-query'; export * from './use-channels-query';
@@ -4,7 +4,8 @@ import type { AxiosRequestConfig } from 'axios';
import axios from 'axios'; import axios from 'axios';
import { compileCodeAreas, type CodeArea, type CodeLines, type CodeSites } from '../../types'; import { compileCodeAreas, type CodeArea, type CodeLines, type CodeSites } from '../../types';
import { useCameraStore, useAlarmStore } from '../../stores'; import { useCameraStore, useAlarmStore } from '../../stores';
import { catalogAllDeviceApi, catalogChannelApi, type VimpChannel, type VimpStation } from '../../apis'; import { catalogAllDeviceApi, catalogChannelApi, type VimpChannel, type VimpSite } from '../../apis';
import { VIMP_CHANNELS_QUERY_KEY } from '../../constants';
const config: AxiosRequestConfig = { const config: AxiosRequestConfig = {
headers: { headers: {
@@ -35,7 +36,7 @@ const compareByCode = <T extends { code: string }>(a: T, b: T) => {
if (a.code > b.code) return 1; if (a.code > b.code) return 1;
return 0; return 0;
}; };
const sortSitesByCode = (sites: VimpStation[]) => { const sortSitesByCode = (sites: VimpSite[]) => {
sites.sort(compareByCode); sites.sort(compareByCode);
}; };
const sortChannelsMapByCode = (siteCodeToChannelsMap: Map<string, VimpChannel[]>) => { const sortChannelsMapByCode = (siteCodeToChannelsMap: Map<string, VimpChannel[]>) => {
@@ -44,12 +45,12 @@ const sortChannelsMapByCode = (siteCodeToChannelsMap: Map<string, VimpChannel[]>
} }
}; };
export const useDeviceCenterQuery = () => { export const useChannelsQuery = () => {
const cameraStore = useCameraStore(); const cameraStore = useCameraStore();
const alarmStore = useAlarmStore(); const alarmStore = useAlarmStore();
return useQuery({ return useQuery({
queryKey: computed(() => ['vimp-device']), queryKey: computed(() => [VIMP_CHANNELS_QUERY_KEY]),
refetchInterval: 10 * 1000, refetchInterval: 10 * 1000,
refetchOnWindowFocus: false, refetchOnWindowFocus: false,
queryFn: async ({ signal }) => { queryFn: async ({ signal }) => {
@@ -73,8 +74,8 @@ export const useDeviceCenterQuery = () => {
// 从 /allDevice 接口获取的站点信息并不保证真实性和完整性, // 从 /allDevice 接口获取的站点信息并不保证真实性和完整性,
// 例如有一个站点的编码是 010699 开头,但是其下的通道是 010199 和 010599 开头, // 例如有一个站点的编码是 010699 开头,但是其下的通道是 010199 和 010599 开头,
// 而 010699 是一个不存在的站点编码,所以需要基于通道的编码来确定所有的站点。 // 而 010699 是一个不存在的站点编码,所以需要基于通道的编码来确定所有的站点。
const cameraSites: VimpStation[] = []; const cameraSites: VimpSite[] = [];
const alarmSites: VimpStation[] = []; const alarmSites: VimpSite[] = [];
const cameraBuiltSitesSet = new Set<string>(); const cameraBuiltSitesSet = new Set<string>();
const alarmBuiltSitesSet = new Set<string>(); const alarmBuiltSitesSet = new Set<string>();
const siteCodeToCamerasMap = new Map<string, VimpChannel[]>(); const siteCodeToCamerasMap = new Map<string, VimpChannel[]>();
@@ -133,6 +134,7 @@ export const useDeviceCenterQuery = () => {
codeSites, codeSites,
compiledCodeAreas, compiledCodeAreas,
}); });
cameraStore.buildCameraRecord(siteCodeToCamerasMap);
alarmStore.buildLineTabPanes({ alarmStore.buildLineTabPanes({
sites: alarmSites, sites: alarmSites,
@@ -141,6 +143,7 @@ export const useDeviceCenterQuery = () => {
codeSites, codeSites,
compiledCodeAreas, compiledCodeAreas,
}); });
alarmStore.buildAlarmRecord(siteCodeToAlarmsMap);
return null; return null;
}, },
+1
View File
@@ -0,0 +1 @@
export * from './query';
+1
View File
@@ -0,0 +1 @@
export const VIMP_CHANNELS_QUERY_KEY = 'vimp-channels';
+16 -2
View File
@@ -1,10 +1,10 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import type { VimpChannel, VimpStation } from '../apis'; import type { VimpChannel, VimpSite } from '../apis';
import { shallowRef } from 'vue'; import { shallowRef } from 'vue';
import type { AlarmMainAreaNodeOption, AlarmNodeOption, CodeLines, CodeSites, AlarmLineTabPane, AlarmSiteNodeOption, AlarmSubAreaNodeOption, CompiledCodeAreas } from '../types'; import type { AlarmMainAreaNodeOption, AlarmNodeOption, CodeLines, CodeSites, AlarmLineTabPane, AlarmSiteNodeOption, AlarmSubAreaNodeOption, CompiledCodeAreas } from '../types';
interface BuildLineTabPanesParams { interface BuildLineTabPanesParams {
sites: VimpStation[]; sites: VimpSite[];
siteCodeToAlarmsMap: Map<string, VimpChannel[]>; siteCodeToAlarmsMap: Map<string, VimpChannel[]>;
codeLines: CodeLines; codeLines: CodeLines;
codeSites: CodeSites; codeSites: CodeSites;
@@ -16,6 +16,7 @@ const buildSubAreaNodeKey = (siteCode: string, areaCode: string) => `${siteCode}
export const useAlarmStore = defineStore('vimp-alarm-store', () => { export const useAlarmStore = defineStore('vimp-alarm-store', () => {
const lineTabPanes = shallowRef<AlarmLineTabPane[]>([]); const lineTabPanes = shallowRef<AlarmLineTabPane[]>([]);
const alarmRecord = shallowRef<Record<string, VimpChannel>>({});
const buildLineTabPanes = (params: BuildLineTabPanesParams) => { const buildLineTabPanes = (params: BuildLineTabPanesParams) => {
const { sites, siteCodeToAlarmsMap, codeLines, codeSites, compiledCodeAreas } = params; const { sites, siteCodeToAlarmsMap, codeLines, codeSites, compiledCodeAreas } = params;
@@ -154,8 +155,21 @@ export const useAlarmStore = defineStore('vimp-alarm-store', () => {
lineTabPanes.value = result; lineTabPanes.value = result;
}; };
const buildAlarmRecord = (siteCodeToAlarmsMap: Map<string, VimpChannel[]>) => {
const record: Record<string, VimpChannel> = {};
for (const [, alarms] of siteCodeToAlarmsMap) {
for (const alarm of alarms) {
record[alarm.code] = alarm;
}
}
alarmRecord.value = record;
};
return { return {
lineTabPanes, lineTabPanes,
alarmRecord,
buildLineTabPanes, buildLineTabPanes,
buildAlarmRecord,
}; };
}); });
+17 -3
View File
@@ -1,10 +1,10 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import type { VimpChannel, VimpStation } from '../apis'; import type { VimpChannel, VimpSite } from '../apis';
import { shallowRef } from 'vue'; import { ref, shallowRef } from 'vue';
import type { CameraMainAreaNodeOption, CameraNodeOption, CodeLines, CodeSites, CameraLineTabPane, CameraSiteNodeOption, CameraSubAreaNodeOption, CompiledCodeAreas } from '../types'; import type { CameraMainAreaNodeOption, CameraNodeOption, CodeLines, CodeSites, CameraLineTabPane, CameraSiteNodeOption, CameraSubAreaNodeOption, CompiledCodeAreas } from '../types';
interface BuildLineTabPanesParams { interface BuildLineTabPanesParams {
sites: VimpStation[]; sites: VimpSite[];
siteCodeToCamerasMap: Map<string, VimpChannel[]>; siteCodeToCamerasMap: Map<string, VimpChannel[]>;
codeLines: CodeLines; codeLines: CodeLines;
codeSites: CodeSites; codeSites: CodeSites;
@@ -16,6 +16,7 @@ const buildSubAreaNodeKey = (siteCode: string, areaCode: string) => `${siteCode}
export const useCameraStore = defineStore('vimp-camera-store', () => { export const useCameraStore = defineStore('vimp-camera-store', () => {
const lineTabPanes = shallowRef<CameraLineTabPane[]>([]); const lineTabPanes = shallowRef<CameraLineTabPane[]>([]);
const cameraRecord = shallowRef<Record<string, VimpChannel>>({});
const buildLineTabPanes = (params: BuildLineTabPanesParams) => { const buildLineTabPanes = (params: BuildLineTabPanesParams) => {
const { sites, siteCodeToCamerasMap, codeLines, codeSites, compiledCodeAreas } = params; const { sites, siteCodeToCamerasMap, codeLines, codeSites, compiledCodeAreas } = params;
@@ -153,8 +154,21 @@ export const useCameraStore = defineStore('vimp-camera-store', () => {
lineTabPanes.value = result; lineTabPanes.value = result;
}; };
const buildCameraRecord = (siteCodeToCamerasMap: Map<string, VimpChannel[]>) => {
const record: Record<string, VimpChannel> = {};
for (const [, cameras] of siteCodeToCamerasMap) {
for (const camera of cameras) {
record[camera.code] = camera;
}
}
cameraRecord.value = record;
};
return { return {
lineTabPanes, lineTabPanes,
cameraRecord,
buildLineTabPanes, buildLineTabPanes,
buildCameraRecord,
}; };
}); });
+7 -7
View File
@@ -1,5 +1,5 @@
import type { TabPaneProps, TreeOption } from 'naive-ui'; import type { TabPaneProps, TreeOption } from 'naive-ui';
import type { VimpChannel, VimpStation } from '../apis/model'; import type { VimpChannel, VimpSite } from '../apis/model';
export type SiteType = 'station' | 'parking' | 'occ' | 'train'; export type SiteType = 'station' | 'parking' | 'occ' | 'train';
export type CodeLines = Record<string, { name: string; color: string }>; export type CodeLines = Record<string, { name: string; color: string }>;
@@ -57,20 +57,20 @@ export interface CountStats {
export interface CameraNodeOption extends TreeOption { export interface CameraNodeOption extends TreeOption {
camera: VimpChannel; camera: VimpChannel;
type: string; type: string;
site: VimpStation; site: VimpSite;
} }
export interface CameraSubAreaNodeOption extends TreeOption { export interface CameraSubAreaNodeOption extends TreeOption {
children?: CameraNodeOption[]; children?: CameraNodeOption[];
stats: CountStats; stats: CountStats;
site: VimpStation; site: VimpSite;
areaLevel: 2; areaLevel: 2;
} }
export interface CameraMainAreaNodeOption extends TreeOption { export interface CameraMainAreaNodeOption extends TreeOption {
children?: CameraSubAreaNodeOption[]; children?: CameraSubAreaNodeOption[];
stats: CountStats; stats: CountStats;
site: VimpStation; site: VimpSite;
areaLevel: 1; areaLevel: 1;
} }
@@ -104,20 +104,20 @@ export interface CameraLineTabPane extends TabPaneProps {
export interface AlarmNodeOption extends TreeOption { export interface AlarmNodeOption extends TreeOption {
alarm: VimpChannel; alarm: VimpChannel;
type: string; type: string;
site: VimpStation; site: VimpSite;
} }
export interface AlarmSubAreaNodeOption extends TreeOption { export interface AlarmSubAreaNodeOption extends TreeOption {
children?: AlarmNodeOption[]; children?: AlarmNodeOption[];
stats: CountStats; stats: CountStats;
site: VimpStation; site: VimpSite;
areaLevel: 2; areaLevel: 2;
} }
export interface AlarmMainAreaNodeOption extends TreeOption { export interface AlarmMainAreaNodeOption extends TreeOption {
children?: AlarmSubAreaNodeOption[]; children?: AlarmSubAreaNodeOption[];
stats: CountStats; stats: CountStats;
site: VimpStation; site: VimpSite;
areaLevel: 1; areaLevel: 1;
} }
+1 -1
View File
@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import ResourcePanel from './components/resource-pannel.vue'; import ResourcePanel from './components/resource-panel.vue';
const onDragover = (event: DragEvent) => { const onDragover = (event: DragEvent) => {
event.preventDefault(); event.preventDefault();