From 112912730c477a64f7b27086794a3bc30e6787c7 Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期二, 03 十一月 2026 13:22:14 +0800
Subject: [PATCH] feat: 设备实时报警订阅与监控/巡检页面优化

---
 src/api/environmentAccess/deviceMonitor.js |   66 +++++++++++++++++++++++++++++++++
 1 files changed, 66 insertions(+), 0 deletions(-)

diff --git a/src/api/environmentAccess/deviceMonitor.js b/src/api/environmentAccess/deviceMonitor.js
index a3586a7..0b7edf5 100644
--- a/src/api/environmentAccess/deviceMonitor.js
+++ b/src/api/environmentAccess/deviceMonitor.js
@@ -1,4 +1,5 @@
 import request from "@/utils/request";
+import { getToken } from "@/utils/auth";
 
 export const listDeviceMonitor = () => request({ url: "/environmentAccess/deviceMonitor/list", method: "get" });
 export const collectTelemetry = () => request({ url: "/environmentAccess/deviceMonitor/collect", method: "post" });
@@ -9,3 +10,68 @@
   data: { deviceId, action },
 });
 
+/**
+ * 浣跨敤甯� Authorization 璇锋眰澶寸殑 fetch 璁㈤槄 SSE 鎶ヨ娴併��
+ * 鍘熺敓 EventSource 鏃犳硶鎼哄甫鏈」鐩殑 Bearer Token锛屽洜姝ゅ湪杩欓噷瑙f瀽浜嬩欢娴併��
+ */
+export function subscribeDeviceAlarms(onAlarm, onState = () => {}) {
+  let stopped = false;
+  let controller;
+  let retryTimer;
+
+  const processBlock = (block) => {
+    let event = "message";
+    const data = [];
+    block.split("\n").forEach((line) => {
+      if (line.startsWith("event:")) event = line.slice(6).trim();
+      if (line.startsWith("data:")) data.push(line.slice(5).trim());
+    });
+    if (event !== "alarm" || !data.length) return;
+    try { onAlarm(JSON.parse(data.join("\n"))); } catch (error) { console.warn("鎶ヨ鏁版嵁瑙f瀽澶辫触", error); }
+  };
+
+  const connect = async () => {
+    if (stopped) return;
+    controller = new AbortController();
+    onState("connecting");
+    try {
+      const response = await fetch(`${import.meta.env.VITE_APP_BASE_API}/environmentAccess/deviceMonitor/alarm-stream`, {
+        headers: { Authorization: `Bearer ${getToken()}` },
+        signal: controller.signal,
+        cache: "no-store",
+      });
+      if (!response.ok || !response.body) throw new Error(`SSE ${response.status}`);
+      onState("connected");
+      const reader = response.body.getReader();
+      const decoder = new TextDecoder("utf-8");
+      let buffer = "";
+      while (!stopped) {
+        const { value, done } = await reader.read();
+        if (done) break;
+        buffer += decoder.decode(value, { stream: true }).replace(/\r/g, "");
+        let boundary;
+        while ((boundary = buffer.indexOf("\n\n")) >= 0) {
+          processBlock(buffer.slice(0, boundary));
+          buffer = buffer.slice(boundary + 2);
+        }
+      }
+    } catch (error) {
+      if (!stopped && error?.name !== "AbortError") console.warn("鎶ヨ鎺ㄩ�佽繛鎺ヤ腑鏂�", error);
+    }
+    if (!stopped) {
+      onState("reconnecting");
+      retryTimer = window.setTimeout(connect, 3000);
+    }
+  };
+
+  connect();
+  return {
+    close() {
+      stopped = true;
+      window.clearTimeout(retryTimer);
+      controller?.abort();
+      onState("closed");
+    },
+  };
+}
+

--
Gitblit v1.9.3