perf(vimp): 预编译码表区域索引优化查询性能
- 新增compileCodeAreas工具函数,将区域数据预构建为Map索引,降低区域查找的时间复杂度 - 重构camera store,移除冗余的区域遍历查找逻辑,改用预编译索引数据 新增节点areaLevel字段,适配不同层级节点的统计后缀样式间距 - 将摄像头图标和节点统计后缀的渲染逻辑迁移至camera-tree组件 - 清理调试控制台日志,简化空通道判断逻辑
This commit is contained in:
@@ -1,86 +1,24 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import type { VimpChannel, VimpStation } from '../apis';
|
||||
import { h, shallowRef } from 'vue';
|
||||
import type { CameraMainAreaNodeOption, CameraNodeOption, CodeArea, CodeLines, CodeSites, CameraLineTabPane, CameraSiteNodeOption, CameraSubAreaNodeOption } 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';
|
||||
import { shallowRef } from 'vue';
|
||||
import type { CameraMainAreaNodeOption, CameraNodeOption, CodeLines, CodeSites, CameraLineTabPane, CameraSiteNodeOption, CameraSubAreaNodeOption, CompiledCodeAreas } from '../types';
|
||||
|
||||
interface BuildLineTabPanesParams {
|
||||
sites: VimpStation[];
|
||||
siteCodeToCamerasMap: Map<string, VimpChannel[]>;
|
||||
codeLines: CodeLines;
|
||||
codeSites: CodeSites;
|
||||
codeStationAreas: CodeArea[];
|
||||
codeParkingAreas: CodeArea[];
|
||||
codeOccAreas: CodeArea[];
|
||||
codeTrainAreas: CodeArea[];
|
||||
compiledCodeAreas: CompiledCodeAreas;
|
||||
}
|
||||
|
||||
const buildMainAreaNodeKey = (siteCode: string, mainAreaCode: string) => `${siteCode}${mainAreaCode}`;
|
||||
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', () => {
|
||||
const lineTabPanes = shallowRef<CameraLineTabPane[]>([]);
|
||||
|
||||
const buildLineTabPanes = (params: BuildLineTabPanesParams) => {
|
||||
const { sites, siteCodeToCamerasMap, codeLines, codeSites, codeStationAreas, codeParkingAreas, codeOccAreas, codeTrainAreas } = 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 { sites, siteCodeToCamerasMap, codeLines, codeSites, compiledCodeAreas } = params;
|
||||
|
||||
const result: CameraLineTabPane[] = [];
|
||||
|
||||
@@ -89,7 +27,7 @@ export const useCameraStore = defineStore('vimp-camera-store', () => {
|
||||
|
||||
// 遍历所有站点
|
||||
for (const site of sites) {
|
||||
// 2. 站点节点 siteNode 不需要建立索引
|
||||
// 2. 站点节点 siteNode 只在当前轮次中顺序创建,不需要建立索引
|
||||
|
||||
const lineCode = site.code.substring(0, 3);
|
||||
const lineName = codeLines[lineCode]?.name ?? '';
|
||||
@@ -102,8 +40,13 @@ export const useCameraStore = defineStore('vimp-camera-store', () => {
|
||||
}
|
||||
|
||||
const siteCode = site.code;
|
||||
const siteName = codeSites[siteCode]?.name;
|
||||
if (!siteName) continue;
|
||||
const siteMeta = codeSites[siteCode];
|
||||
if (!siteMeta) continue;
|
||||
const siteName = siteMeta.name;
|
||||
const siteType = siteMeta.type;
|
||||
|
||||
const compiledCodeAreaMaps = compiledCodeAreas[siteType];
|
||||
const mainAreaCodeLength = siteType === 'train' ? 3 : 2;
|
||||
|
||||
// 构造站点节点
|
||||
const siteNode: CameraSiteNodeOption = {
|
||||
@@ -132,16 +75,14 @@ export const useCameraStore = defineStore('vimp-camera-store', () => {
|
||||
for (const camera of cameras) {
|
||||
// 计算相关编码
|
||||
const { code: cameraGbCode, name: cameraName } = camera;
|
||||
const cameraSiteCode = cameraGbCode.substring(0, 6);
|
||||
const cameraSiteType = codeSites[cameraSiteCode]?.type;
|
||||
const cameraAreaCode = cameraGbCode.substring(6, 11);
|
||||
const cameraMainAreaCode = cameraAreaCode.slice(0, cameraSiteType === 'train' ? 3 : 2);
|
||||
const cameraMainAreaCode = cameraAreaCode.slice(0, mainAreaCodeLength);
|
||||
|
||||
// 查找1级区域,如果未找到则跳过该摄像机
|
||||
const mainArea = findMainArea(cameraSiteType, cameraMainAreaCode);
|
||||
const mainArea = compiledCodeAreaMaps.mainAreaMap.get(cameraMainAreaCode);
|
||||
if (!mainArea) continue;
|
||||
// 尝试从索引中获取1级区域节点,若不存在则创建
|
||||
const mainAreaNodeKey = buildMainAreaNodeKey(cameraSiteCode, cameraMainAreaCode);
|
||||
const mainAreaNodeKey = buildMainAreaNodeKey(siteCode, cameraMainAreaCode);
|
||||
let mainAreaNode = mainAreaNodeMap.get(mainAreaNodeKey);
|
||||
if (!mainAreaNode) {
|
||||
mainAreaNode = {
|
||||
@@ -150,16 +91,17 @@ export const useCameraStore = defineStore('vimp-camera-store', () => {
|
||||
children: [],
|
||||
stats: { online: 0, offline: 0, total: 0 },
|
||||
site: site,
|
||||
areaLevel: 1,
|
||||
};
|
||||
mainAreaNodeMap.set(mainAreaNodeKey, mainAreaNode);
|
||||
siteNode.children?.push(mainAreaNode);
|
||||
}
|
||||
|
||||
// 查找2级区域,如果未找到则跳过该摄像机
|
||||
const subArea = findSubArea(cameraSiteType, cameraMainAreaCode, cameraAreaCode);
|
||||
const subArea = compiledCodeAreaMaps.subAreaMap.get(cameraAreaCode);
|
||||
if (!subArea) continue;
|
||||
// 尝试从索引中获取2级区域节点,若不存在则创建
|
||||
const subAreaNodeKey = buildSubAreaNodeKey(cameraSiteCode, cameraAreaCode);
|
||||
const subAreaNodeKey = buildSubAreaNodeKey(siteCode, cameraAreaCode);
|
||||
let subAreaNode = subAreaNodeMap.get(subAreaNodeKey);
|
||||
if (!subAreaNode) {
|
||||
subAreaNode = {
|
||||
@@ -168,6 +110,7 @@ export const useCameraStore = defineStore('vimp-camera-store', () => {
|
||||
children: [],
|
||||
stats: { online: 0, offline: 0, total: 0 },
|
||||
site: site,
|
||||
areaLevel: 2,
|
||||
};
|
||||
subAreaNodeMap.set(subAreaNodeKey, subAreaNode);
|
||||
mainAreaNode.children?.push(subAreaNode);
|
||||
@@ -181,14 +124,13 @@ export const useCameraStore = defineStore('vimp-camera-store', () => {
|
||||
}
|
||||
if (cameraGbCodeSet.has(cameraGbCode)) continue;
|
||||
cameraGbCodeSet.add(cameraGbCode);
|
||||
const cameraType = camera.code.substring(11, 14);
|
||||
const cameraType = cameraGbCode.substring(11, 14);
|
||||
const cameraNode: CameraNodeOption = {
|
||||
key: cameraGbCode,
|
||||
label: cameraName,
|
||||
type: cameraType,
|
||||
camera: camera,
|
||||
site: site,
|
||||
prefix: () => renderCameraNodePrefix(cameraType),
|
||||
};
|
||||
subAreaNode.children?.push(cameraNode);
|
||||
|
||||
@@ -200,15 +142,12 @@ export const useCameraStore = defineStore('vimp-camera-store', () => {
|
||||
siteNode.stats.online++;
|
||||
mainAreaNode.stats.online++;
|
||||
subAreaNode.stats.online++;
|
||||
}
|
||||
if (camera.status === 0) {
|
||||
} else if (camera.status === 0) {
|
||||
siteNode.stats.offline++;
|
||||
mainAreaNode.stats.offline++;
|
||||
subAreaNode.stats.offline++;
|
||||
}
|
||||
}
|
||||
|
||||
renderCascadedSuffix(siteNode);
|
||||
}
|
||||
|
||||
lineTabPanes.value = result;
|
||||
|
||||
Reference in New Issue
Block a user