docs: add PR7050 panoramic monitoring data flow

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
liumangmang
2026-06-17 17:00:29 +08:00
parent ec273dd486
commit 8c5a06b7e6
2 changed files with 649 additions and 0 deletions
+40
View File
@@ -22,6 +22,46 @@
flex-shrink: 0;
}
.vp-sidebar .vp-sidebar-link {
display: flex;
align-items: center;
gap: 0.3em;
min-width: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.vp-sidebar .vp-sidebar-header {
gap: 0.3em;
white-space: nowrap;
}
.vp-sidebar .vp-sidebar-link .icon,
.vp-sidebar .vp-sidebar-link .vp-icon,
.vp-sidebar .vp-sidebar-header .icon,
.vp-sidebar .vp-sidebar-header .vp-icon {
flex: 0 0 1em;
margin-top: 0;
}
.vp-sidebar .vp-sidebar-title {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
#app {
--sidebar-width: 19rem;
}
@media (max-width: 959px) {
#app {
--sidebar-width: var(--sidebar-mobile-width, 16rem);
}
}
.todo-page {
--todo-border: rgba(220, 20, 60, 0.2);
--todo-accent: rgba(220, 20, 60, 0.08);
@@ -0,0 +1,609 @@
---
title: PR7050 全景监控(主辅监控)数据加载流程深度解析
icon: fa6-solid:network-wired
date: 2026-06-17
category:
- 工作
tag:
- PR7050
- Java
- Vue
- 实时监控
- 组态画面
---
# PR7050 全景监控(主辅监控)数据加载流程深度解析
本文基于 PR7050 项目中全景监控模块(`/panoramicMonitoring/main-auxiliaryMonitoring`)的实际代码,深入分析组态画面数据加载的完整流程、核心接口、缓存机制及关键注意事项。
<!-- more -->
## 1. 项目概述
全景监控模块是 PR7050 系统中用于实时展示变电站设备状态的核心功能模块。它通过组态画面的形式,将设备的遥测、遥信、遥控、遥设等实时数据以图形化方式呈现给用户,支持设备状态监控、遥控操作、告警展示等功能。
**核心特点**
- **图形化展示**:通过组态画面直观展示设备状态
- **实时数据刷新**:支持定时轮询和 MQ 推送两种刷新机制
- **多级导航**:顶部Tab菜单 + 左侧树提供设备分类导航
- **缓存优化**:文件缓存和内存缓存双重优化加载性能
## 2. 整体数据加载流程
组态画面的数据加载分为五个主要阶段,形成完整的数据闭环:
```
阶段1:获取顶部Tab菜单 → 阶段2:加载左侧导航树 → 阶段3:获取画面属性 → 阶段4:获取实时数据 → 阶段5:定时刷新/MQ推送
```
### 2.1 阶段一:获取顶部Tab菜单
**目的**:获取全站总览图列表,作为一级导航菜单
**涉及接口**
| 接口路径 | 请求方式 | 作用 |
| :--- | :--- | :--- |
| `/userManage/dynamic/route` | POST | 获取动态路由(全站总览图列表) |
**数据来源**`picfileinfo` 表中 `pictype=8`(全站总览图)的数据
**返回数据结构**
```json
[
{
"name": "辅控照明子系统",
"nodeId": "1001",
"url": "/main-auxiliaryMonitoring/1001",
"right": true,
"invalidhide": true
},
{
"name": "巡视设备总览",
"nodeId": "1002",
"url": "/main-auxiliaryMonitoring/1002",
"right": true,
"invalidhide": true
}
]
```
**前端处理逻辑**[MainDeviceMonitoring/index.tsx](file:///home/liumangmang/IdeaProjects/PR7050/V1.00-web/V1.00/src_web/prw/src/pages/BizComponents/MainAuxiliaryMonitoring/MainDeviceMonitoring/index.tsx#L38)):
```tsx
const getInitialData = async () => {
const { data } = await getRouteList();
const options = data?.map((item: any) => {
return {
key: item?.nodeId,
label: item?.name,
};
});
setTabList(data?.length ? [...tabListDefault, ...options] : tabListDefault);
};
```
**Tab列表结构**
| Tab名称 | key | 说明 |
| :--- | :--- | :--- |
| 监控首页 | `'0'` | 默认页,显示左侧树 |
| 辅控照明子系统 | `'1001'` | 全站总览图,直接加载画面 |
| 巡视设备总览 | `'1002'` | 全站总览图,直接加载画面 |
**Tab点击处理**[MainDeviceMonitoring/index.tsx](file:///home/liumangmang/IdeaProjects/PR7050/V1.00-web/V1.00/src_web/prw/src/pages/BizComponents/MainAuxiliaryMonitoring/MainDeviceMonitoring/index.tsx#L48)):
```tsx
const changeTabs = (key: string) => {
setActiveKey(key);
setFixedPicId(key !== '0' ? key : null);
};
```
- 点击"监控首页"key='0'):`fixedPicId = null`,显示左侧树,用户从树中选择画面
- 点击其他Tabkey='1001'等):`fixedPicId = 画面ID`,直接加载指定画面,隐藏左侧树
**代码位置**
- 控制器:[UserManageController.java](file:///home/liumangmang/IdeaProjects/PR7050/V1.00-web/V1.00/src_java/platapp/04_sunri-web-patrol/sunri-web-center-cygbusiness/cygbusiness-auth/src/main/java/com/sunri/controller/usermanage/UserManageController.java#L486)
- 服务实现:[UserManageServiceImpl.java](file:///home/liumangmang/IdeaProjects/PR7050/V1.00-web/V1.00/src_java/platapp/service/sunri-service-auth-patrol/sunri-service-auth-patrol-core/src/main/java/com/sunri/service/impl/UserManageServiceImpl.java#L640)
### 2.2 阶段二:加载左侧导航树
**目的**:获取图形画面的分类结构,提供导航入口
**涉及接口**(前端实际调用):
| 接口路径 | 请求方式 | 作用 |
| :--- | :--- | :--- |
| `/api/graph/picture/get/baseGraph/tree/list/v2` | GET | 按设备类型分类(主设备/辅设备/巡视设备) |
> **注意**:前端只调用了按设备类型分类的接口,没有调用按子系统分类的接口(`/api/graph/picture/get/subSystem/tree/list`)。
**关键参数**
| 参数 | 来源 | 值 |
| :--- | :--- | :--- |
| `equipmentType` | `graphType` | `'主设备'` / `'辅设备'` / `'巡视设备'` |
| `siteId` | `siteData` | 变电站ID |
**graphType 与设备类型映射**
| graphType | equipmentType | 说明 |
| :--- | :--- | :--- |
| 0 | `'主设备'` | 监控首页 |
| 1 | `'辅设备'` | 其他Tab页 |
| 2 | `'巡视设备'` | 巡视设备监控 |
**前端调用逻辑**[ControlHMI/index.tsx](file:///home/liumangmang/IdeaProjects/PR7050/V1.00-web/V1.00/src_web/prw/src/pages/BasicComponents/ControlHMI/index.tsx#L74)):
```tsx
const initGraphInfo = async (siteId: number) => {
const equipmentType = ['主设备', '辅设备', '巡视设备']?.[graphType];
const { status, data } = await getPvarrayV2(equipmentType, siteId);
if (status === 200 && data) {
GraphConfigModel(data, useGraphStore, siteId);
fixedPicId ? getPageData(fixedPicId, timerLimit?.current) : handleGraphTree(data?.picFileInfoVos?.[0]?.children || []);
}
};
```
**返回数据结构**
```json
{
"level": 1,
"nodeId": "1",
"description": "画面类型",
"hasChildren": true,
"children": [
{
"level": 2,
"nodeId": "1",
"description": "主接线图",
"hasChildren": true,
"children": [
{
"level": 3,
"nodeId": "101",
"description": "220kV主接线图",
"picType": 1,
"siteId": 1
}
]
}
]
}
```
**节点判断规则**
| 字段 | 判断条件 | 是否可获取画面 |
| :--- | :--- | :--- |
| `level` | ≥ 3 | ✅ |
| `nodeId` | 为 `picId`(数字) | ✅ |
| `hasChildren` | `false`(叶子节点) | ✅ |
| `level` | ≤ 2 | ❌ |
| `nodeId` | 为 `picType``"bayId"` 开头 | ❌ |
**代码位置**
- 控制器:[BasePictureController.java](file:///home/liumangmang/IdeaProjects/PR7050/V1.00-web/V1.00/src_java/platform/03_platapp/04_sunri-web-center/sunri-web-center-cygbusiness/cygbusiness-graphic/src/main/java/com/sunri/controller/BasePictureController.java#L194)
- 服务实现:[BasePictureServiceImpl.java](file:///home/liumangmang/IdeaProjects/PR7050/V1.00-web/V1.00/src_java/platform/02_platservice/sunri-service-graphic/sunri-service-graphic-core/src/main/java/com/sunri/service/impl/BasePictureServiceImpl.java#L171)
- VO定义:[GraphTreeNodeVo.java](file:///home/liumangmang/IdeaProjects/PR7050/V1.00-web/V1.00/src_java/platform/00_depends/sunri-service-graphic-spi/src/main/java/com/sunri/vo/GraphTreeNodeVo.java)
### 2.3 阶段三:获取画面属性(静态数据)
**目的**:获取组态画面的完整结构,包括静态元素和动态元素定义
**涉及接口**(前端实际调用):
| 接口路径 | 请求方式 | 作用 | 调用场景 |
| :--- | :--- | :--- | :--- |
| `/api/graph/picture/get/graph/properties` | GET | 获取画面属性 | 用户选择画面时 |
| `/api/graph/picture/get/drawing/properties` | GET | 获取图纸属性(图元) | 画面渲染过程中动态加载图元 |
| `/api/graph/picture/get/graph/wiringProperties` | GET | 获取主接线图属性 | 专门的主接线图页面 |
**三个接口的核心区别**
| 特性 | `get/graph/properties` | `get/drawing/properties` | `get/graph/wiringProperties` |
| :--- | :--- | :--- | :--- |
| **参数** | `picId`(必填)、`siteId``cmyId` | `elementId`(必填)、`siteId` | `siteId``cmyId` |
| **返回类型** | `List<PicFileInfoVo>` | `GraphElementVo` | `List<PicFileInfoVo>` |
| **数据粒度** | 完整画面 | 单个图元 | 主接线图画面 |
| **数据来源** | `picfileinfo` 表 | 图元表 | `picfileinfo` 表(主接线图) |
| **前端调用位置** | ControlHMI、Graph组件 | Graph组件 | 未在当前项目中直接调用 |
| **触发时机** | 点击画面节点、Tab切换 | 画面渲染时动态加载图元 | 获取主接线图 |
**请求参数**`get/graph/properties`):
```json
{
"picId": "101", // 画面ID(来自树节点的nodeId
"siteId": 1, // 变电站ID
"cmyId": 1 // 厂站ID
}
```
**返回数据结构**
```json
{
"picId": 101,
"picFilename": "220kV主接线图",
"jsonContent": {
"width": 1920,
"height": 1080,
"elements": [
{
"id": "element_1",
"type": "rect", // 静态元素
"x": 100,
"y": 100,
"fill": "#336699"
},
{
"id": "element_2",
"type": "text", // 动态元素
"signalId": "45_1001", // 信号绑定标识
"format": "%.1f"
}
]
},
"sigIds": [45, 1001, 46, 2001] // 动态信号ID列表(二进制)
}
```
**静态/动态元素区分**
| 区分方式 | 字段/属性 | 作用 |
| :--- | :--- | :--- |
| `sigIds` | `byte[]` | 快速获取所有动态信号ID |
| `signalId` | JSON属性 | 精确标识每个动态元素绑定的信号 |
**代码位置**
- 控制器:[BasePictureController.java](file:///home/liumangmang/IdeaProjects/PR7050/V1.00-web/V1.00/src_java/platform/03_platapp/04_sunri-web-center/sunri-web-center-cygbusiness/cygbusiness-graphic/src/main/java/com/sunri/controller/BasePictureController.java#L222)
- VO定义:[PicFileInfoVo.java](file:///home/liumangmang/IdeaProjects/PR7050/V1.00-web/V1.00/src_java/platform/00_depends/sunri-service-graphic-spi/src/main/java/com/sunri/vo/PicFileInfoVo.java)
### 2.4 阶段四:获取实时数据(动态数据)
**目的**:根据画面中的信号绑定,从实时数据库获取信号的实时值
**涉及接口**
| 接口路径 | 请求方式 | 作用 |
| :--- | :--- | :--- |
| `/api/rt/data/get` | POST | 获取信号点实时数据 |
**请求参数**
```json
{
"cmyId": 1,
"staId": 1,
"tables": [
{
"table": 45, // 遥测表
"records": [
{"record": 1001},
{"record": 1002}
]
},
{
"table": 46, // 遥信表
"records": [
{"record": 2001}
]
}
]
}
```
**信号表类型**
| tableId | 信号类型 | 说明 |
| :--- | :--- | :--- |
| 45 | 遥测(Analog) | 电流、电压、功率等连续数值 |
| 46 | 遥信(Digital) | 开关位置、告警状态等离散状态 |
| 47 | 遥脉(Power | 电能累计值 |
| 48 | 遥控(Control | 遥控命令状态 |
| 53 | 遥设(Set | 设定值 |
**返回数据结构**
```json
[
{
"record": 1001,
"realValue": 220.5,
"status": "0000",
"time": "2026-06-17 10:30:00",
"table": 45,
"hoverMessages": ["220kV母线电压(1001)"]
},
{
"record": 2001,
"realValue": 1,
"status": "0001",
"time": "2026-06-17 10:30:00",
"table": 46,
"hoverMessages": ["断路器位置(2001)"]
}
]
```
**代码位置**
- 控制器:[RTDataController.java](file:///home/liumangmang/IdeaProjects/PR7050/V1.00-web/V1.00/src_java/platform/03_platapp/04_sunri-web-center/sunri-web-center-cygbusiness/cygbusiness-graphic/src/main/java/com/sunri/controller/RTDataController.java#L50)
- 服务实现:[GraphicRealtimeServiceImpl.java](file:///home/liumangmang/IdeaProjects/PR7050/V1.00-web/V1.00/src_java/platform/02_platservice/sunri-service-graphic/sunri-service-graphic-core/src/main/java/com/sunri/service/impl/GraphicRealtimeServiceImpl.java)
- 数据聚合:[GraphicAggregate.java](file:///home/liumangmang/IdeaProjects/PR7050/V1.00-web/V1.00/src_java/platform/02_platservice/sunri-service-graphic/sunri-service-graphic-core/src/main/java/com/sunri/model/realtime/graphics/GraphicAggregate.java)
### 2.5 阶段五:定时刷新与MQ推送
**目的**:保持数据的实时性,处理画面变更
#### 5.1 定时轮询刷新
```
前端 setInterval(1-3秒) → POST /api/rt/data/get → 更新画面显示
```
**轮询频率**:通常1-3秒一次,根据实际需求调整
**适用场景**:信号值变化的实时更新
#### 5.2 MQ推送(画面变更)
**触发场景**:组态工具修改画面(新增/修改/删除元素、变更信号绑定)
**MQ消息流程**
```
组态工具 → MQ发送 /cyggraph/update → 后端监听 → 更新缓存 → 通知前端刷新
```
**涉及代码**
| 文件 | 作用 |
| :--- | :--- |
| [GraphicUpdateSource.java](file:///home/liumangmang/IdeaProjects/PR7050/V1.00-web/V1.00/src_java/platform/02_platservice/sunri-service-graphic/sunri-service-graphic-core/src/main/java/com/sunri/task/source/GraphicUpdateSource.java) | MQ消息监听 |
| [GraphicTask.java](file:///home/liumangmang/IdeaProjects/PR7050/V1.00-web/V1.00/src_java/platform/02_platservice/sunri-service-graphic/sunri-service-graphic-core/src/main/java/com/sunri/task/GraphicTask.java) | 任务处理 |
| [WebFrontNotify.java](file:///home/liumangmang/IdeaProjects/PR7050/V1.00-web/V1.00/src_java/platform/01_componnet/03_sunri-unify-notify/src/main/java/com/sunri/WebFrontNotify.java) | 前端通知 |
**前端通知类型**
```java
// NotifyMessageTypeConstants.java
public static final String GRAPHIC_UPDATE = "graphic-update"; // 画面更新
public static final String SIGNBOARD_UPDATE = "graphic-signboard-update"; // 看板更新
public static final String GRAPHIC_PICTURE_CLEAR = "graphic-picture-clear"; // 画面清除
public static final String GRAPHIC_SITE_CLEAR = "graphic-site-clear"; // 站点清除
```
## 3. 缓存机制详解
### 3.1 文件缓存
**目的**:加速画面结构数据加载,减少数据库查询
**存储位置**
```
主接线图缓存:{wiringPath}/1/{siteId}/{timestamp}.dat
普通图形缓存:{picturePath}/1/{siteId}/{picId}/{timestamp}.dat
```
**更新时机**
1. 应用启动时初始化
2. 收到 `/cyggraph/update` MQ消息时更新
**实现逻辑**
```java
// BasePictureServiceImpl.java
public void updateGraphicCacheFile(List<SubStation> subStationList, boolean init) {
subStationList.forEach(subStation -> {
// 查询数据库获取图形数据
List<PicFileInfo> picFileInfoList = graphGroupMapper.getSimpleGraphProperties(null);
picFileInfoList.forEach(picFileInfo -> {
// 创建缓存目录
File dir = getPictureDirectory(subStation.getSubId(), picFileInfo.getPicId());
dir.mkdirs();
// 文件名使用 lastSaveTime 时间戳(防止缓存问题)
String fileName = String.valueOf(DateUtils.parseESOrCHDateTime(picFileInfo.getLastSaveTime()).getTime());
// 创建缓存文件
File file = createPicFileCache(subStation.getSubId(), picFileInfo.getPicId(),
Paths.get(dir.getAbsolutePath(), fileName).toString());
});
});
}
```
### 3.2 内存缓存
**目的**:加速实时数据查询,减少RTDB访问
**缓存内容**
| Helper | 缓存内容 | 用途 |
| :--- | :--- | :--- |
| MeasureHelper | `siteParamGroupCache`(信号配置)、`siteHoverInfoCache`(悬浮信息) | 获取信号配置和悬浮提示 |
| TopologyHelper | 拓扑着色相关缓存 | 主接线图动态着色 |
**清除时机**:收到 `/cyggraph/update` MQ消息时清除
```java
// GraphicAggregate.java
public void clearCache(Integer siteId) {
for (GraphicHelper graphicHelper : graphicHelperList) {
graphicHelper.clearCache(siteId);
}
}
```
## 4. 关键注意事项
### 4.1 轮询与推送的适用场景
| 变更类型 | 轮询(/api/rt/data/get | MQ推送(/cyggraph/update |
| :--- | :--- | :--- |
| 信号值变化 | ✅ 可以处理 | ❌ 不需要 |
| 新增图形元素 | ❌ 无法处理 | ✅ 必须使用 |
| 删除图形元素 | ❌ 无法处理 | ✅ 必须使用 |
| 修改图形元素属性 | ❌ 无法处理 | ✅ 必须使用 |
| 修改信号绑定关系 | ❌ 无法处理 | ✅ 必须使用 |
**核心原因**:轮询请求的信号ID列表来源于已加载的静态数据,无法发现画面结构的变化。
### 4.2 时间戳文件名设计
```java
String fileName = String.valueOf(DateUtils.parseESOrCHDateTime(picFileInfo.getLastSaveTime()).getTime());
```
**作用**
- 每次画面修改后,`lastSaveTime` 更新,文件名变更
- 避免浏览器缓存问题(文件名变更相当于资源版本更新)
- 前端能正确获取最新内容
### 4.3 信号绑定机制
**一对一绑定**:一个动态元素绑定一个信号点
```json
{"signalId": "45_1001"} // tableId_recordId
```
**一对多绑定**:一个元素绑定多个信号点(复合元素)
```json
{"signalIds": ["45_1001", "46_2001"]}
```
### 4.4 数据一致性
**潜在问题**
1. **缓存不一致**:文件缓存更新后,前端可能仍使用旧缓存
2. **信号ID过期**:画面变更后,旧的信号ID可能不再有效
3. **轮询中断**:网络异常导致轮询失败
**解决方案**
1. 使用时间戳文件名强制刷新
2. MQ推送通知前端重新加载画面
3. 前端增加异常处理和重试机制
### 4.5 性能优化建议
**后端优化**
1. **批量查询**:一次请求获取多个信号的数据
2. **缓存策略**:文件缓存 + 内存缓存双重优化
3. **异步处理**MQ消息异步处理,不阻塞主线程
**前端优化**
1. **按需加载**:只加载当前画面需要的信号
2. **防抖节流**:避免频繁请求
3. **局部更新**:只更新变化的元素,不重绘整个画面
## 5. 完整数据闭环图
```
┌─────────────────────────────────────────────────────────────────────────┐
│ 用户打开全景监控页面 │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ 阶段1: 获取顶部Tab菜单 │
│ POST /userManage/dynamic/route │
│ 返回: 全站总览图列表(pictype=8) │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ 阶段2: 加载左侧树 │
│ GET /api/graph/picture/get/baseGraph/tree/list/v2 │
│ 参数: equipmentType=主设备/辅设备/巡视设备, siteId │
│ 返回: 画面分类结构(节点包含 picId) │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ 阶段3: 用户选择画面(树节点或Tab) │
│ - 树节点: nodeId = picId │
│ - Tab: fixedPicId = 画面ID │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ 阶段4: 获取画面属性(静态数据) │
│ GET /api/graph/picture/get/graph/properties?picId=xxx │
│ 返回: 画面JSON内容 + sigIds(动态信号ID列表) │
│ 渲染过程中: GET /api/graph/picture/get/drawing/properties?elementId=xxx│
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ 阶段5: 获取实时数据(动态数据) │
│ POST /api/rt/data/get(携带 sigIds 中的信号ID
│ 返回: 信号实时值 │
│ 前端绑定: 信号值 → 画面动态元素 │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ 阶段6: 定时轮询刷新(持续循环) │
│ setInterval(1-3秒) → POST /api/rt/data/get → 更新元素显示 │
└─────────────────────────────────────────────────────────────────────────┘
▲ │ ▼
│ │ │
┌─────┴─────┐ │ ┌─────┴─────┐
│ │ │ │ │
│ MQ推送 │◄──┴───┤ 画面变更 │
│ │ │ │
└─────┬─────┘ └─────┬─────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ 更新文件缓存 │ │ 组态工具修改画面 │
│ 清除内存缓存 │ │ │
│ 通知前端刷新 │ └─────────────────┘
└────────┬────────┘
┌─────────────────┐
│ 前端重新执行阶段4│
│ 更新画面结构 │
│ 继续轮询 │
└─────────────────┘
```
## 6. 总结
全景监控模块的数据加载流程是一个典型的**静态结构 + 动态数据 + 实时刷新**的架构模式:
1. **顶部Tab菜单**:通过 `/userManage/dynamic/route` 获取全站总览图列表,提供一级导航
2. **左侧导航树**:通过 `/api/graph/picture/get/baseGraph/tree/list/v2` 按设备类型分类,提供二级导航
3. **静态结构**:通过 `/api/graph/picture/get/graph/properties` 获取画面的完整定义
4. **动态数据**:通过 `/api/rt/data/get` 获取信号的实时值
5. **实时刷新**:通过定时轮询保持数据更新,通过 MQ 推送处理画面变更
6. **缓存优化**:文件缓存加速静态数据加载,内存缓存加速实时数据查询
**核心设计思想**
- **分离静态与动态**:画面结构(静态)与信号数据(动态)分离,便于独立更新
- **轮询与推送结合**:常规数据轮询,画面变更推送,兼顾效率和实时性
- **多级缓存**:文件缓存 + 内存缓存,减少数据库和RTDB访问
- **前端组件分层**`MainDeviceMonitoring`(业务层)→ `ControlHMI`(核心监控组件)→ `Graph`(画面渲染组件)
理解这个流程对于开发和维护全景监控模块至关重要,特别是在处理画面更新、性能优化和故障排查时。
---
PR7050 全景监控数据加载流程解析 · 基于实际代码分析 · 最后更新 2026-06