From e9b531edd2917b01a80dfa14e917ec21ddad8882 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期四, 19 三月 2026 20:26:13 +0800
Subject: [PATCH] #

---
 src/main/webapp/static/js/dashboard/dashboard.js |  398 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 378 insertions(+), 20 deletions(-)

diff --git a/src/main/webapp/static/js/dashboard/dashboard.js b/src/main/webapp/static/js/dashboard/dashboard.js
index db6676a..6a3cd1a 100644
--- a/src/main/webapp/static/js/dashboard/dashboard.js
+++ b/src/main/webapp/static/js/dashboard/dashboard.js
@@ -11,8 +11,10 @@
     el: "#app",
     data: function () {
       return {
+        rawPayload: null,
         loading: true,
         refreshing: false,
+        switchingSystem: false,
         countdown: REFRESH_SECONDS,
         countdownTimer: null,
         resizeHandler: null,
@@ -95,6 +97,12 @@
     },
     mounted: function () {
       var self = this;
+      this.refreshDocumentTitle();
+      if (window.WCS_I18N && typeof window.WCS_I18N.onReady === "function") {
+        window.WCS_I18N.onReady(function () {
+          self.refreshLocalizedState();
+        });
+      }
       this.$nextTick(function () {
         self.initCharts();
         self.loadDashboard(false);
@@ -108,6 +116,48 @@
       this.disposeCharts();
     },
     methods: {
+      formatMessage: function (text, params) {
+        var list = Array.isArray(params) ? params : [params];
+        return String(text == null ? "" : text).replace(/\{(\d+)\}/g, function (match, index) {
+          return list[index] == null ? "" : list[index];
+        });
+      },
+      i18n: function (key, fallback, params) {
+        if (window.WCS_I18N && typeof window.WCS_I18N.t === "function") {
+          var translated = window.WCS_I18N.t(key, params);
+          if (translated && translated !== key) {
+            return translated;
+          }
+        }
+        return this.formatMessage(fallback || key, params);
+      },
+      translateLegacyText: function (text) {
+        if (text == null || text === "") {
+          return text;
+        }
+        if (window.WCS_I18N && typeof window.WCS_I18N.tl === "function") {
+          return window.WCS_I18N.tl(String(text));
+        }
+        return text;
+      },
+      getCurrentLocale: function () {
+        if (window.WCS_I18N && typeof window.WCS_I18N.getLocale === "function") {
+          return window.WCS_I18N.getLocale();
+        }
+        return "zh-CN";
+      },
+      refreshDocumentTitle: function () {
+        document.title = this.i18n("dashboard.title", "绯荤粺浠〃鐩�");
+      },
+      refreshLocalizedState: function () {
+        this.refreshDocumentTitle();
+        if (this.rawPayload) {
+          this.applyData(this.rawPayload);
+          return;
+        }
+        this.$forceUpdate();
+        this.updateCharts();
+      },
       loadDashboard: function (manual) {
         var self = this;
         if (this.refreshing) {
@@ -124,11 +174,11 @@
               self.countdown = REFRESH_SECONDS;
               return;
             }
-            self.$message.error((res && res.msg) || "浠〃鐩樻暟鎹姞杞藉け璐�");
+            self.$message.error((res && res.msg) || self.i18n("dashboard.loadFailed", "浠〃鐩樻暟鎹姞杞藉け璐�"));
           },
           error: function () {
             if (manual) {
-              self.$message.error("浠〃鐩樻暟鎹姞杞藉け璐ワ紝璇锋鏌ユ帴鍙g姸鎬�");
+              self.$message.error(self.i18n("dashboard.loadFailedDetail", "浠〃鐩樻暟鎹姞杞藉け璐ワ紝璇锋鏌ユ帴鍙g姸鎬�"));
             }
           },
           complete: function () {
@@ -138,12 +188,165 @@
         });
       },
       applyData: function (payload) {
-        this.overview = payload.overview || this.overview;
-        this.tasks = payload.tasks || this.tasks;
-        this.devices = payload.devices || this.devices;
-        this.network = payload.network || this.network;
-        this.ai = payload.ai || this.ai;
+        var tasks = payload && payload.tasks ? payload.tasks : {};
+        var devices = payload && payload.devices ? payload.devices : {};
+        var network = payload && payload.network ? payload.network : {};
+        var ai = payload && payload.ai ? payload.ai : {};
+
+        this.rawPayload = payload || {};
+        this.refreshDocumentTitle();
+        this.overview = payload && payload.overview ? payload.overview : this.overview;
+        this.tasks = {
+          overview: tasks.overview || this.tasks.overview,
+          directionStats: this.normalizeTaskDirectionMetrics(tasks.directionStats),
+          stageStats: this.normalizeTaskStageMetrics(tasks.stageStats),
+          statusStats: this.normalizeMetricList(tasks.statusStats),
+          recentTasks: this.normalizeRecentTasks(tasks.recentTasks)
+        };
+        this.devices = {
+          overview: devices.overview || this.devices.overview,
+          typeStats: this.normalizeDeviceTypeStats(devices.typeStats)
+        };
+        this.network = {
+          overview: network.overview || this.network.overview,
+          samplingConfig: network.samplingConfig || this.network.samplingConfig,
+          statusStats: this.normalizeNetworkStatusMetrics(network.statusStats),
+          focusDevices: this.normalizeFocusDevices(network.focusDevices)
+        };
+        this.ai = {
+          overview: ai.overview || this.ai.overview,
+          routeStats: this.normalizeAiRouteStats(ai.routeStats),
+          routeList: this.normalizeAiRouteList(ai.routeList)
+        };
         this.updateCharts();
+      },
+      normalizeTaskDirectionMetrics: function (list) {
+        var self = this;
+        return cloneMetricList(list).map(function (item) {
+          var result = Object.assign({}, item);
+          if (item && item.name === "鍏ュ簱浠诲姟") {
+            result.name = self.i18n("dashboard.taskDirectionInbound", "鍏ュ簱浠诲姟");
+          } else if (item && item.name === "鍑哄簱浠诲姟") {
+            result.name = self.i18n("dashboard.taskDirectionOutbound", "鍑哄簱浠诲姟");
+          } else if (item && item.name === "绉诲簱浠诲姟") {
+            result.name = self.i18n("dashboard.taskDirectionMove", "绉诲簱浠诲姟");
+          } else {
+            result.name = self.translateLegacyText(item && item.name);
+          }
+          return result;
+        });
+      },
+      normalizeTaskStageMetrics: function (list) {
+        var self = this;
+        return cloneMetricList(list).map(function (item) {
+          var result = Object.assign({}, item);
+          if (item && item.name === "鎵ц涓�") {
+            result.name = self.i18n("dashboard.taskRunningLabel", "鎵ц涓�");
+          } else if (item && item.name === "寰呬汉宸�") {
+            result.name = self.i18n("dashboard.taskManualLabel", "寰呬汉宸�");
+          } else if (item && item.name === "宸插畬鎴�") {
+            result.name = self.i18n("dashboard.taskCompletedLabel", "宸插畬鎴�");
+          } else if (item && item.name === "鏂板缓") {
+            result.name = self.i18n("dashboard.taskNewLabel", "鏂板缓");
+          } else {
+            result.name = self.translateLegacyText(item && item.name);
+          }
+          return result;
+        });
+      },
+      normalizeMetricList: function (list) {
+        var self = this;
+        return cloneMetricList(list).map(function (item) {
+          var result = Object.assign({}, item);
+          result.name = self.translateLegacyText(item && item.name);
+          return result;
+        });
+      },
+      normalizeRecentTasks: function (list) {
+        var self = this;
+        return cloneMetricList(list).map(function (item) {
+          var result = Object.assign({}, item);
+          result.taskType = self.translateLegacyText(item && item.taskType);
+          result.status = self.translateLegacyText(item && item.status);
+          result.source = self.translateLegacyText(item && item.source);
+          result.target = self.translateLegacyText(item && item.target);
+          result.device = self.translateLegacyText(item && item.device);
+          return result;
+        });
+      },
+      normalizeAiRouteStats: function (list) {
+        var self = this;
+        return cloneMetricList(list).map(function (item) {
+          var result = Object.assign({}, item);
+          if (item && item.name === "鍙敤") {
+            result.name = self.i18n("dashboard.aiRouteStatusAvailable", "鍙敤");
+          } else if (item && item.name === "鍐峰嵈涓�") {
+            result.name = self.i18n("dashboard.aiRouteStatusCooling", "鍐峰嵈涓�");
+          } else if (item && item.name === "宸茬鐢�") {
+            result.name = self.i18n("dashboard.aiRouteStatusDisabled", "宸茬鐢�");
+          } else {
+            result.name = self.translateLegacyText(item && item.name);
+          }
+          return result;
+        });
+      },
+      normalizeNetworkStatusMetrics: function (list) {
+        var self = this;
+        return cloneMetricList(list).map(function (item) {
+          var result = Object.assign({}, item);
+          if (item && item.name === "姝e父") {
+            result.name = self.i18n("dashboard.networkOkLabel", "姝e父");
+          } else if (item && item.name === "娉㈠姩") {
+            result.name = self.i18n("dashboard.networkUnstableLabel", "娉㈠姩");
+          } else if (item && item.name === "瓒呮椂/寮傚父") {
+            result.name = self.i18n("dashboard.networkOfflineLabel", "瓒呮椂/寮傚父");
+          } else if (item && item.name === "鏆傛棤鏁版嵁") {
+            result.name = self.i18n("dashboard.networkNoDataLabel", "鏆傛棤鏁版嵁");
+          } else {
+            result.name = self.translateLegacyText(item && item.name);
+          }
+          return result;
+        });
+      },
+      normalizeDeviceTypeStats: function (list) {
+        var self = this;
+        return cloneMetricList(list).map(function (item) {
+          var result = Object.assign({}, item);
+          result.name = self.translateLegacyText(item && item.name);
+          return result;
+        });
+      },
+      normalizeAiRouteList: function (list) {
+        var self = this;
+        return cloneMetricList(list).map(function (item) {
+          var result = Object.assign({}, item);
+          if (result.statusType === "success") {
+            result.statusText = self.i18n("dashboard.aiRouteStatusAvailable", "鍙敤");
+          } else if (result.statusType === "warning") {
+            result.statusText = self.i18n("dashboard.aiRouteStatusCooling", "鍐峰嵈涓�");
+          } else {
+            result.statusText = self.i18n("dashboard.aiRouteStatusDisabled", "宸茬鐢�");
+          }
+          result.lastError = self.translateLegacyText(item && item.lastError);
+          return result;
+        });
+      },
+      normalizeFocusDevices: function (list) {
+        var self = this;
+        return cloneMetricList(list).map(function (item) {
+          var result = Object.assign({}, item);
+          if (result.statusType === "success") {
+            result.statusText = self.i18n("dashboard.networkOkLabel", "姝e父");
+          } else if (result.statusType === "warning") {
+            result.statusText = self.i18n("dashboard.networkUnstableLabel", "娉㈠姩");
+          } else if (result.statusType === "danger") {
+            result.statusText = self.i18n("dashboard.networkOfflineLabel", "瓒呮椂/寮傚父");
+          } else {
+            result.statusText = self.i18n("dashboard.networkNoDataLabel", "鏆傛棤鏁版嵁");
+          }
+          result.message = self.translateLegacyText(item && item.message);
+          return result;
+        });
       },
       initCharts: function () {
         this.disposeCharts();
@@ -247,6 +450,8 @@
       },
       buildDeviceTypeOption: function () {
         var data = cloneMetricList(this.devices.typeStats);
+        var onlineText = this.i18n("dashboard.deviceOnlineLegend", "鍦ㄧ嚎");
+        var offlineText = this.i18n("dashboard.deviceOfflineLegend", "绂荤嚎");
         return {
           color: ["#2fa38e", "#d8e2ec"],
           legend: {
@@ -255,7 +460,7 @@
             itemWidth: 10,
             itemHeight: 10,
             textStyle: { color: "#60778d", fontSize: 12 },
-            data: ["鍦ㄧ嚎", "绂荤嚎"]
+            data: [onlineText, offlineText]
           },
           grid: {
             left: 76,
@@ -282,7 +487,7 @@
             axisLabel: { color: "#60778d", fontSize: 12 }
           },
           series: [{
-            name: "鍦ㄧ嚎",
+            name: onlineText,
             type: "bar",
             stack: "device",
             barWidth: 18,
@@ -291,7 +496,7 @@
               borderRadius: [9, 0, 0, 9]
             }
           }, {
-            name: "绂荤嚎",
+            name: offlineText,
             type: "bar",
             stack: "device",
             barWidth: 18,
@@ -325,7 +530,7 @@
             left: "center",
             top: "55%",
             style: {
-              text: "鍙敤璺敱",
+              text: this.i18n("dashboard.chartCenter.availableRoutes", "鍙敤璺敱"),
               fill: "#7c8fa4",
               fontSize: 12
             }
@@ -370,7 +575,7 @@
             left: "center",
             top: "54%",
             style: {
-              text: "闇�鍏虫敞璁惧",
+              text: this.i18n("dashboard.chartCenter.attentionDevices", "闇�鍏虫敞璁惧"),
               fill: "#7c8fa4",
               fontSize: 12
             }
@@ -397,7 +602,7 @@
         if (!isFinite(num)) {
           return "0";
         }
-        return num.toLocaleString("zh-CN");
+        return num.toLocaleString(this.getCurrentLocale());
       },
       formatLatency: function (value) {
         var num;
@@ -408,22 +613,43 @@
         if (!isFinite(num)) {
           return "--";
         }
-        return num.toLocaleString("zh-CN", { maximumFractionDigits: 2 }) + " ms";
+        return num.toLocaleString(this.getCurrentLocale(), { maximumFractionDigits: 2 }) + " ms";
+      },
+      formatPercentValue: function (value) {
+        var num = Number(value);
+        if (!isFinite(num)) {
+          return "--";
+        }
+        return num.toLocaleString(this.getCurrentLocale(), { maximumFractionDigits: 2 }) + "%";
       },
       formatPacketSize: function (value) {
         var num = Number(value);
         if (!isFinite(num) || num < 0) {
-          return "绯荤粺榛樿";
+          return this.i18n("dashboard.systemDefaultPacketSize", "绯荤粺榛樿");
         }
-        return num + " B";
+        return num.toLocaleString(this.getCurrentLocale()) + " B";
       },
       displayText: function (value, fallback) {
         return value == null || value === "" ? (fallback || "") : value;
       },
+      showMessage: function (message, type) {
+        if (this.$message && typeof this.$message === "function") {
+          this.$message({
+            message: message,
+            type: type || "info"
+          });
+          return;
+        }
+        console[type === "error" ? "error" : "log"](message);
+      },
       networkSamplingText: function () {
         var config = this.network && this.network.samplingConfig ? this.network.samplingConfig : {};
-        return "閲囨牱 " + this.displayText(config.intervalMs, 0) + " ms / 瓒呮椂 " + this.displayText(config.timeoutMs, 0) +
-          " ms / 姣忔牱鏈� " + this.displayText(config.probeCount, 0) + " 娆� / 鍖呭ぇ灏� " + this.formatPacketSize(config.packetSize);
+        return this.i18n("dashboard.networkSampling", "閲囨牱 {0} ms / 瓒呮椂 {1} ms / 姣忔牱鏈� {2} 娆� / 鍖呭ぇ灏� {3}", [
+          this.displayText(config.intervalMs, 0),
+          this.displayText(config.timeoutMs, 0),
+          this.displayText(config.probeCount, 0),
+          this.formatPacketSize(config.packetSize)
+        ]);
       },
       startAutoRefresh: function () {
         var self = this;
@@ -549,10 +775,142 @@
         window.open(targetMenu && targetMenu.url ? targetMenu.url : this.resolveAbsoluteViewPath(targetPath), "_blank");
       },
       openMonitor: function () {
-        this.openParentMenuView("/views/watch/console.html", "鐩戞帶鐢婚潰", "鐩戞帶鐢婚潰", "鐩戞帶绯荤粺");
+        this.openParentMenuView(
+          "/views/watch/console.html",
+          this.i18n("dashboard.monitorView", "鐩戞帶鐢婚潰"),
+          this.translateLegacyText("鐩戞帶鐢婚潰"),
+          this.translateLegacyText("鐩戞帶绯荤粺")
+        );
+      },
+      syncParentSystemRunning: function (status) {
+        try {
+          if (window.parent && window.parent !== window) {
+            window.parent.systemRunning = !!status;
+          }
+        } catch (e) {
+        }
+      },
+      requestSystemSwitch: function (operatorType, password) {
+        var self = this;
+        this.switchingSystem = true;
+        $.ajax({
+          url: baseUrl + "/console/system/switch",
+          headers: {
+            token: localStorage.getItem("token")
+          },
+          data: {
+            operatorType: operatorType,
+            password: password || ""
+          },
+          method: "POST",
+          success: function (res) {
+            var status;
+            if (res && res.code === 200) {
+              status = !!(res.data && res.data.status);
+              self.overview = Object.assign({}, self.overview, {
+                systemRunning: status
+              });
+              self.syncParentSystemRunning(status);
+              self.showMessage(
+                status
+                  ? self.i18n("dashboard.systemStarted", "绯荤粺宸插惎鍔�")
+                  : self.i18n("dashboard.systemStopped", "绯荤粺宸插仠姝�"),
+                "success"
+              );
+              self.loadDashboard(false);
+              return;
+            }
+            if (res && res.code === 403) {
+              window.location.href = baseUrl + "/login";
+              return;
+            }
+            self.showMessage(
+              (res && res.msg) || self.i18n("dashboard.systemSwitchFailed", "绯荤粺鐘舵�佸垏鎹㈠け璐�"),
+              "error"
+            );
+          },
+          error: function () {
+            self.showMessage(
+              self.i18n("dashboard.systemSwitchFailedDetail", "绯荤粺鐘舵�佸垏鎹㈠け璐ワ紝璇锋鏌ユ帴鍙g姸鎬�"),
+              "error"
+            );
+          },
+          complete: function () {
+            self.switchingSystem = false;
+          }
+        });
+      },
+      startSystem: function () {
+        if (this.overview.systemRunning || this.switchingSystem) {
+          return;
+        }
+        this.requestSystemSwitch(1);
+      },
+      maskStopSystemPromptInput: function () {
+        setTimeout(function () {
+          var input = document.querySelector(".el-message-box__wrapper .el-message-box__input input");
+          if (!input) {
+            return;
+          }
+          input.setAttribute("type", "text");
+          input.setAttribute("name", "dashboard-stop-code");
+          input.setAttribute("autocomplete", "new-password");
+          input.setAttribute("autocapitalize", "off");
+          input.setAttribute("autocorrect", "off");
+          input.setAttribute("spellcheck", "false");
+          input.setAttribute("data-form-type", "other");
+          input.style.webkitTextSecurity = "disc";
+        }, 30);
+      },
+      stopSystem: function () {
+        var self = this;
+        var proceed = function (password) {
+          var cleanPassword = String(password == null ? "" : password).trim();
+          if (!cleanPassword) {
+            self.showMessage(self.i18n("dashboard.stopSystemPasswordRequired", "璇疯緭鍏ュ仠姝㈢郴缁熷彛浠�"), "warning");
+            return;
+          }
+          self.requestSystemSwitch(0, cleanPassword);
+        };
+
+        if (!this.overview.systemRunning || this.switchingSystem) {
+          return;
+        }
+
+        if (typeof this.$prompt === "function") {
+          this.$prompt(
+            this.i18n("dashboard.stopSystemPrompt", "璇疯緭鍏ュ彛浠わ紝骞跺仠姝� WCS 绯荤粺"),
+            this.i18n("dashboard.stopSystemTitle", "鍋滄绯荤粺"),
+            {
+              confirmButtonText: this.i18n("common.confirm", "纭畾"),
+              cancelButtonText: this.i18n("common.cancel", "鍙栨秷"),
+              inputType: "text",
+              inputPattern: /\S+/,
+              inputErrorMessage: this.i18n("dashboard.stopSystemPasswordRequired", "璇疯緭鍏ュ仠姝㈢郴缁熷彛浠�")
+            }
+          ).then(function (result) {
+            proceed(result && result.value);
+          }).catch(function () {
+          });
+          this.maskStopSystemPromptInput();
+          return;
+        }
+
+        proceed(window.prompt(this.i18n("dashboard.stopSystemPrompt", "璇疯緭鍏ュ彛浠わ紝骞跺仠姝� WCS 绯荤粺"), ""));
+      },
+      toggleSystem: function () {
+        if (this.overview.systemRunning) {
+          this.stopSystem();
+          return;
+        }
+        this.startSystem();
       },
       openDevicePingAnalysis: function () {
-        this.openParentMenuView("/views/devicePingLog/devicePingLog.html", "璁惧缃戠粶鍒嗘瀽", "璁惧缃戠粶鍒嗘瀽");
+        this.openParentMenuView(
+          "/views/devicePingLog/devicePingLog.html",
+          this.i18n("devicePingLog.title", "璁惧缃戠粶鍒嗘瀽"),
+          this.translateLegacyText("璁惧缃戠粶鍒嗘瀽")
+        );
       }
     }
   });

--
Gitblit v1.9.1