Просмотр исходного кода

编写page5页面js和后台接口代码,完成40%

niujiuru 3 недель назад
Родитель
Сommit
5b1038e527

+ 101 - 0
web-ui.service/page5_handler.go

@@ -1 +1,102 @@
 package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"os"
+	"os/exec"
+	"time"
+)
+
+func downloadCameraLog(w http.ResponseWriter, r *http.Request) {
+	if r.Method != http.MethodGet {
+		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
+		return
+	}
+
+	filename := fmt.Sprintf("camera.log.%s.tar.gz", time.Now().Format("20060102150405"))
+	tmpFile := fmt.Sprintf("/tmp/%d.tar.gz", time.Now().UnixNano())
+
+	defer os.Remove(tmpFile)
+
+	cmd := exec.Command(
+		"tar",
+		"--warning=no-file-changed",
+		"-czf",
+		tmpFile,
+		"-C",
+		"/opt/yfkj/camera-capture.service/log",
+		".",
+	)
+
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		if exitErr, ok := err.(*exec.ExitError); !ok || exitErr.ExitCode() != 1 {
+			http.Error(w, string(out), http.StatusInternalServerError)
+			return
+		}
+	}
+
+	w.Header().Set("Content-Type", "application/gzip")
+	w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filename))
+
+	http.ServeFile(w, r, tmpFile)
+}
+
+func restartCameraService(w http.ResponseWriter, r *http.Request) {
+	if r.Method != http.MethodPost {
+		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
+		return
+	}
+
+	cmd := exec.Command("systemctl", "restart", "yfkj-camera-capture.service")
+
+	if out, err := cmd.CombinedOutput(); err != nil {
+		http.Error(w, string(out)+err.Error(), http.StatusInternalServerError)
+		return
+	}
+
+	w.Header().Set("Content-Type", "application/json")
+	w.Write([]byte(`{"status":"ok"}`))
+}
+
+func cameraStatusHandler(w http.ResponseWriter, r *http.Request) {
+	var countAll, countHK, countDH string
+	var power struct {
+		Enable string `json:"enable"`
+	}
+	var check string
+
+	avar1, avar2, avar3, avar4, avar5, avar6 := noValue, noValue, noValue, noValue, noValue, noValue
+
+	if callRPCResult(r.Context(), 7003, "core.getSupportedCameraCount", map[string]string{"type": "all"}, &countAll) == nil {
+		avar1 = "🟢正常"
+		avar2 = countAll
+	}
+
+	if callRPCResult(r.Context(), 7003, "core.getSupportedCameraCount", map[string]string{"type": "hk"}, &countHK) == nil {
+		avar3 = countHK
+	}
+
+	if callRPCResult(r.Context(), 7003, "core.getSupportedCameraCount", map[string]string{"type": "dh"}, &countDH) == nil {
+		avar4 = countDH
+	}
+
+	callRPCResult(r.Context(), 7003, "core.getGigeCameraPower", nil, &power)
+	if power.Enable == "true" {
+		avar5 = "🟢打开"
+	}
+
+	callRPCResult(r.Context(), 7003, "core.checkGigeCamera", map[string]string{"ip": "192.168.100.100", "prefix": "24"}, &check)
+	if check == "success" {
+		avar6 = "🟢正常"
+	}
+
+	w.Header().Set("Content-Type", "application/json; charset=utf-8")
+	json.NewEncoder(w).Encode(map[string]string{
+		"avar1": avar1, "avar2": avar2,
+		"avar3": avar3, "avar4": avar4,
+		"avar5": avar5, "avar6": avar6,
+	})
+}

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

@@ -30,6 +30,10 @@
           <span class="label">大华数量</span>
           <span class="value" id="avar4">--</span>
         </div>
+        <div class="status-item button-item"">
+          <span style="margin:0 1px;"></span>
+          <button class="btn" title="点击刷新最新数据" id="btn1" onclick="getCameraStatus()">数据刷新</button>
+        </div>
       </div>
 
       <div class="status-bar">
@@ -38,11 +42,11 @@
           <span class="value">192.168.100.100/24</span>
         </div>
         <div class="status-item">
-          <span class="label">电源状态</span>
+          <span class="label">供电开关</span>
           <span class="value" id="avar5">--</span>
         </div>
         <div class="status-item">
-          <span class="label">相机状态</span>
+          <span class="label">连接状态</span>
           <span class="value" id="avar6">--</span>
         </div>
         <div class="status-item button-item"">
@@ -50,6 +54,8 @@
           <button class="btn" title="打开网口相机供电" onclick="cameraPower('true')">上电</button>
           <span style="margin:0 1px;"></span>
           <button class="btn" title="关闭网口相机供电" onclick="cameraPower('false')">断电</button>
+          <span style="margin:0 1px;"></span>
+          <button class="btn" title="检测网口相机是否连通(ping测试)" onclick="cameraPing()">检测</button>
         </div>
       </div>
     </div>
@@ -61,13 +67,13 @@
           <div class="card-header">
             <h2>拍照测试</h2>
             <div class="camera-actions">
-              <button class="btn" onclick="takeOnePhoto()">单次拍照</button>
+              <button class="btn" id="btn2" onclick="takeOnePhoto()">单次拍照</button>
               <span style="margin:0 1px;"></span>
-              <button class="btn" onclick="startCameraPreview()">连续拍照</button>
+              <button class="btn" id="btn3" onclick="startCameraPreview()">连续拍照</button>
               <span style="margin:0 1px;"></span>
-              <button class="btn" onclick="stopCameraPreview()">停止连拍</button>
+              <button class="btn" id="btn4" onclick="stopCameraPreview()">停止连拍</button>
               <span style="margin:0 1px;"></span>
-              <button class="btn" onclick="downloadCameraImage()">下载图像</button>
+              <button class="btn" id="btn5" onclick="downloadCameraImage()">图像下载</button>
             </div>
           </div>
           <div class="camera-image-box">

+ 6 - 3
web-ui.service/web/static/js/app.js

@@ -59,9 +59,12 @@ async function fetchIMEI() {
 function setText(id, value)
 {
   const el = document.getElementById(id);
-  if (el) {
-    el.textContent = value ?? "--";
-  }
+  if (el) el.textContent = value ?? "--";
+}
+
+function setBtnStatus(id, enabled) {
+  const btn = document.getElementById(id);
+  if (btn) btn.disabled = !enabled;
 }
 
 let sysTimeTimer = null;

+ 18 - 65
web-ui.service/web/static/js/page1.js

@@ -3,7 +3,6 @@ let memChart       = null;
 let diskChart      = null;
 let sysStatusTimer = null;
 let resizeHandler  = null;
-let page1Active    = false;
 
 function getSystemInfo(){
   fetch("/api/system/info")
@@ -110,28 +109,14 @@ function getLoadInfo(){
       return r.json();
     })
     .then(data => {
-      if(!page1Active){
-        return;
-      }
-      document.getElementById("load1m").textContent = data.load1m || "--";
-      document.getElementById("load5m").textContent = data.load5m || "--";
-      document.getElementById("load15m").textContent = data.load15m || "--";
-      document.getElementById("runQueue").textContent = data.runQueue || "--";
-      document.getElementById("bootTime").textContent = data.bootTime || "--";
-      document.getElementById("uptime").textContent = data.uptime || "--";
+      ["load1m","load5m","load15m","runQueue","bootTime","uptime"]
+        .forEach(id => setText(id, data[id]));
     })
     .catch(e => {
-      if(!page1Active){
-        return;
-      }
-      console.error("network status failed:", e);
-
-      document.getElementById("load1m").textContent = "--";
-      document.getElementById("load5m").textContent = "--";
-      document.getElementById("load15m").textContent = "--";
-      document.getElementById("runQueue").textContent = "--";
-      document.getElementById("bootTime").textContent = "--";
-      document.getElementById("uptime").textContent = "--";
+      console.error("load info failed:", e);
+
+      ["load1m","load5m","load15m","runQueue","bootTime","uptime"]
+        .forEach(id => setText(id, null));
     });
 }
 
@@ -145,50 +130,22 @@ function getServiceInfo(){
       return r.json();
     })
     .then(data => {
-      if(!page1Active){
-        return;
-      }
-      document.getElementById("var1").textContent = data.var1 || "--";
-      document.getElementById("var2").textContent = data.var2 || "--";
-      document.getElementById("var3").textContent = data.var3 || "--";
-      document.getElementById("var4").textContent = data.var4 || "--";
-      document.getElementById("var5").textContent = data.var5 || "--";
-      document.getElementById("var6").textContent = data.var6 || "--";
-      document.getElementById("var7").textContent = data.var7 || "--";
-      document.getElementById("var8").textContent = data.var8 || "--";
-      document.getElementById("var9").textContent = data.var9 || "--";
-      document.getElementById("var11").textContent = data.var11 || "--";
-      document.getElementById("var22").textContent = data.var22 || "--";
-      document.getElementById("var33").textContent = data.var33 || "--";
-      document.getElementById("var44").textContent = data.var44 || "--";
-      document.getElementById("var55").textContent = data.var55 || "--";
-      document.getElementById("var66").textContent = data.var66 || "--";
-      document.getElementById("var77").textContent = data.var77 || "--";
-      document.getElementById("var88").textContent = data.var88 || "--";
+      [
+        "var1","var2","var3","var4","var5",
+        "var6","var7","var8","var9",
+        "var11","var22","var33","var44",
+        "var55","var66","var77","var88"
+      ].forEach(id => setText(id, data[id]));
     })
     .catch(e => {
-      if(!page1Active){
-        return;
-      }
       console.error("getAllServiceStatus() failed:", e);
 
-      document.getElementById("var1").textContent = "--";
-      document.getElementById("var2").textContent = "--";
-      document.getElementById("var3").textContent = "--";
-      document.getElementById("var4").textContent = "--";
-      document.getElementById("var5").textContent = "--";
-      document.getElementById("var6").textContent = "--";
-      document.getElementById("var7").textContent = "--";
-      document.getElementById("var8").textContent = "--";
-      document.getElementById("var9").textContent = "--";
-      document.getElementById("var11").textContent = "--";
-      document.getElementById("var22").textContent = "--";
-      document.getElementById("var33").textContent = "--";
-      document.getElementById("var44").textContent = "--";
-      document.getElementById("var55").textContent = "--";
-      document.getElementById("var66").textContent = "--";
-      document.getElementById("var77").textContent = "--";
-      document.getElementById("var88").textContent = "--";
+      [
+        "var1","var2","var3","var4","var5",
+        "var6","var7","var8","var9",
+        "var11","var22","var33","var44",
+        "var55","var66","var77","var88"
+      ].forEach(id => setText(id, null));
     });
 }
 
@@ -304,8 +261,6 @@ function switchAutoUpgrade(action)
 }
 
 function initPage1(){
-  page1Active = true;
-
   cpuChart=echarts.init(document.getElementById("cpu-chart"));
   memChart=echarts.init(document.getElementById("mem-chart"));
   diskChart=echarts.init(document.getElementById("disk-chart"));
@@ -353,8 +308,6 @@ function initPage1(){
 }
 
 function exitPage1(){
-  page1Active = false;
-
   stopSysStatusRefresh();
 
   if(resizeHandler){

+ 4 - 10
web-ui.service/web/static/js/page2.js

@@ -182,20 +182,14 @@ function getNetworkStatus() {
       return r.json();
     })
     .then(data => {
-      document.getElementById("var1").textContent = data.var1 || "--";
-      document.getElementById("var2").textContent = data.var2 || "--";
-      document.getElementById("var3").textContent = data.var3 || "--";
-      document.getElementById("var4").textContent = data.var4 || "--";
-      document.getElementById("var5").textContent = data.var5 || "--";
+      ["var1","var2","var3","var4","var5"]
+        .forEach(id => setText(id, data[id]));
     })
     .catch(e => {
       console.error("getNetworkStatus() failed:", e);
 
-      document.getElementById("var1").textContent = "--";
-      document.getElementById("var2").textContent = "--";
-      document.getElementById("var3").textContent = "--";
-      document.getElementById("var4").textContent = "--";
-      document.getElementById("var5").textContent = "--";
+      ["var1","var2","var3","var4","var5"]
+        .forEach(id => setText(id, null));
     });
 
   getNetLogLevel();

+ 4 - 12
web-ui.service/web/static/js/page3.js

@@ -122,22 +122,14 @@ function getTimeStatus() {
       return r.json();
     })
     .then(data => {
-      document.getElementById("var1").textContent = data.var1 || "--";
-      document.getElementById("var2").textContent = data.var2 || "--";
-      document.getElementById("var3").textContent = data.var3 || "--";
-      document.getElementById("var4").textContent = data.var4 || "--";
-      document.getElementById("var5").textContent = data.var5 || "--";
-      document.getElementById("var6").textContent = data.var6 || "--";
+      ["var1","var2","var3","var4","var5","var6"]
+        .forEach(id => setText(id, data[id]));
     })
     .catch(e => {
       console.error("getTimeStatus() failed:", e);
 
-      document.getElementById("var1").textContent = "--";
-      document.getElementById("var2").textContent = "--";
-      document.getElementById("var3").textContent = "--";
-      document.getElementById("var4").textContent = "--";
-      document.getElementById("var5").textContent = "--";
-      document.getElementById("var6").textContent = "--";
+      ["var1","var2","var3","var4","var5","var6"]
+        .forEach(id => setText(id, null));
     });
 
   getTimeLogLevel();

+ 6 - 6
web-ui.service/web/static/js/page4.js

@@ -122,16 +122,16 @@ function getGnssStatus() {
       return r.json();
     })
     .then(data => {
-      document.getElementById("var1").textContent = data.var1 || "--";
-      document.getElementById("var2").textContent = data.var2 || "--";
-      document.getElementById("var3").textContent = data.var3 || "--";
+      ["var1", "var2", "var3"].forEach(id => {
+        setText(id, data[id]);
+      });
     })
     .catch(e => {
       console.error("getGnssStatus() failed:", e);
 
-      document.getElementById("var1").textContent = "--";
-      document.getElementById("var2").textContent = "--";
-      document.getElementById("var3").textContent = "--";
+      ["var1", "var2", "var3"].forEach(id => {
+        setText(id, null);
+      });
     });
 
   getGnssLogLevel();

+ 152 - 0
web-ui.service/web/static/js/page5.js

@@ -1,5 +1,157 @@
+let cameraLogLevel = "";
+function setCameraLogLevel() {
+  const level = logLevel.value;
+
+  fetch("/api/camera/loglevel", {
+    method: "POST",
+    headers: {"Content-Type": "application/json"},
+    body: JSON.stringify({level})
+  })
+  .then(async r => {
+    if (!r.ok) throw new Error(await r.text());
+    cameraLogLevel = level;
+  })
+  .catch(e => {
+    logLevel.value = cameraLogLevel;
+  });
+}
+
+function getCameraLogLevel() {
+  fetch("/api/camera/loglevel")
+  .then(async r => {
+    if (!r.ok) throw new Error(await r.text());
+    return r.json();
+  })
+  .then(d => {
+    cameraLogLevel = d.log_level;
+    logLevel.value = d.log_level;
+  })
+  .catch(e => {
+    cameraLogLevel = "";
+    logLevel.value = "";
+  });
+}
+
+function downloadCameraLogFile() {
+  const btn = event.currentTarget;
+  btn.disabled = true;
+
+  fetch("/api/camera/logfile")
+  .then(async r => {
+    if (!r.ok) {
+      throw new Error("HTTP " + r.status);
+    }
+
+    const disposition = r.headers.get("Content-Disposition");
+    let filename = "camera.log.tar.gz";
+    if (disposition) {
+      const match = disposition.match(/filename="?([^";]+)"?/);
+      if (match) {
+        filename = match[1];
+      }
+    }
+
+    return {
+      blob: await r.blob(),
+      filename
+    };
+  })
+  .then(({ blob, filename }) => {
+    const url = URL.createObjectURL(blob);
+
+    const a = document.createElement("a");
+    a.href = url;
+    a.download = filename;
+
+    document.body.appendChild(a);
+    a.click();
+    a.remove();
+
+    setTimeout(() => {
+      URL.revokeObjectURL(url);
+    }, 1000);
+
+    alert("下载成功");
+  })
+  .catch(e => {
+    console.error("download failed:", e);
+    alert("下载失败: " + e.message);
+  })
+  .finally(() => {
+    btn.disabled = false;
+    btn.textContent = "下载";
+  });
+}
+
+function restartCameraService() {
+  if (!confirm("确定重启相机服务吗?")) {
+    return;
+  }
+
+  const btn = event.currentTarget;
+  btn.disabled = true;
+
+  fetch("/api/camera/restart", {
+    method: "POST"
+  })
+  .then(async r => {
+    if (!r.ok) {
+      throw new Error(await r.text());
+    }
+    logLevel.value = "info";
+    cameraLogLevel = logLevel.value;
+    disconnectLog();
+    connectLog("yfkj-camera-capture.service", "text1");
+    alert("重启成功");
+  })
+  .catch(e => {
+    console.error("restart failed:", e);
+    alert("重启失败: " + e.message);
+  })
+  .finally(() => {
+    btn.disabled = false;
+  });
+}
+
+function getCameraStatus() {
+  setBtnStatus("btn1", false);
+  setBtnStatus("btn2", false);
+  setBtnStatus("btn3", false);
+  setBtnStatus("btn4", false);
+
+  fetch("/api/camera/status")
+    .then(async r => {
+      if (!r.ok) {
+        throw new Error("HTTP " + r.status);
+      }
+
+      return r.json();
+    })
+    .then(data => {
+      ["avar1","avar2","avar3","avar4","avar5", "avar6"]
+        .forEach(id => setText(id, data[id]));
+    })
+    .catch(e => {
+      console.error("getCameraStatus() failed:", e);
+
+      ["avar1","avar2","avar3","avar4","avar5", "avar6"]
+        .forEach(id => setText(id, null));
+    })
+    .finally(() => {
+      setBtnStatus("btn1", true);
+      setBtnStatus("btn2", true);
+      setBtnStatus("btn3", true);
+      setBtnStatus("btn4", true);
+    });
+
+  getCameraLogLevel();
+}
+
 function initPage5() {
+  getCameraStatus();
+  connectLog("yfkj-camera-capture.service", "text1");
 }
 
 function exitPage5() {
+  disconnectLog();
 }

+ 4 - 1
web-ui.service/web/static/js/router.js

@@ -28,7 +28,10 @@ const pageHandlers = {
     init: () => window.initPage4?.(),
     exit: () => window.exitPage4?.()
   },
-  page5: {},
+  page5: {
+    init: () => window.initPage5?.(),
+    exit: () => window.exitPage5?.()
+  },
   page6: {},
   page7: {},
   page8: {

+ 29 - 12
web-ui.service/web_handler.go

@@ -141,6 +141,10 @@ func (ui *WebUI) rootHandler(w http.ResponseWriter, r *http.Request) {
 	http.NotFound(w, r)
 }
 
+var logFiles = map[string]string{
+	"yfkj-camera-capture.service": "/opt/yfkj/camera-capture.service/log/camera-capture.log",
+}
+
 func serviceLogHandler(w http.ResponseWriter, r *http.Request) {
 	unit := r.URL.Query().Get("unit")
 	if unit == "" {
@@ -161,18 +165,31 @@ func serviceLogHandler(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	cmd := exec.Command(
-		"journalctl",
-		"-f",
-		"-u",
-		unit,
-		"-n",
-		"10",
-		"--no-pager",
-		"-q",
-		"-o",
-		"short-iso",
-	)
+	var cmd *exec.Cmd
+
+	if file, ok := logFiles[unit]; ok {
+		cmd = exec.Command(
+			"tail",
+			"-F",
+			"-n",
+			"10",
+			"--",
+			file,
+		)
+	} else {
+		cmd = exec.Command(
+			"journalctl",
+			"-f",
+			"-u",
+			unit,
+			"-n",
+			"10",
+			"--no-pager",
+			"-q",
+			"-o",
+			"short-iso",
+		)
+	}
 
 	stdout, err := cmd.StdoutPipe()
 	if err != nil {

+ 20 - 0
web-ui.service/web_route.go

@@ -129,6 +129,26 @@ var routes = []Route{
 	},
 
 	{
+		"/api/camera/loglevel",
+		serviceLogLevelHandler(7003),
+	},
+
+	{
+		"/api/camera/logfile",
+		downloadCameraLog,
+	},
+
+	{
+		"/api/camera/restart",
+		restartCameraService,
+	},
+
+	{
+		"/api/camera/status",
+		cameraStatusHandler,
+	},
+
+	{
 		"/api/ssh/ws",
 		sshWSHandler,
 	},