perf(vimp): 预编译码表区域索引优化查询性能
- 新增compileCodeAreas工具函数,将区域数据预构建为Map索引,降低区域查找的时间复杂度 - 重构camera store,移除冗余的区域遍历查找逻辑,改用预编译索引数据 新增节点areaLevel字段,适配不同层级节点的统计后缀样式间距 - 将摄像头图标和节点统计后缀的渲染逻辑迁移至camera-tree组件 - 清理调试控制台日志,简化空通道判断逻辑
This commit is contained in:
@@ -1,10 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { NTabPane, NTabs, NTree, type TreeOverrideNodeClickBehavior, type TreeProps } from 'naive-ui';
|
import { NIcon, NTabPane, NTabs, NTree, type TreeOverrideNodeClickBehavior, type TreeProps } from 'naive-ui';
|
||||||
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 { useDeviceCenterQuery } from '../composables';
|
||||||
import { isCameraNode, isCameraSiteNode, isCameraAreaNode } from '../types';
|
import { isCameraNode, isCameraSiteNode, isCameraAreaNode } from '../types';
|
||||||
|
import PtzCamera from './icon/ptz-camera.vue';
|
||||||
|
import HemiPtzCamera from './icon/hemi-ptz-camera.vue';
|
||||||
|
import BulletCamera from './icon/bullet-camera.vue';
|
||||||
|
|
||||||
const { isLoading } = useDeviceCenterQuery();
|
const { isLoading } = useDeviceCenterQuery();
|
||||||
|
|
||||||
@@ -77,6 +80,31 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
|
|||||||
return option.label;
|
return option.label;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderNodePrefix: TreeProps['renderPrefix'] = ({ option }) => {
|
||||||
|
if (!isCameraNode(option)) return null;
|
||||||
|
|
||||||
|
if (option.type === '004') return h(NIcon, () => h(PtzCamera));
|
||||||
|
if (option.type === '005') return h(NIcon, () => h(HemiPtzCamera));
|
||||||
|
if (option.type === '006') return h(NIcon, () => h(BulletCamera));
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderNodeSuffix: TreeProps['renderSuffix'] = ({ option }) => {
|
||||||
|
if (isCameraSiteNode(option)) {
|
||||||
|
const { online, offline, total } = option.stats;
|
||||||
|
return `(${online}/${offline}/${total})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCameraAreaNode(option)) {
|
||||||
|
const { online, offline, total } = option.stats;
|
||||||
|
const suffixStyle: CSSProperties = option.areaLevel === 1 ? { marginRight: '8px', opacity: 0.6 } : { marginRight: '16px', opacity: 0.4 };
|
||||||
|
return h('div', { style: suffixStyle }, `(${online}/${offline}/${total})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
const resourcePanelStore = useResourcePanelStore();
|
const resourcePanelStore = useResourcePanelStore();
|
||||||
const { searchPattern } = storeToRefs(resourcePanelStore);
|
const { searchPattern } = storeToRefs(resourcePanelStore);
|
||||||
|
|
||||||
@@ -98,6 +126,8 @@ const searchFilter: TreeProps['filter'] = (pattern, node) => {
|
|||||||
virtual-scroll
|
virtual-scroll
|
||||||
style="height: 100%"
|
style="height: 100%"
|
||||||
:render-label="renderNodeLabel"
|
:render-label="renderNodeLabel"
|
||||||
|
:render-prefix="renderNodePrefix"
|
||||||
|
:render-suffix="renderNodeSuffix"
|
||||||
:override-default-node-click-behavior="overrideNodeClickBehavior"
|
:override-default-node-click-behavior="overrideNodeClickBehavior"
|
||||||
:default-expand-all="searchPattern.trim().length > 0"
|
:default-expand-all="searchPattern.trim().length > 0"
|
||||||
:show-irrelevant-nodes="false"
|
:show-irrelevant-nodes="false"
|
||||||
@@ -116,6 +146,8 @@ const searchFilter: TreeProps['filter'] = (pattern, node) => {
|
|||||||
virtual-scroll
|
virtual-scroll
|
||||||
style="height: 100%"
|
style="height: 100%"
|
||||||
:render-label="renderNodeLabel"
|
:render-label="renderNodeLabel"
|
||||||
|
:render-prefix="renderNodePrefix"
|
||||||
|
:render-suffix="renderNodeSuffix"
|
||||||
:override-default-node-click-behavior="overrideNodeClickBehavior"
|
:override-default-node-click-behavior="overrideNodeClickBehavior"
|
||||||
:default-expand-all="false"
|
:default-expand-all="false"
|
||||||
:show-irrelevant-nodes="false"
|
:show-irrelevant-nodes="false"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/vue-query';
|
|||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import type { AxiosRequestConfig } from 'axios';
|
import type { AxiosRequestConfig } from 'axios';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import type { CodeArea, CodeLines, CodeSites } from '../../types';
|
import { compileCodeAreas, type CodeArea, type CodeLines, type CodeSites, type CompiledCodeAreaMaps, type CompiledCodeAreas } 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 VimpStation } from '../../apis';
|
||||||
|
|
||||||
@@ -39,12 +39,20 @@ export const useDeviceCenterQuery = () => {
|
|||||||
refetchInterval: 10 * 1000,
|
refetchInterval: 10 * 1000,
|
||||||
refetchOnWindowFocus: false,
|
refetchOnWindowFocus: false,
|
||||||
queryFn: async ({ signal }) => {
|
queryFn: async ({ signal }) => {
|
||||||
|
// 请求所有码表
|
||||||
const codeLines = (await axios.get<CodeLines>('/cdn/vimp/codes/codeLines.json', config)).data;
|
const codeLines = (await axios.get<CodeLines>('/cdn/vimp/codes/codeLines.json', config)).data;
|
||||||
const codeSites = (await axios.get<CodeSites>('/cdn/vimp/codes/codeStations.json', config)).data;
|
const codeSites = (await axios.get<CodeSites>('/cdn/vimp/codes/codeStations.json', config)).data;
|
||||||
const codeStationAreas = (await axios.get<CodeArea[]>('/cdn/vimp/codes/codeStationAreas.json', config)).data;
|
const codeStationAreas = (await axios.get<CodeArea[]>('/cdn/vimp/codes/codeStationAreas.json', config)).data;
|
||||||
const codeParkingAreas = (await axios.get<CodeArea[]>('/cdn/vimp/codes/codeParkingAreas.json', config)).data;
|
const codeParkingAreas = (await axios.get<CodeArea[]>('/cdn/vimp/codes/codeParkingAreas.json', config)).data;
|
||||||
const codeOccAreas = (await axios.get<CodeArea[]>('/cdn/vimp/codes/codeOccAreas.json', config)).data;
|
const codeOccAreas = (await axios.get<CodeArea[]>('/cdn/vimp/codes/codeOccAreas.json', config)).data;
|
||||||
const codeTrainAreas = buildTrainAreas();
|
const codeTrainAreas = buildTrainAreas();
|
||||||
|
// 预编译区域码表索引 (性能优化)
|
||||||
|
const compiledCodeAreas = compileCodeAreas({
|
||||||
|
codeStationAreas,
|
||||||
|
codeParkingAreas,
|
||||||
|
codeOccAreas,
|
||||||
|
codeTrainAreas,
|
||||||
|
});
|
||||||
|
|
||||||
const sitesFromApi = await catalogAllDeviceApi({ signal });
|
const sitesFromApi = await catalogAllDeviceApi({ signal });
|
||||||
|
|
||||||
@@ -60,7 +68,7 @@ export const useDeviceCenterQuery = () => {
|
|||||||
|
|
||||||
for (const siteFromApi of sitesFromApi ?? []) {
|
for (const siteFromApi of sitesFromApi ?? []) {
|
||||||
const channels = await catalogChannelApi(siteFromApi.code, { signal });
|
const channels = await catalogChannelApi(siteFromApi.code, { signal });
|
||||||
if (!channels || channels.length === 0) continue;
|
if (!channels) continue;
|
||||||
|
|
||||||
channels.forEach((channel) => {
|
channels.forEach((channel) => {
|
||||||
const siteCode = channel.code.substring(0, 6);
|
const siteCode = channel.code.substring(0, 6);
|
||||||
@@ -97,21 +105,12 @@ export const useDeviceCenterQuery = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(new Date().toLocaleString());
|
|
||||||
console.log(cameraSites);
|
|
||||||
console.log(siteCodeToCamerasMap);
|
|
||||||
console.log(alarmSites);
|
|
||||||
console.log(siteCodeToAlarmsMap);
|
|
||||||
|
|
||||||
cameraStore.buildLineTabPanes({
|
cameraStore.buildLineTabPanes({
|
||||||
sites: cameraSites,
|
sites: cameraSites,
|
||||||
siteCodeToCamerasMap: siteCodeToCamerasMap,
|
siteCodeToCamerasMap: siteCodeToCamerasMap,
|
||||||
codeLines,
|
codeLines,
|
||||||
codeSites,
|
codeSites,
|
||||||
codeStationAreas,
|
compiledCodeAreas,
|
||||||
codeParkingAreas,
|
|
||||||
codeOccAreas,
|
|
||||||
codeTrainAreas,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
alarmStore.buildLineTabPanes({
|
alarmStore.buildLineTabPanes({
|
||||||
|
|||||||
@@ -1,86 +1,24 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import type { VimpChannel, VimpStation } from '../apis';
|
import type { VimpChannel, VimpStation } from '../apis';
|
||||||
import { h, shallowRef } from 'vue';
|
import { shallowRef } from 'vue';
|
||||||
import type { CameraMainAreaNodeOption, CameraNodeOption, CodeArea, CodeLines, CodeSites, CameraLineTabPane, CameraSiteNodeOption, CameraSubAreaNodeOption } from '../types';
|
import type { CameraMainAreaNodeOption, CameraNodeOption, CodeLines, CodeSites, CameraLineTabPane, CameraSiteNodeOption, CameraSubAreaNodeOption, CompiledCodeAreas } from '../types';
|
||||||
import { NIcon } from 'naive-ui';
|
|
||||||
import BulletCamera from '../components/icon/bullet-camera.vue';
|
|
||||||
import PtzCamera from '../components/icon/ptz-camera.vue';
|
|
||||||
import HemiPtzCamera from '../components/icon/hemi-ptz-camera.vue';
|
|
||||||
|
|
||||||
interface BuildLineTabPanesParams {
|
interface BuildLineTabPanesParams {
|
||||||
sites: VimpStation[];
|
sites: VimpStation[];
|
||||||
siteCodeToCamerasMap: Map<string, VimpChannel[]>;
|
siteCodeToCamerasMap: Map<string, VimpChannel[]>;
|
||||||
codeLines: CodeLines;
|
codeLines: CodeLines;
|
||||||
codeSites: CodeSites;
|
codeSites: CodeSites;
|
||||||
codeStationAreas: CodeArea[];
|
compiledCodeAreas: CompiledCodeAreas;
|
||||||
codeParkingAreas: CodeArea[];
|
|
||||||
codeOccAreas: CodeArea[];
|
|
||||||
codeTrainAreas: CodeArea[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildMainAreaNodeKey = (siteCode: string, mainAreaCode: string) => `${siteCode}${mainAreaCode}`;
|
const buildMainAreaNodeKey = (siteCode: string, mainAreaCode: string) => `${siteCode}${mainAreaCode}`;
|
||||||
const buildSubAreaNodeKey = (siteCode: string, areaCode: string) => `${siteCode}${areaCode}`;
|
const buildSubAreaNodeKey = (siteCode: string, areaCode: string) => `${siteCode}${areaCode}`;
|
||||||
const renderCameraNodePrefix = (cameraType: string) => {
|
|
||||||
if (cameraType === '004') return h(NIcon, () => h(PtzCamera));
|
|
||||||
if (cameraType === '005') return h(NIcon, () => h(HemiPtzCamera));
|
|
||||||
if (cameraType === '006') return h(NIcon, () => h(BulletCamera));
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useCameraStore = defineStore('vimp-camera-store', () => {
|
export const useCameraStore = defineStore('vimp-camera-store', () => {
|
||||||
const lineTabPanes = shallowRef<CameraLineTabPane[]>([]);
|
const lineTabPanes = shallowRef<CameraLineTabPane[]>([]);
|
||||||
|
|
||||||
const buildLineTabPanes = (params: BuildLineTabPanesParams) => {
|
const buildLineTabPanes = (params: BuildLineTabPanesParams) => {
|
||||||
const { sites, siteCodeToCamerasMap, codeLines, codeSites, codeStationAreas, codeParkingAreas, codeOccAreas, codeTrainAreas } = params;
|
const { sites, siteCodeToCamerasMap, codeLines, codeSites, compiledCodeAreas } = params;
|
||||||
|
|
||||||
const findMainArea = (siteType: CodeSites[string]['type'] | undefined, mainAreaCode: string) => {
|
|
||||||
if (siteType === 'station') {
|
|
||||||
return codeStationAreas.find((area) => area.code === mainAreaCode);
|
|
||||||
}
|
|
||||||
if (siteType === 'parking') {
|
|
||||||
return codeParkingAreas.find((area) => area.code === mainAreaCode);
|
|
||||||
}
|
|
||||||
if (siteType === 'occ') {
|
|
||||||
return codeOccAreas.find((area) => area.code === mainAreaCode);
|
|
||||||
}
|
|
||||||
if (siteType === 'train') {
|
|
||||||
return codeTrainAreas.find((area) => area.code === mainAreaCode);
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
const findSubArea = (siteType: CodeSites[string]['type'] | undefined, mainAreaCode: string, areaCode: string) => {
|
|
||||||
if (siteType === 'station') {
|
|
||||||
return codeStationAreas.find((area) => area.code === mainAreaCode)?.subs.find((subArea) => subArea.code === areaCode);
|
|
||||||
}
|
|
||||||
if (siteType === 'parking') {
|
|
||||||
return codeParkingAreas.find((area) => area.code === mainAreaCode)?.subs.find((subArea) => subArea.code === areaCode);
|
|
||||||
}
|
|
||||||
if (siteType === 'occ') {
|
|
||||||
return codeOccAreas.find((area) => area.code === mainAreaCode)?.subs.find((subArea) => subArea.code === areaCode);
|
|
||||||
}
|
|
||||||
if (siteType === 'train') {
|
|
||||||
return codeTrainAreas.find((area) => area.code === mainAreaCode)?.subs.find((subArea) => subArea.code === areaCode);
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
const renderCascadedSuffix = (siteNode: CameraSiteNodeOption) => {
|
|
||||||
siteNode.suffix = () => {
|
|
||||||
const { online, offline, total } = siteNode.stats;
|
|
||||||
return `(${online}/${offline}/${total})`;
|
|
||||||
};
|
|
||||||
siteNode.children?.forEach((areaNode) => {
|
|
||||||
areaNode.suffix = () => {
|
|
||||||
const { online, offline, total } = areaNode.stats;
|
|
||||||
return h('div', { style: { marginRight: '8px', opacity: 0.6 } }, `(${online}/${offline}/${total})`);
|
|
||||||
};
|
|
||||||
areaNode.children?.forEach((subAreaNode) => {
|
|
||||||
subAreaNode.suffix = () => {
|
|
||||||
const { online, offline, total } = subAreaNode.stats;
|
|
||||||
return h('div', { style: { marginRight: '16px', opacity: 0.4 } }, `(${online}/${offline}/${total})`);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const result: CameraLineTabPane[] = [];
|
const result: CameraLineTabPane[] = [];
|
||||||
|
|
||||||
@@ -89,7 +27,7 @@ export const useCameraStore = defineStore('vimp-camera-store', () => {
|
|||||||
|
|
||||||
// 遍历所有站点
|
// 遍历所有站点
|
||||||
for (const site of sites) {
|
for (const site of sites) {
|
||||||
// 2. 站点节点 siteNode 不需要建立索引
|
// 2. 站点节点 siteNode 只在当前轮次中顺序创建,不需要建立索引
|
||||||
|
|
||||||
const lineCode = site.code.substring(0, 3);
|
const lineCode = site.code.substring(0, 3);
|
||||||
const lineName = codeLines[lineCode]?.name ?? '';
|
const lineName = codeLines[lineCode]?.name ?? '';
|
||||||
@@ -102,8 +40,13 @@ export const useCameraStore = defineStore('vimp-camera-store', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const siteCode = site.code;
|
const siteCode = site.code;
|
||||||
const siteName = codeSites[siteCode]?.name;
|
const siteMeta = codeSites[siteCode];
|
||||||
if (!siteName) continue;
|
if (!siteMeta) continue;
|
||||||
|
const siteName = siteMeta.name;
|
||||||
|
const siteType = siteMeta.type;
|
||||||
|
|
||||||
|
const compiledCodeAreaMaps = compiledCodeAreas[siteType];
|
||||||
|
const mainAreaCodeLength = siteType === 'train' ? 3 : 2;
|
||||||
|
|
||||||
// 构造站点节点
|
// 构造站点节点
|
||||||
const siteNode: CameraSiteNodeOption = {
|
const siteNode: CameraSiteNodeOption = {
|
||||||
@@ -132,16 +75,14 @@ export const useCameraStore = defineStore('vimp-camera-store', () => {
|
|||||||
for (const camera of cameras) {
|
for (const camera of cameras) {
|
||||||
// 计算相关编码
|
// 计算相关编码
|
||||||
const { code: cameraGbCode, name: cameraName } = camera;
|
const { code: cameraGbCode, name: cameraName } = camera;
|
||||||
const cameraSiteCode = cameraGbCode.substring(0, 6);
|
|
||||||
const cameraSiteType = codeSites[cameraSiteCode]?.type;
|
|
||||||
const cameraAreaCode = cameraGbCode.substring(6, 11);
|
const cameraAreaCode = cameraGbCode.substring(6, 11);
|
||||||
const cameraMainAreaCode = cameraAreaCode.slice(0, cameraSiteType === 'train' ? 3 : 2);
|
const cameraMainAreaCode = cameraAreaCode.slice(0, mainAreaCodeLength);
|
||||||
|
|
||||||
// 查找1级区域,如果未找到则跳过该摄像机
|
// 查找1级区域,如果未找到则跳过该摄像机
|
||||||
const mainArea = findMainArea(cameraSiteType, cameraMainAreaCode);
|
const mainArea = compiledCodeAreaMaps.mainAreaMap.get(cameraMainAreaCode);
|
||||||
if (!mainArea) continue;
|
if (!mainArea) continue;
|
||||||
// 尝试从索引中获取1级区域节点,若不存在则创建
|
// 尝试从索引中获取1级区域节点,若不存在则创建
|
||||||
const mainAreaNodeKey = buildMainAreaNodeKey(cameraSiteCode, cameraMainAreaCode);
|
const mainAreaNodeKey = buildMainAreaNodeKey(siteCode, cameraMainAreaCode);
|
||||||
let mainAreaNode = mainAreaNodeMap.get(mainAreaNodeKey);
|
let mainAreaNode = mainAreaNodeMap.get(mainAreaNodeKey);
|
||||||
if (!mainAreaNode) {
|
if (!mainAreaNode) {
|
||||||
mainAreaNode = {
|
mainAreaNode = {
|
||||||
@@ -150,16 +91,17 @@ export const useCameraStore = defineStore('vimp-camera-store', () => {
|
|||||||
children: [],
|
children: [],
|
||||||
stats: { online: 0, offline: 0, total: 0 },
|
stats: { online: 0, offline: 0, total: 0 },
|
||||||
site: site,
|
site: site,
|
||||||
|
areaLevel: 1,
|
||||||
};
|
};
|
||||||
mainAreaNodeMap.set(mainAreaNodeKey, mainAreaNode);
|
mainAreaNodeMap.set(mainAreaNodeKey, mainAreaNode);
|
||||||
siteNode.children?.push(mainAreaNode);
|
siteNode.children?.push(mainAreaNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查找2级区域,如果未找到则跳过该摄像机
|
// 查找2级区域,如果未找到则跳过该摄像机
|
||||||
const subArea = findSubArea(cameraSiteType, cameraMainAreaCode, cameraAreaCode);
|
const subArea = compiledCodeAreaMaps.subAreaMap.get(cameraAreaCode);
|
||||||
if (!subArea) continue;
|
if (!subArea) continue;
|
||||||
// 尝试从索引中获取2级区域节点,若不存在则创建
|
// 尝试从索引中获取2级区域节点,若不存在则创建
|
||||||
const subAreaNodeKey = buildSubAreaNodeKey(cameraSiteCode, cameraAreaCode);
|
const subAreaNodeKey = buildSubAreaNodeKey(siteCode, cameraAreaCode);
|
||||||
let subAreaNode = subAreaNodeMap.get(subAreaNodeKey);
|
let subAreaNode = subAreaNodeMap.get(subAreaNodeKey);
|
||||||
if (!subAreaNode) {
|
if (!subAreaNode) {
|
||||||
subAreaNode = {
|
subAreaNode = {
|
||||||
@@ -168,6 +110,7 @@ export const useCameraStore = defineStore('vimp-camera-store', () => {
|
|||||||
children: [],
|
children: [],
|
||||||
stats: { online: 0, offline: 0, total: 0 },
|
stats: { online: 0, offline: 0, total: 0 },
|
||||||
site: site,
|
site: site,
|
||||||
|
areaLevel: 2,
|
||||||
};
|
};
|
||||||
subAreaNodeMap.set(subAreaNodeKey, subAreaNode);
|
subAreaNodeMap.set(subAreaNodeKey, subAreaNode);
|
||||||
mainAreaNode.children?.push(subAreaNode);
|
mainAreaNode.children?.push(subAreaNode);
|
||||||
@@ -181,14 +124,13 @@ export const useCameraStore = defineStore('vimp-camera-store', () => {
|
|||||||
}
|
}
|
||||||
if (cameraGbCodeSet.has(cameraGbCode)) continue;
|
if (cameraGbCodeSet.has(cameraGbCode)) continue;
|
||||||
cameraGbCodeSet.add(cameraGbCode);
|
cameraGbCodeSet.add(cameraGbCode);
|
||||||
const cameraType = camera.code.substring(11, 14);
|
const cameraType = cameraGbCode.substring(11, 14);
|
||||||
const cameraNode: CameraNodeOption = {
|
const cameraNode: CameraNodeOption = {
|
||||||
key: cameraGbCode,
|
key: cameraGbCode,
|
||||||
label: cameraName,
|
label: cameraName,
|
||||||
type: cameraType,
|
type: cameraType,
|
||||||
camera: camera,
|
camera: camera,
|
||||||
site: site,
|
site: site,
|
||||||
prefix: () => renderCameraNodePrefix(cameraType),
|
|
||||||
};
|
};
|
||||||
subAreaNode.children?.push(cameraNode);
|
subAreaNode.children?.push(cameraNode);
|
||||||
|
|
||||||
@@ -200,15 +142,12 @@ export const useCameraStore = defineStore('vimp-camera-store', () => {
|
|||||||
siteNode.stats.online++;
|
siteNode.stats.online++;
|
||||||
mainAreaNode.stats.online++;
|
mainAreaNode.stats.online++;
|
||||||
subAreaNode.stats.online++;
|
subAreaNode.stats.online++;
|
||||||
}
|
} else if (camera.status === 0) {
|
||||||
if (camera.status === 0) {
|
|
||||||
siteNode.stats.offline++;
|
siteNode.stats.offline++;
|
||||||
mainAreaNode.stats.offline++;
|
mainAreaNode.stats.offline++;
|
||||||
subAreaNode.stats.offline++;
|
subAreaNode.stats.offline++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderCascadedSuffix(siteNode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lineTabPanes.value = result;
|
lineTabPanes.value = result;
|
||||||
|
|||||||
@@ -6,6 +6,45 @@ export type CodeLines = Record<string, { name: string; color: string }>;
|
|||||||
export type CodeSites = Record<string, { name: string; type: SiteType }>;
|
export type CodeSites = Record<string, { name: string; type: SiteType }>;
|
||||||
export type CodeArea = { code: string; name: string; subs: { code: string; name: string }[] };
|
export type CodeArea = { code: string; name: string; subs: { code: string; name: string }[] };
|
||||||
|
|
||||||
|
export type CompiledCodeAreaMaps = {
|
||||||
|
mainAreaMap: Map<string, CodeArea>;
|
||||||
|
subAreaMap: Map<string, CodeArea['subs'][number]>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CompiledCodeAreas = Record<SiteType, CompiledCodeAreaMaps>;
|
||||||
|
|
||||||
|
interface CompileCodeAreasParams {
|
||||||
|
codeStationAreas: CodeArea[];
|
||||||
|
codeParkingAreas: CodeArea[];
|
||||||
|
codeOccAreas: CodeArea[];
|
||||||
|
codeTrainAreas: CodeArea[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const compileCodeAreaMaps = (areas: CodeArea[]): CompiledCodeAreaMaps => {
|
||||||
|
const mainAreaMap = new Map<string, CodeArea>();
|
||||||
|
const subAreaMap = new Map<string, CodeArea['subs'][number]>();
|
||||||
|
for (const area of areas) {
|
||||||
|
mainAreaMap.set(area.code, area);
|
||||||
|
for (const subArea of area.subs) {
|
||||||
|
subAreaMap.set(subArea.code, subArea);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
mainAreaMap,
|
||||||
|
subAreaMap,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const compileCodeAreas = (parmas: CompileCodeAreasParams): CompiledCodeAreas => {
|
||||||
|
const { codeStationAreas, codeParkingAreas, codeOccAreas, codeTrainAreas } = parmas;
|
||||||
|
return {
|
||||||
|
station: compileCodeAreaMaps(codeStationAreas),
|
||||||
|
parking: compileCodeAreaMaps(codeParkingAreas),
|
||||||
|
occ: compileCodeAreaMaps(codeOccAreas),
|
||||||
|
train: compileCodeAreaMaps(codeTrainAreas),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export interface CountStats {
|
export interface CountStats {
|
||||||
online: number;
|
online: number;
|
||||||
offline: number;
|
offline: number;
|
||||||
@@ -25,12 +64,14 @@ export interface CameraSubAreaNodeOption extends TreeOption {
|
|||||||
children?: CameraNodeOption[];
|
children?: CameraNodeOption[];
|
||||||
stats: CountStats;
|
stats: CountStats;
|
||||||
site: VimpStation;
|
site: VimpStation;
|
||||||
|
areaLevel: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CameraMainAreaNodeOption extends TreeOption {
|
export interface CameraMainAreaNodeOption extends TreeOption {
|
||||||
children?: CameraSubAreaNodeOption[];
|
children?: CameraSubAreaNodeOption[];
|
||||||
stats: CountStats;
|
stats: CountStats;
|
||||||
site: VimpStation;
|
site: VimpStation;
|
||||||
|
areaLevel: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CameraSiteNodeOption extends TreeOption {
|
export interface CameraSiteNodeOption extends TreeOption {
|
||||||
|
|||||||
Reference in New Issue
Block a user