IEC61850 客户端模型发现进度条修复
版本: 1.0
日期: 2026-06-29
状态: 已实施
1. 问题背景
IEC61850 客户端在执行“发现模型”时,前端进度条偶发出现显示异常,主要表现为:
| 现象 | 触发场景 | 影响 |
|---|---|---|
| 进度条偶尔不显示 | 模型发现接口较快返回,或状态轮询尚未拿到后端任务态 | 用户无法确认发现任务是否已启动 |
| 进度卡在 0% | 前端先启动展示,但后端仍返回旧的空闲状态或粗粒度进度 | 容易误判为任务卡死 |
| 进度条在动但秒数不一致 | 本地计时器与后端任务状态各自推进,连接阶段又会中断轮询 | 展示信息不可信 |
| 自动连接后进度提前消失 | 未连接状态下触发发现模型,后端先连接再发现 | 发现阶段仍在运行,但前端认为连接成功后即可停止 |
本次修复目标是让 IEC61850 客户端模型发现进度在“连接 + 发现 + 后处理”的完整链路中保持稳定、可恢复、可解释。
2. 根因分析
2.1 前端先轮询,后端任务状态尚未建立
发现模型按钮点击后,前端会立即启动进度展示和轮询,但后端状态可能还停留在上一次任务的 idle/done。如果前端过早采信旧状态,就会把刚启动的进度条停止或维持在 0%。
2.2 连接进度与发现进度共用状态,缺少操作类型区分
原实现只暴露 progress/status 等粗粒度字段,没有明确当前是 connect 还是 discover。当发现模型需要先自动连接时,前端无法判断当前进度属于连接阶段还是模型发现阶段。
2.3 连接成功会打断发现进度轮询
fetchDeviceStatus() 在检测到 IEC61850 服务状态变为已连接后,会停止连接进度轮询。对于“未连接时点击发现模型”的场景,连接成功只是发现流程的前置阶段,后续远程模型发现仍在继续,前端却提前停止了进度更新。
2.4 后端发现过程进度粒度过粗
后端原先主要返回 10%、50%、100% 等少量节点,真实发现过程中缺少按逻辑设备、构建模型、读取描述等阶段的连续反馈。大模型或网络较慢时,前端容易长时间停在某一个百分比。
2.5 前端本地秒数与后端任务时间不同步
前端使用本地定时器显示秒数,但后端任务已经运行的时间没有纳入恢复逻辑。切换页面、重新拉取设备状态或轮询重入时,秒数可能重置,导致同一条进度展示里秒数前后不一致。
3. 修复方案
3.1 后端新增统一进度快照
在 IEC61850 客户端处理器中增加任务级进度快照,统一描述当前进度任务:
| 字段 | 说明 |
|---|---|
active | 当前是否有连接或发现任务正在运行 |
operation | 当前操作类型,取值为 connect 或 discover |
operation_id | 本次任务唯一标识,用于前端过滤旧状态 |
progress | 任务进度百分比 |
status | idle/running/done/failed 等状态 |
message | 当前阶段说明 |
elapsed_seconds | 后端统计的任务耗时 |
对应新增 _begin_progress()、_update_progress()、_finish_progress() 三个内部方法,连接和发现流程都通过同一套快照更新状态。
3.2 发现模型流程拆分为明确阶段
remote_discover_model() 现在会按阶段持续更新进度:
| 阶段 | 进度范围 | 说明 |
|---|---|---|
| 初始化 | 10% ~ 20% | 创建发现任务;必要时先建立连接 |
| 远程发现 | 20% ~ 70% | 按逻辑设备发现模型,并通过回调持续推进 |
| 构建模型 | 75% | 生成统一模型结构 |
| 读取描述 | 80% ~ 85% | 补充 dU 等描述信息 |
| 数据整理 | 88% ~ 96% | 生成前端需要的模型、测点和统计数据 |
| 完成 | 100% | 写入最终结果并结束任务 |
如果发现过程抛出异常,后端会将快照置为 failed,并保留失败消息,避免前端一直停留在运行态。
3.3 前端按操作类型恢复和过滤进度
前端进度轮询增加 mode 参数,明确当前轮询的是连接还是发现:
- 发现模型时只接受当前
operation=discover的活动任务。 - 通过
operation_id过滤旧任务状态,避免上一轮done/idle把新进度打断。 - 页面重新拉取设备信息时,如果后端仍有 IEC61850 任务活动,会按
operation自动恢复对应进度展示。 - 轮询请求增加重入保护,避免上一次轮询未返回时下一次轮询又发起,造成状态乱序。
3.4 避免连接成功误停发现进度
fetchDeviceStatus() 只在当前进度模式为 connect 时,才会因连接状态变更而停止轮询。当前模式为 discover 时,即使服务端已经连上,也会继续等待发现流程返回最终状态。
3.5 统一秒数来源和展示节奏
前端计时逻辑改为基于任务开始时间计算,并吸收后端返回的 elapsed_seconds:
- 本地展示使用时间戳差值,不再依赖定时器累计次数。
- 后端返回耗时更大时,前端会向后对齐,避免秒数倒退。
- 进度文本只在一个位置显示秒数,避免阶段文本和进度文本各自显示不同耗时。
3.6 保证快速任务也能被用户看见
发现模型前端在发起 HTTP 请求前,先等待一次 Vue 渲染和浏览器帧,让初始进度行有机会真正绘制出来。任务结束后也保留一个很短的收尾展示时间,避免快速完成时进度条一闪而过。
4. 修改文件清单
| 文件 | 改动 | 说明 |
|---|---|---|
front/src/views/Device.vue | 中 | 重构 IEC61850 连接/发现进度轮询、秒数同步、旧状态过滤和快速任务展示 |
front/src/api/deviceApi.ts | 小 | 扩展 IEC61850 进度接口类型,增加 active/operation/operation_id/elapsed_seconds/message |
src/device/protocol/iec61850_handler.py | 中 | 增加进度快照、任务互斥、发现阶段进度和失败收尾 |
src/device/core/device.py | 小 | 更新 IEC61850 进度查询接口说明 |
src/proto/iec61850/iec61850_client.py | 小 | 将发现进度回调传入模型发现服务,并补充构建/描述读取阶段 |
src/proto/iec61850/model/discovery.py | 小 | 按逻辑设备发现进度回调,提升长耗时发现过程的可见性 |
src/tests/iec61850/test_discovery_progress.py | 新增 | 覆盖发现进度阶段、失败收尾和任务互斥 |
src/tests/iec61850/test_remote_discovery_refresh.py | 小 | 适配新增的发现进度回调参数 |
5. 修复后的行为
模型发现
- 点击发现模型后,进度条会稳定显示,不再依赖后端第一次轮询是否已经进入运行态。
- 未连接时触发发现模型,会显示连接和发现的连续进度,不会在连接成功后提前消失。
- 大模型发现时,进度会随逻辑设备发现、模型构建、描述读取等阶段逐步推进。
- 发现失败时,进度状态会进入失败态并展示失败原因。
秒数显示
- 秒数只显示一份,避免同一条进度中出现多个不同耗时。
- 页面刷新或设备状态重新拉取后,如果后端任务仍在运行,秒数会按后端任务耗时恢复。
- 轮询乱序或重入不会导致秒数回退。
任务互斥
- 连接任务和发现任务都纳入同一进度任务管理。
- 当已有 IEC61850 连接/发现任务运行时,新任务会被拒绝,避免多个后台任务抢占同一个进度状态。
6. 验证结果
6.1 后端测试
python -m pytest -q src/tests/iec61850/test_discovery_progress.py src/tests/iec61850/test_remote_discovery_refresh.py
6 passed
python -m pytest -q src/tests/iec61850
98 passed, 25 skipped, 1 warning新增测试覆盖:
- 远程发现模型时按阶段推进进度,并在完成后进入
done/100%。 - 发现异常时进入
failed,并释放活动任务状态。 - 已有发现任务运行时,第二个任务会被拒绝。
6.2 代码质量与前端构建
ruff check src/device/core/device.py src/device/protocol/iec61850_handler.py src/proto/iec61850/iec61850_client.py src/proto/iec61850/model/discovery.py src/tests/iec61850/test_discovery_progress.py src/tests/iec61850/test_remote_discovery_refresh.py
passed
ruff format --check src/device/core/device.py src/device/protocol/iec61850_handler.py src/proto/iec61850/iec61850_client.py src/proto/iec61850/model/discovery.py src/tests/iec61850/test_discovery_progress.py src/tests/iec61850/test_remote_discovery_refresh.py
passed
npm run type-check
passed
npm run build-only
passed7. 后续建议
- 在 IEC61850 客户端页面增加可选的阶段明细日志,方便现场定位具体卡在哪个 LD 或哪个读取阶段。
- 如果后续模型发现还要支持取消任务,可以复用本次新增的
operation_id作为取消目标。 - 对前端其他长耗时操作复用同样的“后端快照 + 操作类型 + 任务 ID + 后端耗时”模式,避免类似进度展示问题重复出现。