Files
ndm-web-platform/src/pages/vimp/stores/camera.ts
T
yangsy e06afe36ae perf(vimp): 预编译码表区域索引优化查询性能
- 新增compileCodeAreas工具函数,将区域数据预构建为Map索引,降低区域查找的时间复杂度
- 重构camera store,移除冗余的区域遍历查找逻辑,改用预编译索引数据
新增节点areaLevel字段,适配不同层级节点的统计后缀样式间距
- 将摄像头图标和节点统计后缀的渲染逻辑迁移至camera-tree组件
- 清理调试控制台日志,简化空通道判断逻辑
2026-06-23 14:01:25 +08:00

161 lines
5.9 KiB
TypeScript

import { defineStore } from 'pinia';
import type { VimpChannel, VimpStation } from '../apis';
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;
compiledCodeAreas: CompiledCodeAreas;
}
const buildMainAreaNodeKey = (siteCode: string, mainAreaCode: string) => `${siteCode}${mainAreaCode}`;
const buildSubAreaNodeKey = (siteCode: string, areaCode: string) => `${siteCode}${areaCode}`;
export const useCameraStore = defineStore('vimp-camera-store', () => {
const lineTabPanes = shallowRef<CameraLineTabPane[]>([]);
const buildLineTabPanes = (params: BuildLineTabPanesParams) => {
const { sites, siteCodeToCamerasMap, codeLines, codeSites, compiledCodeAreas } = params;
const result: CameraLineTabPane[] = [];
// 1. 线路索引 lineCode -> CameraLineTabPane
const linePaneMap = new Map<string, CameraLineTabPane>();
// 遍历所有站点
for (const site of sites) {
// 2. 站点节点 siteNode 只在当前轮次中顺序创建,不需要建立索引
const lineCode = site.code.substring(0, 3);
const lineName = codeLines[lineCode]?.name ?? '';
let linePane = linePaneMap.get(lineCode);
if (!linePane) {
linePane = { lineCode, lineName, cameraTree: [] };
linePaneMap.set(lineCode, linePane);
result.push(linePane);
}
const siteCode = site.code;
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 = {
key: siteCode,
label: siteName,
children: [],
stats: { online: 0, offline: 0, total: 0 },
online: site.online,
};
linePane.cameraTree.push(siteNode);
// 获取所有摄像机
const cameras = siteCodeToCamerasMap.get(siteCode);
if (!cameras) continue;
// 3. 1级区域索引 mainAreaNodeKey -> CameraMainAreaNodeOption
// mainAreaNodeKey = ${siteCode}${cameraMainAreaCode}
const mainAreaNodeMap = new Map<string, CameraMainAreaNodeOption>();
// 4. 2级区域索引 subAreaNodeKey -> CameraSubAreaNodeOption
// subAreaNodeKey = ${siteCode}${cameraAreaCode}
const subAreaNodeMap = new Map<string, CameraSubAreaNodeOption>();
// 5. 摄像机索引 subAreaNodeKey -> Set<CameraGbCode>
const subAreaNodeKeyToCameraGbCodeSetMap = new Map<string, Set<string>>();
// 遍历摄像机
for (const camera of cameras) {
// 计算相关编码
const { code: cameraGbCode, name: cameraName } = camera;
const cameraAreaCode = cameraGbCode.substring(6, 11);
const cameraMainAreaCode = cameraAreaCode.slice(0, mainAreaCodeLength);
// 查找1级区域,如果未找到则跳过该摄像机
const mainArea = compiledCodeAreaMaps.mainAreaMap.get(cameraMainAreaCode);
if (!mainArea) continue;
// 尝试从索引中获取1级区域节点,若不存在则创建
const mainAreaNodeKey = buildMainAreaNodeKey(siteCode, cameraMainAreaCode);
let mainAreaNode = mainAreaNodeMap.get(mainAreaNodeKey);
if (!mainAreaNode) {
mainAreaNode = {
key: mainAreaNodeKey,
label: mainArea.name,
children: [],
stats: { online: 0, offline: 0, total: 0 },
site: site,
areaLevel: 1,
};
mainAreaNodeMap.set(mainAreaNodeKey, mainAreaNode);
siteNode.children?.push(mainAreaNode);
}
// 查找2级区域,如果未找到则跳过该摄像机
const subArea = compiledCodeAreaMaps.subAreaMap.get(cameraAreaCode);
if (!subArea) continue;
// 尝试从索引中获取2级区域节点,若不存在则创建
const subAreaNodeKey = buildSubAreaNodeKey(siteCode, cameraAreaCode);
let subAreaNode = subAreaNodeMap.get(subAreaNodeKey);
if (!subAreaNode) {
subAreaNode = {
key: subAreaNodeKey,
label: subArea.name,
children: [],
stats: { online: 0, offline: 0, total: 0 },
site: site,
areaLevel: 2,
};
subAreaNodeMap.set(subAreaNodeKey, subAreaNode);
mainAreaNode.children?.push(subAreaNode);
}
// 构造摄像机节点
let cameraGbCodeSet = subAreaNodeKeyToCameraGbCodeSetMap.get(subAreaNodeKey);
if (!cameraGbCodeSet) {
cameraGbCodeSet = new Set<string>();
subAreaNodeKeyToCameraGbCodeSetMap.set(subAreaNodeKey, cameraGbCodeSet);
}
if (cameraGbCodeSet.has(cameraGbCode)) continue;
cameraGbCodeSet.add(cameraGbCode);
const cameraType = cameraGbCode.substring(11, 14);
const cameraNode: CameraNodeOption = {
key: cameraGbCode,
label: cameraName,
type: cameraType,
camera: camera,
site: site,
};
subAreaNode.children?.push(cameraNode);
// 统计站点、区域、子区域的在线/离线/总摄像机数量
siteNode.stats.total++;
mainAreaNode.stats.total++;
subAreaNode.stats.total++;
if (camera.status === 1) {
siteNode.stats.online++;
mainAreaNode.stats.online++;
subAreaNode.stats.online++;
} else if (camera.status === 0) {
siteNode.stats.offline++;
mainAreaNode.stats.offline++;
subAreaNode.stats.offline++;
}
}
}
lineTabPanes.value = result;
};
return {
lineTabPanes,
buildLineTabPanes,
};
});