Bläddra i källkod

优化log-stream.js,解决实时日志过多时,界面卡顿,CPU占用过高等问题

niujiuru 3 veckor sedan
förälder
incheckning
392c7db64f

+ 1 - 1
web-ui.service/web/pages/page2.html

@@ -85,7 +85,7 @@
               <button class="btn" title="点击重启联网服务" onclick="restartNetService()">重启</button>
             </div>
           </div>
-          <pre class="output" id="text4">自动实时获取数据...</pre>
+          <div class="output" id="text4">自动实时获取数据...</div>
         </div>
       </div>
       <!-- 结束 -->

+ 1 - 1
web-ui.service/web/pages/page3.html

@@ -63,7 +63,7 @@
             <button class="btn" title="点击重启时间服务" onclick="restartTimeService()">重启</button>
           </div>
         </div>
-        <pre class="output" id="text1">自动实时获取数据...</pre>
+        <div class="output" id="text1">自动实时获取数据...</div>
       </div>
     </div>
   </main>

+ 1 - 1
web-ui.service/web/pages/page4.html

@@ -49,7 +49,7 @@
             <button class="btn" title="点击重启时间服务" onclick="restartGnssService()">重启</button>
           </div>
         </div>
-        <pre class="output" id="text1">自动实时获取数据...</pre>
+        <div class="output" id="text1">自动实时获取数据...</div>
       </div>
     </div>
   </main>

+ 10 - 6
web-ui.service/web/pages/page5.html

@@ -35,15 +35,19 @@
       <div class="status-bar">
         <div class="status-item">
           <span class="label">网口相机</span>
-          <span class="value" id="avar5">--</span>
+          <span class="value">192.168.100.100</span>
         </div>
         <div class="status-item">
-          <span class="label">相机地址</span>
-          <span class="value" id="avar6">--</span>
+          <span class="label">子网掩码</span>
+          <span class="value">255.255.255.0</span>
         </div>
         <div class="status-item">
-          <span class="label">子网掩码</span>
-          <span class="value" id="avar7">--</span>
+          <span class="label">电源状态</span>
+          <span class="value" id="avar5">--</span>
+        </div>
+        <div class="status-item">
+          <span class="label">相机状态</span>
+          <span class="value" id="avar6">--</span>
         </div>
         <div class="status-item button-item"">
           <span style="margin:0 1px;"></span>
@@ -120,7 +124,7 @@
               <button class="btn" title="点击重启相机服务" onclick="restartCameraService()">重启</button>
             </div>
           </div>
-          <pre class="output" id="text1">自动实时获取数据...</pre>
+          <div class="output" id="text1">自动实时获取数据...</div>
         </div>
       </div>
       <!-- 结束 -->

+ 1 - 0
web-ui.service/web/static/css/page5.css

@@ -100,6 +100,7 @@
     background:#020617;
     border:1px solid #1f2937;
     border-radius:4px;
+    margin-bottom:14px;
 }
 
 .camera-image-box img {

+ 38 - 22
web-ui.service/web/static/js/log-stream.js

@@ -1,14 +1,19 @@
 let logSource = null;
 let currentUnit = null;
+let autoScroll = true;
 
 const MAX_LOG_LINES = 2000;
 let logLines = [];
 
-function colorLog(line) {
-    let s = line
+function escapeHtml(s) {
+    return s
         .replace(/&/g, "&amp;")
         .replace(/</g, "&lt;")
         .replace(/>/g, "&gt;");
+}
+
+function colorLog(line) {
+    const s = escapeHtml(line);
 
     const levels = [
         ["TRACE", "log-trace"],
@@ -21,8 +26,8 @@ function colorLog(line) {
         ["PANIC", "log-panic"]
     ];
 
-    for (const [level, cls] of levels) {
-        if (s.includes(level) || s.includes(level.toLowerCase())) {
+    for (const [lvl, cls] of levels) {
+        if (s.includes(lvl) || s.includes(lvl.toLowerCase())) {
             return `<span class="${cls}">${s}</span>`;
         }
     }
@@ -57,6 +62,15 @@ function connectLog(unit, target) {
 
     logSource = source;
 
+    el.addEventListener("scroll", () => {
+        const distance = el.scrollHeight - el.scrollTop - el.clientHeight;
+        if (distance < 20) {
+            autoScroll = true;
+        } else {
+            autoScroll = false;
+        }
+    });
+
     source.onmessage = (e) => {
         if (source !== logSource) {
             return;
@@ -65,17 +79,23 @@ function connectLog(unit, target) {
         logLines.push(e.data);
 
         if (logLines.length > MAX_LOG_LINES) {
-            logLines.splice(
-                0,
-                logLines.length - MAX_LOG_LINES
-            );
+            logLines.shift();
         }
 
-        el.innerHTML = logLines
-            .map(colorLog)
-            .join("<br>") + "<br><br><br>";
+        const line = document.createElement("div");
+        line.innerHTML = colorLog(e.data);
 
-        el.scrollTop = el.scrollHeight;
+        el.appendChild(line);
+
+        while (el.childElementCount > MAX_LOG_LINES) {
+            el.removeChild(el.firstElementChild);
+        }
+
+        if (autoScroll) {
+        requestAnimationFrame(() => {
+            el.scrollTop = el.scrollHeight;
+        });
+        }
     };
 
     source.onerror = () => {
@@ -83,7 +103,7 @@ function connectLog(unit, target) {
             return;
         }
 
-        console.log(
+        console.warn(
             `[log-stream] error unit=${unit}, state=${source.readyState}`
         );
     };
@@ -111,22 +131,18 @@ function clearLog(target) {
         : target;
 
     if (el) {
-        el.textContent = "";
+        el.replaceChildren();
+        el.scrollTop = 0;
     }
 }
 
 function copyLog(target) {
-    const el = typeof target === "string"
-        ? document.getElementById(target)
-        : target;
-
-    if (!el) return;
-
-    const text = el.value !== undefined ? el.value : el.innerText;
+    const text = logLines.join("\n");
 
     if (navigator.clipboard) {
         navigator.clipboard.writeText(text)
-            .then(() => alert("复制成功"));
+            .then(() => alert("复制成功"))
+            .catch(() => alert("复制失败"));
     } else {
         const ta = document.createElement("textarea");
         ta.value = text;