From 099a61b80e76634064ff2b41dc800b19367f88e2 Mon Sep 17 00:00:00 2001 From: zch Date: Thu, 9 Apr 2026 15:43:19 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E7=89=A9=E8=81=94?= =?UTF-8?q?=E7=BD=91=E6=8A=A5=E8=A1=A8=E6=A8=A1=E5=9D=97=E5=8F=8A=E5=AE=9E?= =?UTF-8?q?=E6=97=B6=E5=91=8A=E8=AD=A6=E5=A4=84=E7=90=86=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增多个物联网报表页面,包括趋势总览、质量诊断、设备对比等报表视图 添加实时告警处理弹窗组件,支持告警展示、SOP步骤查看和处理操作 实现计量平衡、能效分析和仪表工况等高级报表功能 引入新的图表组件和工具函数,优化报表数据展示效果 重构告警规则表单,增强通知组选择器的可读性 --- src/components/alarm/RealtimeAlarmModal.vue | 482 +++++++ src/utils/alarmRealtime.ts | 88 ++ .../ems/record/recordAlarmRule/index.vue | 9 +- .../ems/report/components/AlarmTrendPanel.vue | 99 ++ .../components/EfficiencyScoreBoard.vue | 127 ++ .../report/components/IotReportWorkbench.vue | 1256 +++++++++++++++++ .../components/MeterBalanceTopology.vue | 104 ++ .../index.vue | 346 +++++ .../energyAbnormalAlertReport/index.vue | 318 +++++ .../instrumentConditionReport/index.vue | 510 +++++++ .../report/iotDeviceCompareReport/index.vue | 15 + .../ems/report/iotQualityReport/index.vue | 15 + src/views/ems/report/iotTrendReport/index.vue | 15 + .../ems/report/meterBalanceReport/index.vue | 385 +++++ .../ems/report/realtimeIOTCurve/index.vue | 988 +++++++++++++ 15 files changed, 4756 insertions(+), 1 deletion(-) create mode 100644 src/components/alarm/RealtimeAlarmModal.vue create mode 100644 src/utils/alarmRealtime.ts create mode 100644 src/views/ems/report/components/AlarmTrendPanel.vue create mode 100644 src/views/ems/report/components/EfficiencyScoreBoard.vue create mode 100644 src/views/ems/report/components/IotReportWorkbench.vue create mode 100644 src/views/ems/report/components/MeterBalanceTopology.vue create mode 100644 src/views/ems/report/comprehensiveEnergyEfficiencyReport/index.vue create mode 100644 src/views/ems/report/energyAbnormalAlertReport/index.vue create mode 100644 src/views/ems/report/instrumentConditionReport/index.vue create mode 100644 src/views/ems/report/iotDeviceCompareReport/index.vue create mode 100644 src/views/ems/report/iotQualityReport/index.vue create mode 100644 src/views/ems/report/iotTrendReport/index.vue create mode 100644 src/views/ems/report/meterBalanceReport/index.vue create mode 100644 src/views/ems/report/realtimeIOTCurve/index.vue diff --git a/src/components/alarm/RealtimeAlarmModal.vue b/src/components/alarm/RealtimeAlarmModal.vue new file mode 100644 index 0000000..6f9b88a --- /dev/null +++ b/src/components/alarm/RealtimeAlarmModal.vue @@ -0,0 +1,482 @@ + + + + + diff --git a/src/utils/alarmRealtime.ts b/src/utils/alarmRealtime.ts new file mode 100644 index 0000000..e749924 --- /dev/null +++ b/src/utils/alarmRealtime.ts @@ -0,0 +1,88 @@ +import type { EmsRecordAlarmDataVO } from '@/api/ems/types'; + +export const EMS_REALTIME_ALARM_EVENT = 'ems:alarm:realtime'; +export const EMS_REALTIME_ALARM_PAYLOAD_TYPE = 'ems_alarm_realtime'; + +export interface EmsRealtimeAlarmEnvelope { + eventType: typeof EMS_REALTIME_ALARM_PAYLOAD_TYPE; + channel?: 'SSE' | 'WEBSOCKET' | 'UNKNOWN'; + source?: string; + generatedAt?: string; + alarms: EmsRecordAlarmDataVO[]; +} + +interface LegacyRealtimeAlarmEnvelope { + eventType?: string; + source?: string; + eventTime?: string; + payload?: { + records?: EmsRecordAlarmDataVO[]; + }; +} + +export interface ParsedAlarmMessage { + envelope: EmsRealtimeAlarmEnvelope | null; + displayMessage: string; +} + +export const useAlarmRealtimeBus = () => useEventBus(EMS_REALTIME_ALARM_EVENT); + +const isRealtimeAlarmEnvelope = (value: unknown): value is EmsRealtimeAlarmEnvelope => { + if (!value || typeof value !== 'object') { + return false; + } + const envelope = value as EmsRealtimeAlarmEnvelope; + return envelope.eventType === EMS_REALTIME_ALARM_PAYLOAD_TYPE && Array.isArray(envelope.alarms); +}; + +const normalizeLegacyEnvelope = (value: unknown): EmsRealtimeAlarmEnvelope | null => { + if (!value || typeof value !== 'object') { + return null; + } + const legacyEnvelope = value as LegacyRealtimeAlarmEnvelope; + const records = legacyEnvelope.payload?.records; + if (legacyEnvelope.eventType !== 'EMS_REALTIME_ALARM_BATCH' || !Array.isArray(records)) { + return null; + } + return { + eventType: EMS_REALTIME_ALARM_PAYLOAD_TYPE, + source: legacyEnvelope.source, + generatedAt: legacyEnvelope.eventTime, + alarms: records + }; +}; + +export const parseAlarmRealtimeMessage = (rawMessage: unknown): ParsedAlarmMessage => { + const fallbackMessage = typeof rawMessage === 'string' ? rawMessage : JSON.stringify(rawMessage ?? ''); + if (typeof rawMessage !== 'string') { + return { + envelope: null, + displayMessage: fallbackMessage + }; + } + try { + const parsed = JSON.parse(rawMessage); + const envelope = isRealtimeAlarmEnvelope(parsed) ? parsed : normalizeLegacyEnvelope(parsed); + if (!envelope) { + return { + envelope: null, + displayMessage: fallbackMessage + }; + } + const firstAlarm = envelope.alarms[0]; + const alarmCount = envelope.alarms.length; + const displayMessage = + alarmCount > 1 + ? `收到 ${alarmCount} 条实时告警,已进入待处置队列` + : `收到实时告警:${firstAlarm?.alarmTitle || firstAlarm?.monitorName || firstAlarm?.monitorId || '未命名告警'}`; + return { + envelope, + displayMessage + }; + } catch { + return { + envelope: null, + displayMessage: fallbackMessage + }; + } +}; diff --git a/src/views/ems/record/recordAlarmRule/index.vue b/src/views/ems/record/recordAlarmRule/index.vue index 0a1662b..db3035a 100644 --- a/src/views/ems/record/recordAlarmRule/index.vue +++ b/src/views/ems/record/recordAlarmRule/index.vue @@ -226,7 +226,14 @@ - + diff --git a/src/views/ems/report/components/AlarmTrendPanel.vue b/src/views/ems/report/components/AlarmTrendPanel.vue new file mode 100644 index 0000000..ad01f77 --- /dev/null +++ b/src/views/ems/report/components/AlarmTrendPanel.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/src/views/ems/report/components/EfficiencyScoreBoard.vue b/src/views/ems/report/components/EfficiencyScoreBoard.vue new file mode 100644 index 0000000..76f1b27 --- /dev/null +++ b/src/views/ems/report/components/EfficiencyScoreBoard.vue @@ -0,0 +1,127 @@ + + + + + diff --git a/src/views/ems/report/components/IotReportWorkbench.vue b/src/views/ems/report/components/IotReportWorkbench.vue new file mode 100644 index 0000000..9b3340d --- /dev/null +++ b/src/views/ems/report/components/IotReportWorkbench.vue @@ -0,0 +1,1256 @@ + + + + + diff --git a/src/views/ems/report/components/MeterBalanceTopology.vue b/src/views/ems/report/components/MeterBalanceTopology.vue new file mode 100644 index 0000000..540c397 --- /dev/null +++ b/src/views/ems/report/components/MeterBalanceTopology.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/src/views/ems/report/comprehensiveEnergyEfficiencyReport/index.vue b/src/views/ems/report/comprehensiveEnergyEfficiencyReport/index.vue new file mode 100644 index 0000000..3306354 --- /dev/null +++ b/src/views/ems/report/comprehensiveEnergyEfficiencyReport/index.vue @@ -0,0 +1,346 @@ + + + + + diff --git a/src/views/ems/report/energyAbnormalAlertReport/index.vue b/src/views/ems/report/energyAbnormalAlertReport/index.vue new file mode 100644 index 0000000..9e0429f --- /dev/null +++ b/src/views/ems/report/energyAbnormalAlertReport/index.vue @@ -0,0 +1,318 @@ + + + + + diff --git a/src/views/ems/report/instrumentConditionReport/index.vue b/src/views/ems/report/instrumentConditionReport/index.vue new file mode 100644 index 0000000..064fd08 --- /dev/null +++ b/src/views/ems/report/instrumentConditionReport/index.vue @@ -0,0 +1,510 @@ + + + + + diff --git a/src/views/ems/report/iotDeviceCompareReport/index.vue b/src/views/ems/report/iotDeviceCompareReport/index.vue new file mode 100644 index 0000000..23b5c7a --- /dev/null +++ b/src/views/ems/report/iotDeviceCompareReport/index.vue @@ -0,0 +1,15 @@ + + + diff --git a/src/views/ems/report/iotQualityReport/index.vue b/src/views/ems/report/iotQualityReport/index.vue new file mode 100644 index 0000000..db9b4a4 --- /dev/null +++ b/src/views/ems/report/iotQualityReport/index.vue @@ -0,0 +1,15 @@ + + + diff --git a/src/views/ems/report/iotTrendReport/index.vue b/src/views/ems/report/iotTrendReport/index.vue new file mode 100644 index 0000000..1112466 --- /dev/null +++ b/src/views/ems/report/iotTrendReport/index.vue @@ -0,0 +1,15 @@ + + + diff --git a/src/views/ems/report/meterBalanceReport/index.vue b/src/views/ems/report/meterBalanceReport/index.vue new file mode 100644 index 0000000..fd4dcac --- /dev/null +++ b/src/views/ems/report/meterBalanceReport/index.vue @@ -0,0 +1,385 @@ + + + + + diff --git a/src/views/ems/report/realtimeIOTCurve/index.vue b/src/views/ems/report/realtimeIOTCurve/index.vue new file mode 100644 index 0000000..d3c6565 --- /dev/null +++ b/src/views/ems/report/realtimeIOTCurve/index.vue @@ -0,0 +1,988 @@ + + + + +