浏览代码

版本迭代

lining 2 年之前
父节点
当前提交
97d6477e86
共有 80 个文件被更改,包括 67613 次插入1160 次删除
  1. 6 6
      .env.development
  2. 52 1
      package-lock.json
  3. 2 0
      package.json
  4. 240 4
      src/App.vue
  5. 38 1
      src/api/index.js
  6. 1 0
      src/assets/dataService/README.md
  7. 234 0
      src/assets/dataService/arcgis-mhs-line.json
  8. 707 0
      src/assets/dataService/arcgis-mhs.json
  9. 1 0
      src/assets/dataService/arcgis-nss-line.json
  10. 1502 0
      src/assets/dataService/arcgis-nss.json
  11. 1 0
      src/assets/dataService/arcgis-qs-line.json
  12. 1007 0
      src/assets/dataService/arcgis-qs.json
  13. 173 0
      src/assets/dataService/arcgis-sbq-line.json
  14. 1757 0
      src/assets/dataService/arcgis-sbq.json
  15. 1 0
      src/assets/dataService/arcgis-xs-line.json
  16. 887 0
      src/assets/dataService/arcgis-xs.json
  17. 二进制
      src/assets/img/menu/agc.png
  18. 二进制
      src/assets/img/menu/booster.png
  19. 二进制
      src/assets/img/menu/homePage.png
  20. 二进制
      src/assets/img/menu/lock.png
  21. 二进制
      src/assets/img/menu/matrix.png
  22. 二进制
      src/assets/img/menu/screenshot.png
  23. 二进制
      src/assets/img/menu/search.png
  24. 二进制
      src/assets/img/menu/set.png
  25. 二进制
      src/assets/img/menu/voice.png
  26. 2 2
      src/components/BasicInformationDetail.vue
  27. 204 17
      src/components/WindturbineDetailPages.vue
  28. 635 0
      src/components/allMatrices.vue
  29. 6 3
      src/components/boxSelect.vue
  30. 1 1
      src/components/check/areaCard.vue
  31. 8 6
      src/components/check/operationRecords.vue
  32. 6 6
      src/components/control/areaCard.vue
  33. 30 38
      src/components/control/controlAllArea.vue
  34. 2 1
      src/components/focus/agcDetails.vue
  35. 287 0
      src/components/focus/currentWarningCard.vue
  36. 524 422
      src/components/focus/dataDetails.vue
  37. 135 24
      src/components/focus/focusArea.vue
  38. 345 0
      src/components/focus/syzDetails.vue
  39. 101 96
      src/components/matrixBlock.vue
  40. 695 495
      src/components/modeControl/modeControl.vue
  41. 93 0
      src/components/panel/panel-no-title.vue
  42. 73 0
      src/components/panel/panel-sand-toolbar.vue
  43. 78 0
      src/components/panel/panel-sand.vue
  44. 112 0
      src/components/panel/panel.vue
  45. 139 0
      src/components/panel/panel2.vue
  46. 52 0
      src/components/panel/panel3.vue
  47. 46 0
      src/components/panel/toolbar-panel.vue
  48. 2 1
      src/components/problem/ProblemArea.vue
  49. 407 0
      src/components/search/action.vue
  50. 348 0
      src/components/search/fault.vue
  51. 519 0
      src/components/search/multiple-y-line-chart-normal.vue
  52. 56 0
      src/components/search/status.vue
  53. 870 0
      src/components/search/warning.vue
  54. 221 0
      src/components/table/check-table.vue
  55. 304 0
      src/components/table/group-table.vue
  56. 333 0
      src/components/table/table-page.vue
  57. 497 0
      src/components/table/table-qc.vue
  58. 139 0
      src/components/table/table-span.vue
  59. 216 0
      src/components/table/table-unpage.vue
  60. 277 0
      src/components/table/table.vue
  61. 301 0
      src/components/table/table2.vue
  62. 303 0
      src/components/table/table3.vue
  63. 270 0
      src/components/temperatureMatrix.vue
  64. 848 0
      src/components/unpaidMatrixBlock.vue
  65. 1 1
      src/components/warning/warningArea.vue
  66. 194 26
      src/components/warning/warningCard.vue
  67. 33 0
      src/store/index.js
  68. 1 1
      src/utils/MessageBridge.js
  69. 268 0
      src/utils/baseTool.js
  70. 9 0
      src/utils/data.js
  71. 15241 0
      src/utils/fault.json
  72. 26 0
      src/utils/partten.js
  73. 16 5
      src/utils/request.js
  74. 44 0
      src/utils/util.js
  75. 35447 0
      src/utils/yujing.json
  76. 1 0
      src/views/CenterPage.vue
  77. 1 0
      src/views/ManualPage.vue
  78. 234 0
      src/views/Menu.vue
  79. 2 2
      src/views/StatusBar.vue
  80. 1 1
      src/views/TitleBar.vue

+ 6 - 6
.env.development

@@ -1,6 +1,6 @@
-VUE_APP_API=http://10.83.68.205:8099
-VUE_APP_WARNING=http://10.83.68.205:8075
-VUE_APP_SHARDINGURL=http://10.83.68.205:8075
-VUE_APP_ADAPTERURL=http://10.83.68.205:8011
-VUE_APP_APIS=10.83.68.205:8099
-VUE_APP_ADAPTERURLS=10.83.68.205:8011
+VUE_APP_API=http://localhost:8099
+VUE_APP_WARNING=http://123.60.219.66:8075
+VUE_APP_SHARDINGURL=http://123.60.219.66:8075
+VUE_APP_ADAPTERURL=http://123.60.213.70:8011
+VUE_APP_APIS=localhost:8099
+VUE_APP_ADAPTERURLS=123.60.213.70:8011

+ 52 - 1
package-lock.json

@@ -1,5 +1,5 @@
 {
-  "name": "neic",
+  "name": "project-neic",
   "version": "0.1.0",
   "lockfileVersion": 1,
   "requires": true,
@@ -3407,6 +3407,11 @@
         }
       }
     },
+    "base64-arraybuffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
+      "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ=="
+    },
     "base64-js": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -3446,6 +3451,11 @@
       "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
       "dev": true
     },
+    "bignumber.js": {
+      "version": "9.0.2",
+      "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz",
+      "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw=="
+    },
     "binary-extensions": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@@ -5254,6 +5264,14 @@
         }
       }
     },
+    "css-line-break": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
+      "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
+      "requires": {
+        "utrie": "^1.0.2"
+      }
+    },
     "css-loader": {
       "version": "3.6.0",
       "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz",
@@ -8098,6 +8116,15 @@
         }
       }
     },
+    "html2canvas": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
+      "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
+      "requires": {
+        "css-line-break": "^2.1.0",
+        "text-segmentation": "^1.0.3"
+      }
+    },
     "htmlparser2": {
       "version": "6.1.0",
       "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
@@ -9077,6 +9104,14 @@
       "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
       "dev": true
     },
+    "json-bigint": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
+      "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
+      "requires": {
+        "bignumber.js": "^9.0.0"
+      }
+    },
     "json-buffer": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz",
@@ -14202,6 +14237,14 @@
         }
       }
     },
+    "text-segmentation": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
+      "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
+      "requires": {
+        "utrie": "^1.0.2"
+      }
+    },
     "thenify": {
       "version": "3.3.1",
       "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
@@ -14949,6 +14992,14 @@
       "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
       "dev": true
     },
+    "utrie": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
+      "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
+      "requires": {
+        "base64-arraybuffer": "^1.0.2"
+      }
+    },
     "uuid": {
       "version": "3.4.0",
       "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",

+ 2 - 0
package.json

@@ -17,7 +17,9 @@
     "dayjs": "^1.10.6",
     "echarts": "^5.1.2",
     "element-plus": "^1.1.0-beta.4",
+    "html2canvas": "^1.4.1",
     "jquery": "^3.6.0",
+    "json-bigint": "^1.0.0",
     "register-service-worker": "^1.7.1",
     "stompjs": "^2.3.3",
     "vue": "^3.0.11",

+ 240 - 4
src/App.vue

@@ -1,6 +1,16 @@
 <template class="app">
-  <div>
+  <div style="background-color: #000000" ref="imageTofile">
+    <div v-if="lockMaskDisplay" class="lockMask"></div>
+    <!-- <div class="warningMask"></div> -->
     <TitleBar class="titleBar" />
+    <div class="left">
+      <Menu
+        :lockMaskDisplay="lockMaskDisplay"
+        :temperatureNum="temperatureNum"
+        @handleChange="handleChange"
+        @handleSearch="handleSearch"
+      />
+    </div>
     <div class="right">
       <el-col>
         <el-row>
@@ -29,30 +39,66 @@
     </div>
     <StatusBar class="statusBar" @getData="getData" />
     <router-view />
+    <AllMatrices v-model="matricesDisplay" />
+    <SYZDetails v-model="$store.state.syzDialogShow"></SYZDetails>
+    <AGCDetails v-model="agcDisplay"></AGCDetails>
+    <TemperatureMatrix v-model="temperatureDisplay" />
+    <Fault v-model="faultDisplay" />
+    <Warning v-model="warningDisplay" />
+    <Status v-model="statusDisplay" />
+    <Action v-model="actionDisplay" />
   </div>
 </template>
 <script>
 import TitleBar from "views/TitleBar.vue";
 import StatusBar from "views/StatusBar.vue";
+import Menu from "views/Menu.vue";
 import MessageBridge from "utils/MessageBridge";
 import ModeControl from "components/modeControl/modeControl.vue";
 import FocusArea from "components/focus/focusArea.vue";
 import WarningArea from "components/warning/warningArea.vue";
 import api from "api/index";
 import boxSelect from "components/boxSelect.vue";
+import AGCDetails from "components/focus/agcDetails.vue";
+import SYZDetails from "components/focus/syzDetails.vue";
+import AllMatrices from "components/allMatrices.vue";
+import TemperatureMatrix from "components/temperatureMatrix.vue";
+import Fault from "components/search/fault.vue";
+import Warning from "components/search/warning.vue";
+import Status from "components/search/status.vue";
+import Action from "components/search/action.vue";
+import html2canvas from "html2canvas";
 export default {
   data() {
     return {
       state: false,
+      agcDisplay: false, //AGC功能
+      matricesDisplay: false, //全部矩阵
+      temperatureDisplay: false, //温度矩阵
+      faultDisplay: false, //查询-报警/故障查询
+      warningDisplay: false, //查询-预警查询
+      statusDisplay: false, //查询-状态时间查询
+      actionDisplay: false, //查询-动作查询
+      lockMaskDisplay: false, //锁屏
+      temperatureNum: 0, //温度矩阵故障数
     };
   },
   components: {
     TitleBar,
     StatusBar,
+    Menu,
     ModeControl,
     FocusArea,
     WarningArea,
     boxSelect,
+    AGCDetails,
+    SYZDetails,
+    AllMatrices,
+    TemperatureMatrix,
+    Fault,
+    Warning,
+    Status,
+    Action,
   },
   created: function () {
     this.getStation();
@@ -61,7 +107,6 @@ export default {
   },
   methods: {
     getData(val) {
-      console.log(val);
       this.state = val;
     },
     none() {
@@ -73,16 +118,37 @@ export default {
       let windturbine = [
         { key: "/topic/windturbine", action: this.windturbineMessage },
       ];
+      let temperature = [
+        { key: "/topic/temperature-count", action: this.temperatureMessage },
+      ];
       mb.register(windturbine);
+      mb.register(temperature);
     },
     windturbineMessage(msg) {
       let json = JSON.parse(msg);
       this.$store.commit("windturbinelist", json);
       // console.log(json);
     },
+    temperatureMessage(msg) {
+      let json = JSON.parse(msg);
+      this.temperatureNum =
+        json.countOverLimit + json.countBadPoint + json.countCrossingLimit;
+    },
     getStation() {
       api.getStation().then((res) => {
         this.$store.commit("stationList", res.data);
+        let syzArray = [];
+        res.data.forEach((item) => {
+          let obj = {
+            id: item.id, // 升压站 ID
+            isWarning: "0", // 升压站是否显示报警小红点
+            name: item.address, // 升压站中文名称
+            isMute: false, // 升压站报警是否静音
+          };
+          syzArray.push(obj);
+        });
+        this.$store.commit("syzArray", syzArray);
+        this.$store.commit("activeTab", syzArray[0].name);
       });
     },
     subscribe() {
@@ -106,6 +172,104 @@ export default {
         this.$store.commit("observers", true);
       }
     },
+    handleChange(val) {
+      if (val !== 9) {
+        this.matricesDisplay = false;
+        this.$store.commit("syzDialogShow", false);
+        this.agcDisplay = false;
+        this.temperatureDisplay = false;
+        this.faultDisplay = false;
+        this.warningDisplay = false;
+        this.statusDisplay = false;
+        this.actionDisplay = false;
+      }
+
+      switch (val) {
+        case 2:
+          this.matricesDisplay = true;
+          break;
+        case 3:
+          this.temperatureDisplay = true;
+          break;
+        case 4:
+          this.$store.commit("syzDialogShow", true);
+          break;
+        case 5:
+          this.agcDisplay = true;
+          break;
+        case 7:
+          this.lockMaskDisplay = !this.lockMaskDisplay;
+          break;
+        case 9:
+          this.toImage();
+          break;
+        default:
+          break;
+      }
+    },
+    handleSearch(val) {
+      this.matricesDisplay = false;
+      this.$store.commit("syzDialogShow", false);
+      this.agcDisplay = false;
+      this.temperatureDisplay = false;
+      this.faultDisplay = false;
+      this.warningDisplay = false;
+      this.statusDisplay = false;
+      this.actionDisplay = false;
+      switch (val) {
+        case "fault":
+          this.faultDisplay = true;
+          break;
+        case "warning":
+          this.warningDisplay = true;
+          break;
+        case "status":
+          this.statusDisplay = true;
+          break;
+        case "action":
+          this.actionDisplay = true;
+          break;
+        default:
+          break;
+      }
+    },
+    // 页面元素转图片
+    toImage() {
+      // 手动创建一个 canvas 标签
+      const canvas = document.createElement("canvas");
+      // 获取父标签,意思是这个标签内的 DOM 元素生成图片
+      // imageTofile是给截图范围内的父级元素自定义的ref名称
+      let canvasBox = this.$refs.imageTofile;
+      // 获取父级的宽高
+      const width = parseInt(window.getComputedStyle(canvasBox).width);
+      const height = parseInt(window.getComputedStyle(canvasBox).height);
+      // 宽高 * 2 并放大 2 倍 是为了防止图片模糊
+      canvas.width = width * 2;
+      canvas.height = height * 2;
+      canvas.style.width = width + "px";
+      canvas.style.height = height + "px";
+      const context = canvas.getContext("2d");
+      context.scale(2, 2);
+      const options = {
+        backgroundColor: null,
+        canvas: canvas,
+        useCORS: true,
+      };
+      html2canvas(canvasBox, options).then((canvas) => {
+        // toDataURL 图片格式转成 base64
+        let dataURL = canvas.toDataURL("image/png");
+        console.log(dataURL);
+        this.downloadImage(dataURL);
+      });
+    },
+    //下载图片
+    downloadImage(url) {
+      // 如果是在网页中可以直接创建一个 a 标签直接下载
+      let a = document.createElement("a");
+      a.href = url;
+      a.download = "页面截图";
+      a.click();
+    },
   },
 };
 </script>
@@ -146,8 +310,18 @@ body {
 .D-:hover {
   background-color: #999999;
 }
+.left {
+  width: 40px;
+  position: absolute;
+  left: 0px;
+  height: 100%;
+  z-index: 9999;
+  background-color: #242424;
+  margin-left: 7px;
+  border-radius: 8px;
+}
 .right {
-  width: 32%;
+  width: 31%;
   position: absolute;
   right: 20px;
   z-index: 99;
@@ -158,6 +332,7 @@ body {
   position: absolute;
   bottom: 0;
   left: 0;
+  z-index: 9999;
 }
 
 .titleBar {
@@ -165,6 +340,7 @@ body {
   position: relative;
   top: 0;
   left: 0;
+  z-index: 1;
 }
 .el-table__body-wrapper::-webkit-scrollbar-thumb {
   background-color: #999999;
@@ -192,6 +368,51 @@ body {
 .el-collapse-item__wrap {
   border: none !important;
 }
+.lockMask {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  background-color: rgba(0, 0, 0, 0.2);
+  z-index: 9998;
+}
+.warningMask {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  background-image: radial-gradient(
+    circle,
+    rgb(255, 0, 0, 0),
+    rgb(255, 0, 0, 0),
+    rgb(255, 0, 0, 0),
+    rgb(255, 0, 0)
+  );
+  animation: fade 2000ms infinite;
+  -webkit-animation: fade 2000ms infinite;
+  z-index: 999;
+  pointer-events: none;
+}
+@keyframes fade {
+  from {
+    opacity: 0.7;
+  }
+  50% {
+    opacity: 0.3;
+  }
+  to {
+    opacity: 0.7;
+  }
+}
+@-webkit-keyframes fade {
+  from {
+    opacity: 0.7;
+  }
+  50% {
+    opacity: 0.3;
+  }
+  to {
+    opacity: 0.7;
+  }
+}
 </style>
 <style lang="less">
 #app {
@@ -202,8 +423,23 @@ body {
   }
 
   .currentScroll::-webkit-scrollbar-thumb {
-    background-color: #292929;
+    background-color: #999999;
     border-radius: 6px;
   }
 }
+::-webkit-scrollbar {
+  width: 8px !important;
+  height: 8px !important;
+  background-color: black !important;
+}
+::-webkit-scrollbar-thumb {
+  background-color: #999999 !important;
+  border-radius: 6px !important;
+}
+.el-table--enable-row-hover .el-table__body tr:hover > td {
+  color: rgba(37, 116, 219, 0.8) !important;
+}
+.el-table__body tr.current-row > td {
+  color: rgba(37, 116, 219, 0.8) !important;
+}
 </style>

+ 38 - 1
src/api/index.js

@@ -206,7 +206,7 @@ const getWindturbineFdc = () => {
 const getWindturbineWarning = (data) => {
     return request({
         baseURL:process.env.VUE_APP_SHARDINGURL,
-        url: `/alarm/history/page?pagenum=${data.pagenum}&pagesize=${data.pagesize}&windturbineid=${data.windturbineid}&starttime=${data.starttime}&endtime=${data.endtime}`,
+        url: `/alarm/history/page?pagenum=${data.pagenum}&pagesize=${data.pagesize}&windturbineid=${data.windturbineid}&starttime=${data.starttime}&endtime=${data.endtime}&keyword=${data.keyword}&stationid=${data.stationid}`,
         method: "get",
     });
 };
@@ -226,6 +226,39 @@ const stationCompared = (data) => {
         method: "get",
     });
 };
+//温度矩阵
+const temperatureInfo = (data) => {
+    return request({
+        baseURL:process.env.VUE_APP_API,
+        url: `/api/windturbine/temperature-info?id=${data}`,
+        method: "get",
+    });
+};
+//获取风机故障
+const alarmSnap = (data) => {
+    return request({
+        baseURL:process.env.VUE_APP_API,
+        url: `/alarm/alarm-snap?windturbineId=${data.windturbineId}`,
+        method: "get",
+    });
+};
+
+//预警分析
+const analysisDetail = (data) => {
+    return request({
+        baseURL:process.env.VUE_APP_WARNING,
+        url: `/analysis/detail?station=${data.station}&startTs=${data.startTs}&endTs=${data.endTs}&interval=${data.interval}&wtId=${data.wtId}&name=${data.name}`,
+        method: "get",
+    });
+};
+//预警分析
+const alarmCountQuery = (data) => {
+    return request({
+        baseURL:process.env.VUE_APP_WARNING,
+        url: `/alarm/count/query/new2?stationid=${data.stationid}&startdate=${data.startdate}&enddate=${data.enddate}`,
+        method: "get",
+    });
+};
 export default {
     login,
     getStation,
@@ -257,4 +290,8 @@ export default {
     getWindturbineWarning,
     getFaultHistory,
     stationCompared,
+    temperatureInfo,
+    alarmSnap,
+    analysisDetail,
+    alarmCountQuery,
 };

+ 1 - 0
src/assets/dataService/README.md

@@ -0,0 +1 @@
+# 用于存放json数据文件 如果数据过大则需要单独打包

+ 234 - 0
src/assets/dataService/arcgis-mhs-line.json

@@ -0,0 +1,234 @@
+[
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "paths": [
+                [
+                    107.0644069,
+                    37.30000218
+                ],
+                [
+                    107.0609736,
+                    37.29027221
+                ],
+                [
+                    107.0545363,
+                    37.29431798
+                ],
+                [
+                    107.0488715,
+                    37.29385708
+                ],
+                [
+                    107.04561,
+                    37.29752713
+                ],
+                [
+                    107.0409322,
+                    37.30025821
+                ],
+                [
+                    107.0374346,
+                    37.30382554
+                ],
+                [
+                    107.0325208,
+                    37.30630038
+                ],
+                [
+                    107.0349455,
+                    37.30909941
+                ],
+                [
+                    107.0286155,
+                    37.30956022
+                ],
+                [
+                    107.0238519,
+                    37.31106208
+                ]
+            ]
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "width": 3
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "paths": [
+                [
+                    107.0649004,
+                    37.30542993
+                ],
+                [
+                    107.0527768,
+                    37.30129941
+                ],
+                [
+                    107.048614,
+                    37.30432051
+                ],
+                [
+                    107.0456958,
+                    37.30819486
+                ],
+                [
+                    107.0414472,
+                    37.31130101
+                ],
+                [
+                    107.0348811,
+                    37.31508967
+                ],
+                [
+                    107.0305467,
+                    37.31749588
+                ],
+                [
+                    107.0199444,
+                    37.31830556
+                ],
+                [
+                    107.0611238,
+                    37.30860447
+                ],
+                [
+                    107.0571327,
+                    37.31169354
+                ],
+                [
+                    107.0521975,
+                    37.31369028
+                ]
+            ]
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "width": 3
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "paths": [
+                [
+                    107.0693851,
+                    37.30322815
+                ],
+                [
+                    107.0744705,
+                    37.30041183
+                ],
+                [
+                    107.0696425,
+                    37.29628104
+                ],
+                [
+                    107.0717883,
+                    37.29213295
+                ],
+                [
+                    107.0662093,
+                    37.28824071
+                ],
+                [
+                    107.0567894,
+                    37.31587468
+                ],
+                [
+                    107.0560169,
+                    37.31988494
+                ],
+                [
+                    107.0506954,
+                    37.32184734
+                ],
+                [
+                    107.0727539,
+                    37.31087435
+                ],
+                [
+                    107.0761871,
+                    37.3067612
+                ],
+                [
+                    107.0820665,
+                    37.30641985
+                ]
+            ]
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "width": 3
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "paths": [
+                [
+                    107.0360184,
+                    37.32406563
+                ],
+                [
+                    107.0318985,
+                    37.32969639
+                ],
+                [
+                    107.0269525,
+                    37.33528407
+                ],
+                [
+                    107.0515966,
+                    37.32539657
+                ],
+                [
+                    107.0396662,
+                    37.33669159
+                ],
+                [
+                    107.0315766,
+                    37.34420644
+                ],
+                [
+                    107.0183909,
+                    37.34223611
+                ],
+                [
+                    107.0164329,
+                    37.33144098
+                ],
+                [
+                    107.0044997,
+                    37.32873236
+                ],
+                [
+                    107.0019168,
+                    37.33337322
+                ]
+            ]
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "width": 3
+        },
+        "popupTemplate": null
+    }
+]

+ 707 - 0
src/assets/dataService/arcgis-mhs.json

@@ -0,0 +1,707 @@
+[
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0674069,
+            "y": 37.3040218
+        },
+        "symbol": null,
+        "attributes": {
+            "objectid": 1,
+            "fc_code": "fc01",
+            "code": "升压站",
+            "type": "升压站"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0644069,
+            "y": 37.30000218
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG01",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0609736,
+            "y": 37.29027221
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG02",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0545363,
+            "y": 37.29431798
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG03",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0488715,
+            "y": 37.29385708
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG04",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.04561,
+            "y": 37.29752713
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG05",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0409322,
+            "y": 37.30025821
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG06",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0374346,
+            "y": 37.30382554
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG07",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0325208,
+            "y": 37.30630038
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG08",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0349455,
+            "y": 37.30909941
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG09",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0286155,
+            "y": 37.30956022
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG10",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0238519,
+            "y": 37.31106208
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG11",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0649004,
+            "y": 37.30542993
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG12",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0527768,
+            "y": 37.30129941
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG13",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.048614,
+            "y": 37.30432051
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG14",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0456958,
+            "y": 37.30819486
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG15",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0414472,
+            "y": 37.31130101
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG16",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0348811,
+            "y": 37.31508967
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG17",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0305467,
+            "y": 37.31749588
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG18",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0199444,
+            "y": 37.31830556
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG19",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0611238,
+            "y": 37.30860447
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG20",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0571327,
+            "y": 37.31169354
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG21",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0521975,
+            "y": 37.31369028
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG22",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0693851,
+            "y": 37.30322815
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG23",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0744705,
+            "y": 37.30041183
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG24",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0696425,
+            "y": 37.29628104
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG25",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0717883,
+            "y": 37.29213295
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG26",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0662093,
+            "y": 37.28824071
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG27",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0567894,
+            "y": 37.31587468
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG28",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0560169,
+            "y": 37.31988494
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG29",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0506954,
+            "y": 37.32184734
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG30",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0727539,
+            "y": 37.31087435
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG31",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0761871,
+            "y": 37.3067612
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG32",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0820665,
+            "y": 37.30641985
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG33",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0360184,
+            "y": 37.32406563
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG34",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0318985,
+            "y": 37.32969639
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG35",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0269525,
+            "y": 37.33528407
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG36",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0515966,
+            "y": 37.32539657
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG37",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0396662,
+            "y": 37.33669159
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG38",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0315766,
+            "y": 37.34420644
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG39",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0183909,
+            "y": 37.34223611
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG40",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0164329,
+            "y": 37.33144098
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG41",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0044997,
+            "y": 37.32873236
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG42",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    },
+    {
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 107.0019168,
+            "y": 37.33337322
+        },
+        "symbol": null,
+        "attributes": {
+            "fc_code": "MHS",
+            "code": "MG43",
+            "type": "风场"
+        },
+        "popupTemplate": null
+    }
+]

文件差异内容过多而无法显示
+ 1 - 0
src/assets/dataService/arcgis-nss-line.json


文件差异内容过多而无法显示
+ 1502 - 0
src/assets/dataService/arcgis-nss.json


文件差异内容过多而无法显示
+ 1 - 0
src/assets/dataService/arcgis-qs-line.json


文件差异内容过多而无法显示
+ 1007 - 0
src/assets/dataService/arcgis-qs.json


+ 173 - 0
src/assets/dataService/arcgis-sbq-line.json

@@ -0,0 +1,173 @@
+[{
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"paths": [
+			[106.4515667, 37.60171667],
+			[106.4368167, 37.6033],
+			[106.4341333, 37.60171667],
+			[106.4250833, 37.60041667],
+			[106.4375, 37.5879],
+			[106.4398167, 37.5854],
+			[106.4510667, 37.57506667],
+			[106.4539333, 37.57455],
+			[106.4591, 37.57405],
+			[106.4753, 37.57543333],
+			[106.48525, 37.57398333],
+			[106.4558833, 37.59241667],
+			[106.4520667, 37.59083333],
+			[106.4503333, 37.5869],
+			[106.4539, 37.58436667],
+			[106.4588333, 37.58393333],
+			[106.4689667, 37.58508333],
+			[106.4557667, 37.58851667],
+			[106.4691, 37.58788333],
+			[106.4727167, 37.5859],
+			[106.4853833, 37.58373333],
+			[106.501, 37.57553333],
+			[106.4698833, 37.6003],
+			[106.4722333, 37.59011667],
+			[106.4838333, 37.59091667],
+			[106.4861333, 37.58858333],
+			[106.4880333, 37.58626667],
+			[106.4897833, 37.58736667],
+			[106.5011667, 37.58518333],
+			[106.5076667, 37.58378333],
+			[106.5184167, 37.5862],
+			[106.5253667, 37.58713333],
+			[106.5342833, 37.58786667]
+		]
+	},
+	"symbol": null,
+	"attributes": {
+		"fc_code": "SBQ",
+		"width": 3
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"paths": [
+			[106.4565333, 37.63861667],
+			[106.4537167, 37.63945],
+			[106.4505667, 37.64101667],
+			[106.4369333, 37.64116667],
+			[106.43425, 37.65011667],
+			[106.43735, 37.654],
+			[106.4381333, 37.65733333],
+			[106.4344, 37.65973333],
+			[106.4393167, 37.66668333],
+			[106.4433167, 37.667],
+			[106.45585, 37.65986667],
+			[106.4680167, 37.63951667],
+			[106.4685, 37.65056667],
+			[106.4562167, 37.6501],
+			[106.43795, 37.65021667],
+			[106.4415833, 37.65116667],
+			[106.4413667, 37.65436667],
+			[106.4417667, 37.65761667],
+			[106.4568333, 37.65378333],
+			[106.47095, 37.65178333],
+			[106.4699833, 37.65555],
+			[106.4736333, 37.66703333],
+			[106.4756167, 37.63865],
+			[106.4847167, 37.64136667],
+			[106.4739833, 37.64246667],
+			[106.4729333, 37.65466667],
+			[106.4751667, 37.6567],
+			[106.48745, 37.65055],
+			[106.4874333, 37.65305],
+			[106.4893333, 37.65453333],
+			[106.48695, 37.65755],
+			[106.4923667, 37.64303333],
+			[106.4925333, 37.6522]
+		]
+	},
+	"symbol": null,
+	"attributes": {
+		"fc_code": "SBQ",
+		"width": 3
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"paths": [
+			[106.4372667, 37.60863333],
+			[106.4358333, 37.62263333],
+			[106.4697, 37.62076667],
+			[106.4594167, 37.6087],
+			[106.4585833, 37.60526667],
+			[106.4248667, 37.617],
+			[106.48565, 37.63513333],
+			[106.4233833, 37.63723333],
+			[106.4683667, 37.63515],
+			[106.4348333, 37.61908333],
+			[106.4395333, 37.62545],
+			[106.4423, 37.62185],
+			[106.4758667, 37.63501667],
+			[106.451, 37.60971667],
+			[106.4543167, 37.60706667],
+			[106.4505, 37.62356667],
+			[106.4544833, 37.61888333],
+			[106.4586833, 37.62058333],
+			[106.4376833, 37.63785],
+			[106.4405167, 37.61908333],
+			[106.4345, 37.63703333],
+			[106.4260833, 37.62615],
+			[106.4693667, 37.61766667],
+			[106.4713333, 37.63703333],
+			[106.4408833, 37.60918333]
+		]
+	},
+	"symbol": null,
+	"attributes": {
+		"fc_code": "SBQ",
+		"width": 3
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"paths": [
+			[106.53535, 37.60373333],
+			[106.5314833, 37.60988333],
+			[106.5277833, 37.61066667],
+			[106.5195, 37.6084],
+			[106.5133333, 37.60538333],
+			[106.5099333, 37.62868333],
+			[106.5286667, 37.62028333],
+			[106.5286833, 37.62013333],
+			[106.5013167, 37.62301667],
+			[106.459833, 37.61241667],
+			[106.5030833, 37.61541667],
+			[106.4942667, 37.61318333],
+			[106.4932667, 37.61023333],
+			[106.4872, 37.61611667],
+			[106.4764833, 37.61796667],
+			[106.4820833, 37.61956667],
+			[106.485, 37.62698333],
+			[106.4895333, 37.63096667],
+			[106.4963, 37.6317],
+			[106.5025167, 37.62693333],
+			[106.5047, 37.63411667],
+			[106.5142, 37.63583333],
+			[106.5098667, 37.64313333],
+			[106.50405, 37.64968333],
+			[106.4992333, 37.6394]
+		]
+	},
+	"symbol": null,
+	"attributes": {
+		"fc_code": "SBQ",
+		"width": 3
+	},
+	"popupTemplate": null
+}]

文件差异内容过多而无法显示
+ 1757 - 0
src/assets/dataService/arcgis-sbq.json


文件差异内容过多而无法显示
+ 1 - 0
src/assets/dataService/arcgis-xs-line.json


+ 887 - 0
src/assets/dataService/arcgis-xs.json

@@ -0,0 +1,887 @@
+[{
+        "geometry": {
+            "spatialReference": {
+                "wkid": 4326
+            },
+            "x": 105.2139616,
+            "y": 37.17630397
+        },
+        "symbol": null,
+        "attributes": {
+            "objectid": 1,
+            "fc_code": "fc01",
+            "code": "升压站",
+            "type": "升压站"
+        },
+        "popupTemplate": null
+    },{
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2139616,
+		"y": 37.17630397
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG01",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2186394,
+		"y": 37.17746656
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG02",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2209997,
+		"y": 37.18197998
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG03",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2246046,
+		"y": 37.18398015
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG04",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2170515,
+		"y": 37.16939645
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG05",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2227592,
+		"y": 37.17149955
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG06",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2188325,
+		"y": 37.17346581
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG07",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2284241,
+		"y": 37.17165343
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG08",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2288532,
+		"y": 37.17532943
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG09",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2307415,
+		"y": 37.17856075
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG10",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2354193,
+		"y": 37.18136453
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG11",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2213216,
+		"y": 37.16744719
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG12",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2199697,
+		"y": 37.1630697
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG13",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2188754,
+		"y": 37.15821314
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG14",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2351832,
+		"y": 37.16212919
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG15",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2419209,
+		"y": 37.16488228
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG16",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2455902,
+		"y": 37.16595955
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG17",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2475214,
+		"y": 37.16895189
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG18",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2521992,
+		"y": 37.16784046
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG19",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2424788,
+		"y": 37.16185559
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG20",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2399254,
+		"y": 37.15814473
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG21",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2384663,
+		"y": 37.15386932
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG22",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2489376,
+		"y": 37.16094927
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG23",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2476501,
+		"y": 37.15793952
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG24",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2444744,
+		"y": 37.15532299
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG25",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2115583,
+		"y": 37.17213218
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG26",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2099276,
+		"y": 37.17526105
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG27",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2087474,
+		"y": 37.18179192
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG28",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2079105,
+		"y": 37.18509134
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG29",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2108502,
+		"y": 37.18861284
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG30",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1989198,
+		"y": 37.1755517
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG31",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1991987,
+		"y": 37.18280057
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG32",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.198791,
+		"y": 37.18815129
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG33",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1958299,
+		"y": 37.1801849
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG34",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1887488,
+		"y": 37.18856156
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG35",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1947355,
+		"y": 37.17633817
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG36",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1866031,
+		"y": 37.17977459
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG37",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1873326,
+		"y": 37.1755688
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG38",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1796722,
+		"y": 37.17688527
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG39",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1824403,
+		"y": 37.18757008
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG40",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1773977,
+		"y": 37.18500586
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG41",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1714969,
+		"y": 37.18526229
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG42",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2116871,
+		"y": 37.16691711
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG43",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2104855,
+		"y": 37.1634288
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG44",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.207417,
+		"y": 37.16799435
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG45",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.201602,
+		"y": 37.16690001
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG46",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2053785,
+		"y": 37.15397194
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG47",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.2037477,
+		"y": 37.15821314
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG48",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1997781,
+		"y": 37.15963252
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG49",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1993275,
+		"y": 37.15679373
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG50",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.194757,
+		"y": 37.15879457
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG51",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1912808,
+		"y": 37.16060726
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG52",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1859164,
+		"y": 37.15607546
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG53",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1862597,
+		"y": 37.15226171
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG54",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1868176,
+		"y": 37.1622147
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG55",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1817322,
+		"y": 37.16525848
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG56",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1725054,
+		"y": 37.16621604
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG57",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}, {
+	"geometry": {
+		"spatialReference": {
+			"wkid": 4326
+		},
+		"x": 105.1694369,
+		"y": 37.1642838
+	},
+	"symbol": null,
+	"attributes": {
+		"code": "XG58",
+		"fc_code": "XS",
+		"type": "风场"
+	},
+	"popupTemplate": null
+}]

二进制
src/assets/img/menu/agc.png


二进制
src/assets/img/menu/booster.png


二进制
src/assets/img/menu/homePage.png


二进制
src/assets/img/menu/lock.png


二进制
src/assets/img/menu/matrix.png


二进制
src/assets/img/menu/screenshot.png


二进制
src/assets/img/menu/search.png


二进制
src/assets/img/menu/set.png


二进制
src/assets/img/menu/voice.png


+ 2 - 2
src/components/BasicInformationDetail.vue

@@ -340,7 +340,7 @@ export default {
         "需要登录",
       ],
       recordData: [],
-      intervals: "",
+      intervals: null,
       refreshTimer: "",
     };
   },
@@ -1038,7 +1038,7 @@ table {
 }
 
 .dataList {
-  width: 94%;
+  width: 97%;
   /* min-height: 250px; */
   height: 28vh;
   background-color: #141414;

+ 204 - 17
src/components/WindturbineDetailPages.vue

@@ -1,6 +1,6 @@
 <template>
   <el-dialog
-    width="75%"
+    width="80%"
     @opened="opened()"
     @closed="closed()"
     :show-close="false"
@@ -14,41 +14,123 @@
         <div class="chunkdiv">
           <div class="title">风机号:&emsp;</div>
           <!-- <div>{{ windturbine.windturbineId }}</div> -->
-          <div>{{ windturbine.stationId.slice(0,2)}}-{{windturbine.code }}</div>
+          <div>
+            {{ windturbine.stationId.slice(0, 2) }}-{{ windturbine.code }}
+          </div>
         </div>
-        <div class="chunkdiv" @dblclick="dbClicks(baseDate.windSpeed)">
+        <div
+          class="chunkdiv"
+          @click="handleClick(true)"
+          @dblclick="dbClicks(baseDate.windSpeed)"
+        >
           <div class="title">{{ baseDate.windSpeed.name }}:&emsp;</div>
           <div>{{ baseDate.windSpeed.value }}{{ baseDate.windSpeed.unit }}</div>
         </div>
         <div
           class="chunkdiv"
+          @click="handleClick(true)"
           @dblclick="dbClicks({ code: 'YDPJFS5M', name: '五分钟平均风速' })"
         >
           <div class="title">五分钟平均风速:&emsp;</div>
           <div>{{ healthInfo?.averageWindSpeed5?.toFixed(2) }}m/s</div>
         </div>
-        <div class="chunkdiv" @dblclick="dbClicks(theoreticalPower)">
+        <div
+          class="chunkdiv"
+          @click="handleClick(true)"
+          @dblclick="dbClicks(theoreticalPower)"
+        >
           <div class="title">理论功率:&emsp;</div>
           <div>{{ healthInfo?.theoreticalPower?.toFixed(2) }}Kw</div>
         </div>
-        <div class="chunkdiv" @dblclick="dbClicks(baseDate.power)">
+        <div
+          class="chunkdiv"
+          @click="handleClick(true)"
+          @dblclick="dbClicks(baseDate.power)"
+        >
           <div class="title">{{ baseDate.power.name }}:&emsp;</div>
           <div>{{ baseDate.power.value }}{{ baseDate.power.unit }}</div>
         </div>
-        <div class="chunkdiv" @dblclick="dbClicks(baseDate.generatorSpeed)">
+        <div
+          class="chunkdiv"
+          @click="handleClick(true)"
+          @dblclick="dbClicks(baseDate.generatorSpeed)"
+        >
           <div class="title">{{ baseDate.generatorSpeed.name }}:&emsp;</div>
           <div>
             {{ baseDate.generatorSpeed.value
             }}{{ baseDate.generatorSpeed.unit }}
           </div>
         </div>
+        <div class="chunkdiv" @click="handleClick(false)">
+          <div class="title">故障信息: &emsp;{{ faultNum }}</div>
+        </div>
       </div>
       <BasicInformationDetail
+        v-show="current"
         ref="BasicInfo"
         :types="types"
         @health-click="handleHealth"
         :windturbine="windturbine"
       ></BasicInformationDetail>
+      <div class="faultInfo" v-show="!current">
+        <div class="left-item">
+          <div
+            :class="item.openedCount > 0 ? 'faultNameErr' : 'faultName'"
+            v-for="(item, index) in fault"
+            :key="index"
+            @click="handleFaultClick(index)"
+          >
+            {{ item.component }}
+            <div class="faultNum" v-if="item.openedCount > 0">
+              ({{ item.openedCount }})
+            </div>
+          </div>
+        </div>
+        <div class="right-item">
+          <div class="tables">
+            <el-table
+              :data="faultList"
+              class="table"
+              style="width: 100%"
+              height="67vh"
+              stripe
+              highlight-current-row
+              :header-cell-style="{
+                background: 'rgb(30,30,30)',
+                color: 'rgb(220,220,220)',
+                padding: '4px',
+                fontSize: '14px',
+                'border-bottom': 'solid 1px rgba(77, 77, 77, 1)',
+              }"
+              :cell-style="tableCellStyle"
+            >
+              <el-table-column
+                prop="id"
+                label="报警编号"
+                width="200"
+                align="center"
+              >
+              </el-table-column>
+              <el-table-column
+                prop="modelId"
+                label="风机型号"
+                width="150"
+                align="center"
+              >
+              </el-table-column>
+              <el-table-column prop="alertText" label="报警信息" align="center">
+              </el-table-column>
+              <el-table-column label="故障状态" width="120" align="center">
+                <template #default="scope">
+                  <span>
+                    {{ scope.row.isOpened > 0 ? "故障" : "正常" }}
+                  </span>
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+        </div>
+      </div>
     </div>
   </el-dialog>
 </template>
@@ -57,6 +139,7 @@
 import api from "api/index";
 import BasicInformationDetail from "./BasicInformationDetail.vue";
 import BackgroundData from "utils/BackgroundData";
+import Fault from "utils/fault";
 export default {
   components: {
     BasicInformationDetail,
@@ -66,6 +149,7 @@ export default {
   },
   data() {
     return {
+      current: true,
       BasicInfo: {},
       healthInfo: {},
       line: "",
@@ -129,14 +213,15 @@ export default {
         },
       },
       types: null,
-      UniformCodes: {},
-      refreshTimer: '',
-      refreshTimers: '',
+      fault: {},
+      refreshTimer: "",
+      refreshTimers: "",
+      faultNum: 0,
+      faultList: [],
       // station: [],
     };
   },
   created() {
-    // this.UniformCodes = new UniformCodes();
     this.getUniformCodes();
     // this.getWindturbineFdc();
   },
@@ -147,6 +232,12 @@ export default {
     //     this.station = res.data;
     //   });
     // },
+    handleFaultClick(index) {
+      this.faultList = this.fault[index].alertSnaps;
+    },
+    handleClick(val) {
+      this.current = val;
+    },
     getUniformCodes() {
       api.getUniformCodes().then((res) => {
         this.UniformCodes = res.data;
@@ -156,7 +247,6 @@ export default {
       this.line = "";
       this.alarmTime = "";
       this.alarmContent = "";
-
       this.BasicInfo = this.uniformCodesDeal(this.windturbine);
       this.BasicInfo.windturbineId = this.windturbine.windturbineId;
       // this.dateDeal(this.BasicInfo)
@@ -165,6 +255,38 @@ export default {
       this.refreshData();
       this.refreshTimer = setInterval(this.refreshData, 5000);
     },
+    tableCellStyle({ row, column, rowIndex, columnIndex }) {
+      let warningColor = false;
+      let obj = {};
+      if (row.isOpened > 0) {
+        warningColor = true;
+      }
+      if (warningColor) {
+        obj = {
+          height: "40px",
+          background: "rgb(30,30,30)",
+          color: "#FF0000",
+          padding: "3px",
+          fontSize: "12px",
+          "border-top": "0px solid #000000",
+          "border-bottom": "1px solid #000000",
+          "border-right": "1px solid #000000",
+        };
+      } else {
+        obj = {
+          height: "40px",
+          background: "rgb(30,30,30)",
+          color: "rgb(220,220,220)",
+          padding: "3px",
+          fontSize: "12px",
+          "border-top": "0px solid #000000",
+          "border-bottom": "1px solid #000000",
+          "border-right": "1px solid #000000",
+        };
+      }
+
+      return obj;
+    },
     uniformCodesDeal(windturbine) {
       let val = this.UniformCodes[windturbine.stationId][windturbine.modelId];
       let codes = "";
@@ -177,16 +299,12 @@ export default {
       return val;
     },
     closed() {
-      // todo 切换页面的时候应该让上一个页面停止刷新数据(调用end方法)
-      // this.$refs.svgRef.closed();
-      // this.$refs.BasicInfo.end();
-      // this.$refs.BasicInfo.labelChange();
       this.$refs.BasicInfo.end();
       this.$emit("close");
       clearInterval(this.refreshTimer);
       clearInterval(this.refreshTimers);
-      this.refreshTimers = null
-      this.refreshTimer = null
+      this.refreshTimers = null;
+      this.refreshTimer = null;
     },
     dateDeal(BasicInfo) {
       let showInf = {};
@@ -238,6 +356,19 @@ export default {
         .catch((err) => {
           console.log(err);
         });
+      api
+        .alarmSnap({
+          windturbineId: this.windturbine.windturbineId,
+        })
+        .then((res) => {
+          this.fault = res.data;
+          this.faultList = res.data[0].alertSnaps;
+          let faultNum = 0;
+          this.fault.forEach((item) => {
+            faultNum = faultNum + item.openedCount;
+          });
+          this.faultNum = faultNum;
+        });
     },
     dbClicks(value) {
       this.$refs.BasicInfo.dbClicks(value, this.windturbine.windturbineId);
@@ -312,4 +443,60 @@ el-tabs {
   flex-direction: row;
   align-items: center;
 }
+.faultInfo {
+  height: 70vh;
+  display: flex;
+  flex-direction: row;
+  width: 100%;
+}
+.left-item {
+  width: 16%;
+  background-color: #4d4d4d;
+  display: flex;
+  flex-direction: column;
+  padding-top: 20px;
+  align-items: center;
+  height: 96%;
+  overflow-y: auto;
+}
+.faultName {
+  font-size: 16px;
+  color: #ffffff;
+  margin-bottom: 10px;
+}
+.faultNameErr {
+  display: flex;
+  flex-direction: row;
+  align-items: baseline;
+  font-size: 16px;
+  color: red;
+  margin-bottom: 15px;
+}
+.faultNum {
+  font-size: 12px;
+}
+.right-item {
+  width: 83%;
+  background-color: #4d4d4d;
+  margin-left: 15px;
+  height: 96%;
+  padding-bottom: 20px;
+}
+.el-table {
+  background-color: #000000 !important;
+}
+.el-table__body-wrapper::-webkit-scrollbar {
+  width: 8px !important;
+  height: 0px !important;
+  background-color: black !important;
+}
+
+.el-table__body-wrapper::-webkit-scrollbar-thumb {
+  background-color: #292929 !important;
+  border-radius: 6px !important;
+}
+.tables {
+  width: 98%;
+  margin: 1%;
+}
 </style>

+ 635 - 0
src/components/allMatrices.vue

@@ -0,0 +1,635 @@
+<template>
+  <el-dialog
+    width="70%"
+    @open="opened"
+    @closed="closed"
+    :fullscreen="true"
+    :show-close="true"
+    class="dialogs"
+  >
+    <template #title>
+      <div class="showTitles currentShowTitles">
+        <div class="titles">风机矩阵</div>
+      </div>
+    </template>
+    <div class="body" @contextmenu="contextmenu">
+      <div class="title">
+        <div
+          :class="current === item.id ? 'title-onItem' : 'title-item'"
+          v-for="(item, index) in stationList"
+          :key="index"
+          @click="handleChange(item.id)"
+        >
+          {{ item.address }}
+        </div>
+      </div>
+      <div class="content">
+        <box-select node=".box" @selectList="selectList">
+          <div
+            class="windStation"
+            v-for="(item, index) in stationArr"
+            :key="index"
+          >
+            <div class="stationTitle">
+              <div class="stationName">
+                {{
+                  stationList.filter((val) => item[0].stationId === val.id)[0]
+                    ?.address
+                }}
+              </div>
+              <div class="num">
+                <div class="jrts">接入台数</div>
+                <div class="jrts_num">{{ item.length }}</div>
+              </div>
+              <div class="num">
+                <div class="djts">待机台数</div>
+                <div class="djts_num">
+                  {{ item.filter((val) => val.status === 2)?.length }}
+                </div>
+              </div>
+              <div class="num">
+                <div class="bwts">并网台数</div>
+                <div class="bwts_num">
+                  {{ item.filter((val) => val.status === 4)?.length }}
+                </div>
+              </div>
+              <div class="num">
+                <div class="gzts">故障台数</div>
+                <div class="gzts_num">
+                  {{ item.filter((val) => val.status === 5)?.length }}
+                </div>
+              </div>
+              <div class="num">
+                <div class="jxts">检修台数</div>
+                <div class="jxts_num">
+                  {{ item.filter((val) => val.status === 6)?.length }}
+                </div>
+              </div>
+              <div class="num">
+                <div class="lxts">离线台数</div>
+                <div class="lxts_num">
+                  {{ item.filter((val) => val.status === 7)?.length }}
+                </div>
+              </div>
+            </div>
+            <div class="block">
+              <UnpaidMatrixBlock
+                @on-click="handleDetial"
+                @choose-click="handleClick"
+                :dataList="item"
+              >
+              </UnpaidMatrixBlock>
+            </div>
+          </div>
+        </box-select>
+      </div>
+    </div>
+    <WindturbineDetailPages
+      v-model="dialogVisible"
+      @close="handleClose"
+      :windturbine="currentWindturbine"
+    >
+    </WindturbineDetailPages>
+    <ParametersContrast
+      :chooseList="chooseList"
+      v-model="parametersDisplay"
+    ></ParametersContrast>
+  </el-dialog>
+</template>
+<script>
+import UnpaidMatrixBlock from "components/unpaidMatrixBlock.vue";
+import WindturbineDetailPages from "components/WindturbineDetailPages.vue";
+import boxSelect from "components/boxSelect.vue";
+import ParametersContrast from "./control/parametersContrast.vue";
+import api from "api/index";
+export default {
+  components: {
+    UnpaidMatrixBlock,
+    WindturbineDetailPages,
+    boxSelect,
+    ParametersContrast,
+  },
+  data() {
+    return {
+      current: "all",
+      windterbin: {},
+      stationObj: {},
+      cache: {},
+      stationArr: [],
+      dialogVisible: false,
+      currentWindturbine: {},
+      chooseList: [],
+      lockValues: [],
+      parametersDisplay: false,
+    };
+  },
+  created() {
+    this.getLocks();
+  },
+  mounted() {},
+  methods: {
+    opened() {
+      let stationList = [
+        {
+          id: "all",
+          address: "全部风机",
+        },
+      ];
+      let stations = this.$store.state.stationList;
+      stations.forEach((item) => {
+        if (item.id.indexOf("FDC") != -1) {
+          stationList.push(item);
+          this.stationObj[item.id] = [];
+        }
+      });
+      this.stationList = stationList;
+    },
+    closed() {},
+    handleChange(val) {
+      this.stationArr = [];
+      this.current = val;
+      this.stationObj = {};
+      let stations = this.$store.state.stationList;
+      stations.forEach((item) => {
+        if (val === "all") {
+          if (item.id.indexOf("FDC") != -1) {
+            this.stationObj[item.id] = [];
+          }
+        } else if (item.id === val) {
+          this.stationObj[item.id] = [];
+        }
+      });
+      if (val === "all") {
+        this.stationObj = this.cache;
+      } else {
+        this.stationObj[val] = this.cache[val];
+      }
+
+      let list = Object.keys(this.stationObj).sort();
+      for (const id of list) {
+        this.stationArr.push(this.stationObj[id]);
+      }
+    },
+    handleDetial(itm) {
+      this.dialogVisible = true;
+      this.currentWindturbine = itm;
+    },
+    handleClick(values) {
+      if (values.active) {
+        let showIndex = null;
+        this.chooseList.forEach((item, index) => {
+          if (item.windturbineId === values.windturbineId) {
+            showIndex = index;
+          }
+        });
+        this.chooseList.splice(showIndex, 1);
+      } else {
+        this.chooseList.push(values);
+      }
+      this.stationArr.forEach((item) => {
+        item.forEach((val) => {
+          if (val.windturbineId === values.windturbineId) {
+            val.active = !val.active;
+          }
+        });
+      });
+    },
+    handleClose() {
+      this.dialogVisible = false;
+      this.getLocks();
+    },
+    selectList(val) {
+      val.forEach((item) => {
+        this.handleClick(this.windterbin[item.id]);
+      });
+    },
+    getLocks() {
+      api.getCustomerLock().then((res) => {
+        if (res) {
+          this.lockValues = res.data;
+        }
+      });
+    },
+
+    /* 右键菜单 */
+    contextmenu() {
+      const remote = require("electron").remote;
+      let that = this;
+      let menuTemplate = [];
+      menuTemplate = [
+        {
+            label: "启动",
+            click() {
+              that.sendCommand({ controlType: "1", deviceType: "Manual" });
+            },
+          },
+          {
+            label: "停机",
+            click() {
+              that.sendCommand({ controlType: "2", deviceType: "Manual" });
+            },
+          },
+          {
+            label: "复位",
+            click() {
+              that.sendCommand({ controlType: "5", deviceType: "Manual" });
+            },
+          },
+          {
+            label: "维护",
+            click() {
+              that.sendCommand({ controlType: "6", deviceType: "Manual" });
+            },
+          },
+          {
+            label: "取消维护",
+            click() {
+              that.sendCommand({ controlType: "8", deviceType: "Manual" });
+            },
+          },
+          {
+            label: "挂牌",
+            submenu: [
+              {
+                label: "检修",
+                click() {
+                  that.sendLock({ value: "CheckLock" });
+                },
+              },
+              {
+                label: "故障维修",
+                click() {
+                  that.sendLock({ value: "FaultLock" });
+                },
+              },
+              {
+                label: "场内受累检修",
+                click() {
+                  that.sendLock({ value: "StationCheckLock" });
+                },
+              },
+              {
+                label: "场内受累故障",
+                click() {
+                  that.sendLock({ value: "StationFaulLock" });
+                },
+              },
+              {
+                label: "场外受累电网",
+                click() {
+                  that.sendLock({ value: "StationPowerLineLock" });
+                },
+              },
+              {
+                label: "场外受累天气",
+                click() {
+                  that.sendLock({ value: "StationWeatherLock" });
+                },
+              },
+            ],
+          },
+          {
+            label: "取消挂牌",
+            click() {
+              that.sendLock({ value: "UnLock" });
+            },
+          },
+          {
+            label: "参数对比",
+            click() {
+              that.parametersContrast();
+            },
+          },
+        ];
+
+      const menu = remote.Menu.buildFromTemplate(menuTemplate);
+
+      menu.popup(remote.getCurrentWindow());
+    },
+    sendCommand(msg, windturbine) {
+      let bd = BackgroundData.getInstance();
+      if (!bd.LoginUser) {
+        this.$notify({
+          title: "请登录",
+          message: "控制风机需要先登录!",
+          type: "warning",
+          position: "bottom-right",
+          offset: 60,
+          duration: 3000,
+        });
+        return;
+      }
+      let sendList = [];
+      if (windturbine) {
+        sendList = windturbine;
+      } else {
+        this.chooseList.forEach((item) => {
+          item.controlType = Number(msg.controlType);
+        });
+        sendList = this.chooseList;
+      }
+
+      if (sendList.length > 0) {
+        bd.checkout(sendList);
+        this.chooseList = [];
+        let pairs = {};
+        sendList.forEach((item) => {
+          let ct = {
+            windturbineId: item.windturbineId,
+            stationId: item.stationId,
+            projectId: item.projectId,
+            modelId: item.modelId,
+            controlType: item.controlType,
+            lockType: item.lockType,
+            userName: `system_${bd.LoginUser.name}`,
+            userId: 0,
+            auto: false,
+            deviceType: msg.deviceType,
+          };
+          pairs[ct.windturbineId] = ct;
+        });
+        api.windturbControl(pairs).then((res) => {
+          if (res) {
+            this.controlSuccess(res);
+          }
+        });
+      }
+    },
+    sendLock(msg, windturbine) {
+      let bd = BackgroundData.getInstance();
+      if (!bd.LoginUser) {
+        this.$notify({
+          title: "请登录",
+          message: "控制风机需要先登录!",
+          type: "warning",
+          position: "bottom-right",
+          offset: 60,
+          duration: 3000,
+        });
+        return;
+      }
+      let sendList = [];
+      if (windturbine) {
+        windturbine.lockType = msg.value;
+        sendList.push(windturbine);
+      } else {
+        this.chooseList.forEach((item) => {
+          item.lockType = msg.value;
+        });
+        sendList = this.chooseList;
+      }
+      if (sendList.length > 0) {
+        this.chooseList = [];
+        let pairs = {};
+        sendList.forEach((item) => {
+          let ct = {
+            windturbineId: item.windturbineId,
+            stationId: item.stationId,
+            projectId: item.projectId,
+            modelId: item.modelId,
+            controlType: item.controlType,
+            lockType: item.lockType,
+            userName: `system_${bd.LoginUser.name}`,
+            userId: 0,
+          };
+          pairs[ct.windturbineId] = ct;
+        });
+        api.windturbControlLock(pairs).then((res) => {
+          if (res) {
+            this.controlSuccess(res);
+          }
+        });
+      }
+    },
+
+    /* 控制成功 */
+    controlSuccess(msg) {
+      let bd = BackgroundData.getInstance();
+      for (let id in msg.data) {
+        let val = msg.data[id];
+        if (val.errorCode !== "0") {
+          bd.removeCheckouts(val);
+        }
+      }
+      let mss = ""; // 信息
+      let iserror = false; // 是否有控制错误的风机
+      for (let v in msg.data) {
+        let val = msg.data[v];
+        if (val.errorCode > 0) {
+          iserror = true;
+          mss += `${val.windturbineId}  ${
+            this.controlErorCodes[val.errorCode]
+          }\n`;
+        }
+      }
+      let tp = iserror ? "warning" : "success";
+      if (!iserror) {
+        mss = "控制成功";
+      }
+
+      this.$notify({
+        title: "控制",
+        message: mss,
+        type: tp,
+        position: "bottom-right",
+        offset: 60,
+        duration: 3000,
+      });
+    },
+
+    /* 控制失败 */
+    controlError(err) {
+      this.$notify({
+        title: "控制出现错误",
+        message: err.message,
+        type: "warning",
+        position: "bottom-right",
+        offset: 60,
+        duration: 3000,
+      });
+    },
+    parametersContrast() {
+      if (this.chooseList.length > 0) {
+        this.parametersDisplay = true;
+      }
+    },
+  },
+  watch: {
+    "$store.getters.windturbinelist": {
+      deep: true,
+      handler: function (json) {
+        this.stationArr = [];
+        for (const key in this.stationObj) {
+          this.stationObj[key] = [];
+        }
+        this.windterbin = json;
+        let arr = Object.keys(json).sort();
+        for (const id of arr) {
+          let val = json[id];
+          if (val.lockValue === 9) {
+            val.lockValues = this.lockValues.filter(
+              (item) => val.windturbineId === item.windturbineID
+            )[0]?.value;
+          }
+          this.chooseList.forEach((item) => {
+            if (item.windturbineId === val.windturbineId) {
+              val.active = true;
+            }
+          });
+          if (this.current === "all") {
+            this.stationObj[val.stationId]?.push(val);
+          } else {
+            if (this.current === val.stationId) {
+              this.stationObj[val.stationId]?.push(val);
+            }
+          }
+        }
+        this.current === "all" &&
+          (this.cache = JSON.parse(JSON.stringify(this.stationObj)));
+        let list = Object.keys(this.stationObj).sort();
+        for (const id of list) {
+          this.stationArr.push(this.stationObj[id]);
+        }
+      },
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.body {
+  display: flex;
+  flex-direction: column;
+  background-color: #000000;
+  height: 90vh;
+  width: 102%;
+  margin-left: -1%;
+  margin-top: -40px;
+  overflow-y: auto;
+}
+.body::-webkit-scrollbar {
+  /*隐藏滚轮*/
+  display: none;
+}
+.title {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin-left: 3vw;
+  padding-top: 8px;
+  position: absolute;
+  width: 100%;
+  background-color: #000000;
+  padding-bottom: 10px;
+
+  .title-item {
+    background-color: #242424;
+    border-radius: 4px;
+    padding: 8px 27px 7px 25px;
+    font-size: 14px;
+    color: #b4bdc0;
+    margin-right: 10px;
+  }
+  .title-onItem {
+    background-color: rgba(37, 116, 219, 1);
+    border-radius: 4px;
+    padding: 8px 27px 7px 25px;
+    font-size: 14px;
+    color: #b4bdc0;
+    margin-right: 10px;
+  }
+}
+.content {
+  display: flex;
+  flex-direction: column;
+  margin-top: 65px;
+}
+.block{
+  padding-left: 10px;
+}
+.windStation {
+  display: flex;
+  flex-direction: column;
+  background-color: #242424;
+  border-radius: 4px;
+  width: 95%;
+  margin-left: 3vw;
+  padding-bottom: 20px;
+  padding-left: 10px;
+  margin-bottom: 20px;
+
+  .stationTitle {
+    display: flex;
+    flex-direction: row;
+    // align-items: center;
+    margin-top: 10px;
+
+    .stationName {
+      font-size: 14px;
+      margin-left: 10px;
+      color: #b4bdc0;
+    }
+    .num {
+      display: flex;
+      flex-direction: row;
+      align-items: center;
+      justify-content: space-between;
+      margin-left: 25px;
+      width: 90px;
+
+      .jrts {
+        font-size: 12px;
+        color: #606769;
+      }
+      .jrts_num {
+        font-size: 16px;
+        color: #ffffff;
+      }
+
+      .djts {
+        font-size: 12px;
+        color: #05bb4c;
+      }
+      .djts_num {
+        font-size: 16px;
+        color: #05bb4c;
+      }
+
+      .bwts {
+        font-size: 12px;
+        color: #4b55ae;
+      }
+      .bwts_num {
+        font-size: 16px;
+        color: #4b55ae;
+      }
+
+      .gzts {
+        font-size: 12px;
+        color: #ba3237;
+      }
+      .gzts_num {
+        font-size: 16px;
+        color: #ba3237;
+      }
+
+      .jxts {
+        font-size: 12px;
+        color: #e17d24;
+      }
+      .jxts_num {
+        font-size: 16px;
+        color: #e17d24;
+      }
+
+      .lxts {
+        font-size: 12px;
+        color: #606769;
+      }
+      .lxts_num {
+        font-size: 16px;
+        color: #606769;
+      }
+    }
+  }
+}
+</style>

+ 6 - 3
src/components/boxSelect.vue

@@ -99,15 +99,18 @@ export default {
       // );
       // 本次框选元素
       let selctList = []
-        for (const i in elements[0].children) {
+      for (const key in elements) {
+        for (const i in elements[key].children) {
           if(Number(i) || i === '0'){
-            let val = elements[0].children[i]
+            let val = elements[key].children[i]
             const withinRange = isWithinRange(val, top, bottom, left, right);
             if(withinRange){
                 selctList.push(val)
             }
           }
         }
+      }
+        
       emit('selectList', selctList);
       // selectedElements.map((item) => {
       //     const withinRange = isWithinRange(item, top, bottom, left, right);
@@ -195,7 +198,7 @@ export default {
   top: 0;
   width: 0;
   height: 0;
-  // background: rgb(250, 12, 12);
+  background: rgba(106, 90, 205,.5);
   border: 1px solid blue;
   opacity: 0.6;
   pointer-events: none;

+ 1 - 1
src/components/check/areaCard.vue

@@ -18,7 +18,7 @@
     <div class="body">
         <img class="logo" src="../../assets/img/logo.png" alt="">
         <div class="title">{{ title }}</div>
-        <div class="record" @click="showRecord">校验记录</div>
+        <!-- <div class="record" @click="showRecord">校验记录</div> -->
         <div style="margin-top: 50px; margin-left: 20px; height: 80%;">
             <el-scrollbar>
                 <div class="scoll" style="margin-left: 5px;">

+ 8 - 6
src/components/check/operationRecords.vue

@@ -11,8 +11,10 @@
         <div class="titles">校验记录详情</div>
       </div>
     </template>
-    <div class="bodys">
-      <div class="left">
+    <div class="bodyDetial">
+      <!-- <div style="width: 50%;height:200px;background-color:red;"></div>
+      <div style="width: 50%;height:200px;background-color:yellow;"></div> -->
+      <div class="left-item">
         <el-scrollbar>
           <el-input placeholder="输入关键字进行过滤" v-model="filterText">
           </el-input>
@@ -29,7 +31,7 @@
           </el-tree>
         </el-scrollbar>
       </div>
-      <div class="rights">
+      <div class="right-item">
         <div class="dateBar">
           <el-date-picker
             class="pickers"
@@ -310,7 +312,7 @@ export default {
   padding: 30px 10px 10px 10px;
 }
 
-.bodys {
+.bodyDetial {
   display: flex;
   flex-direction: row;
   background-color: black;
@@ -319,14 +321,14 @@ export default {
   height: 60vh;
 }
 
-.left {
+.left-item {
   width: 20%;
   height: 100%;
   background-color: rgba(77, 77, 77, 1);
   border-right: 2px solid #000000;
 }
 
-.rights {
+.right-item {
   width: 80%;
   height: 100%;
   background-color: rgba(77, 77, 77, 1);

+ 6 - 6
src/components/control/areaCard.vue

@@ -302,12 +302,12 @@ export default {
       const { remote } = require("electron");
       let that = this;
       const menuTemplate = [
-        // {
-        //   label: "发送",
-        //   click() {
-        //     that.handleSend();
-        //   },
-        // },
+        {
+          label: "发送",
+          click() {
+            that.handleSend();
+          },
+        },
         {
           label: "挂牌",
           submenu: [

+ 30 - 38
src/components/control/controlAllArea.vue

@@ -356,36 +356,36 @@ export default {
         ];
       } else {
         menuTemplate = [
-          // {
-          //   label: "启动",
-          //   click() {
-          //     that.sendCommand({ controlType: "1", deviceType: "Manual" });
-          //   },
-          // },
-          // {
-          //   label: "停机",
-          //   click() {
-          //     that.sendCommand({ controlType: "2", deviceType: "Manual" });
-          //   },
-          // },
-          // {
-          //   label: "复位",
-          //   click() {
-          //     that.sendCommand({ controlType: "5", deviceType: "Manual" });
-          //   },
-          // },
-          // {
-          //   label: "维护",
-          //   click() {
-          //     that.sendCommand({ controlType: "6", deviceType: "Manual" });
-          //   },
-          // },
-          // {
-          //   label: "取消维护",
-          //   click() {
-          //     that.sendCommand({ controlType: "8", deviceType: "Manual" });
-          //   },
-          // },
+          {
+            label: "启动",
+            click() {
+              that.sendCommand({ controlType: "1", deviceType: "Manual" });
+            },
+          },
+          {
+            label: "停机",
+            click() {
+              that.sendCommand({ controlType: "2", deviceType: "Manual" });
+            },
+          },
+          {
+            label: "复位",
+            click() {
+              that.sendCommand({ controlType: "5", deviceType: "Manual" });
+            },
+          },
+          {
+            label: "维护",
+            click() {
+              that.sendCommand({ controlType: "6", deviceType: "Manual" });
+            },
+          },
+          {
+            label: "取消维护",
+            click() {
+              that.sendCommand({ controlType: "8", deviceType: "Manual" });
+            },
+          },
           {
             label: "挂牌",
             submenu: [
@@ -439,12 +439,6 @@ export default {
               that.parametersContrast();
             },
           },
-          // {
-          //     label: "标注",
-          //     click() {
-          //         that.sendLock({ type: "marking" });
-          //     },
-          // },
         ];
       }
 
@@ -782,8 +776,6 @@ export default {
             this.allList[item.stationName] = arr4;
           }
         });
-        // console.log(this.allNames);
-        console.log(this.allList);
 
         let checkoutList = BackgroundData.getInstance().checkouts;
         checkoutList.forEach((item) => {

+ 2 - 1
src/components/focus/agcDetails.vue

@@ -12,7 +12,7 @@
         <div class="titles">AGC监控</div>
       </div>
     </template>
-    <div class="bodyy">
+    <div class="bodyy currentScroll">
       <DataDetails
         ref="detailst"
         :allDate="allDate"
@@ -229,4 +229,5 @@ export default {
   margin-top: -30px;
   min-height: 90vh;
 }
+
 </style>

+ 287 - 0
src/components/focus/currentWarningCard.vue

@@ -0,0 +1,287 @@
+<template>
+  <div
+    class="currentWarningCardTableBox"
+    :class="$store.state.currentWarningCardClass"
+  >
+    <el-table
+      :data="tableData"
+      class="table"
+      height="30vh"
+      :header-cell-style="{
+        background: '#000000',
+        color: 'rgb(220,220,220)',
+        padding: '4px',
+        fontSize: '14px',
+        'border-bottom': 'solid 1px black',
+      }"
+      :cell-class-name="setCellClassName"
+    >
+      <el-table-column
+        prop="lastUpdateTime"
+        align="center"
+        label="时间"
+        width="150"
+      >
+      </el-table-column>
+      <el-table-column prop="alertText" align="center" label="描述" width="280">
+      </el-table-column>
+      <el-table-column prop="isSelected" align="center" label="确认">
+        <template v-slot="scope">
+          <input
+            type="checkbox"
+            v-model="scope.row.isSelected"
+            @click="itemChecked(scope.row)"
+          />
+        </template>
+      </el-table-column>
+    </el-table>
+  </div>
+</template>
+
+<script>
+import MessageBridge from "utils/MessageBridge";
+import BackgroundData from "utils/BackgroundData";
+import api from "api/index";
+
+export default {
+  name: "AlarmArea",
+  components: {},
+  created() {
+    this.initData();
+    this.faultMessage();
+  },
+  props: {
+    activeTab: {
+      type: String,
+      default: "",
+    },
+  },
+  data() {
+    return {
+      values: [],
+      tableData: [],
+      dialogVisible: false,
+      showSvg: false,
+      svgVisible: false,
+      svgWeb: "",
+      stationName: "",
+      currentWindturbine: {},
+      audio: null,
+    };
+  },
+  methods: {
+    filtrationData(activeTab) {
+      let syzAlarm = [];
+      let syzBase = [];
+      this.values.forEach((ele) => {
+        if (
+          ele.stationId === activeTab &&
+          ele.rank === this.$store.state.syzAlarmRank &&
+          ele.category1 === "SYZ"
+        ) {
+          syzAlarm.push(ele);
+        } else if (ele.stationId === activeTab && ele.category1 === "SYZ") {
+          syzBase.push(ele);
+        }
+      });
+
+      this.$store.commit(
+        "currentWarningCardClass",
+        syzAlarm.length ? "show" : ""
+      );
+
+      this.tableData = [].concat(syzAlarm, syzBase);
+    },
+    initData() {
+      let mb = MessageBridge.getInstance();
+      let vs = [
+        {
+          key: "/topic/fault-popup",
+          action: this.faultMessage,
+        },
+      ];
+      mb.register(vs);
+    },
+    faultMessage(json) {
+      let val = json ? JSON.parse(json) : this.$store.state.warning;
+      if (Object.keys(val).length > 0) {
+        let sleected = {};
+        this.values.forEach((it) => {
+          if (it.isSelected) {
+            sleected[it.id] = 0;
+          }
+        });
+        this.values = new Array();
+        for (let v in val) {
+          let vl = val[v];
+          if (vl.stationId != "QS_FDC" && vl.category1 == "FJ") {
+            vl.alertText = vl.windturbineName + "-" + vl.alertText;
+          }
+          if (sleected[vl.id] == 0 && BackgroundData.getInstance().LoginUser) {
+            vl.isSelected = true;
+          }
+          if (vl.category1 !== "GF" && vl.objectId.indexOf("GDC") === -1) {
+            this.values.push(vl);
+          }
+        }
+        this.filtrationData(this.activeTab);
+      }
+    },
+    close() {
+      this.dialogVisible = false;
+      this.svgVisible = false;
+    },
+    itemChecked(row) {
+      if (row.isSelected == true) {
+        row.isSelected = false;
+        return;
+      }
+      let bd = BackgroundData.getInstance();
+      if (!bd.LoginUser) {
+        this.$notify({
+          title: "请登录",
+          message: "确认报警需要先登录!",
+          type: "warning",
+          position: "bottom-right",
+          offset: 60,
+          duration: 3000,
+        });
+        row.isSelected = false;
+        return;
+      }
+      row.isSelected = true;
+      this.confirm(row);
+    },
+    confirm(item) {
+      api
+        .sendWarning({
+          snapID: item.snapIDString,
+          faultID: item.idString,
+          userName: BackgroundData.getInstance().LoginUser.name,
+        })
+        .then((msg) => {
+          let mms = msg.data > 0 ? "报警确认成功!" : "报警确认出现错误!";
+          let tp = msg.data > 0 ? "success" : "error";
+          msg.data === 0 ? (item.isSelected = false) : "";
+          this.$notify({
+            title: "报警",
+            message: mms,
+            type: tp,
+            position: "bottom-right",
+            offset: 60,
+            duration: 3000,
+          });
+        });
+    },
+    setCellClassName({ row }) {
+      if (row.rank === this.$store.state.syzAlarmRank) {
+        return "cellBase flicker";
+      } else {
+        return "cellBase";
+      }
+    },
+  },
+  watch: {
+    activeTab(res) {
+      this.filtrationData(res);
+    },
+  },
+};
+</script>
+<style scoped>
+.el-table::before {
+  width: 0;
+}
+
+.table {
+  background-color: rgba(0, 0, 0, 0.5);
+}
+
+:deep(.el-table__body-wrapper::-webkit-scrollbar) {
+  width: 8px;
+  height: 0px;
+  background-color: black;
+}
+
+:deep(.el-table__body-wrapper::-webkit-scrollbar-thumb) {
+  background-color: #292929;
+  border-radius: 6px;
+}
+
+:deep(.el-table td, .el-table th) {
+  border-bottom: 2px solid black;
+}
+.el-table__body-wrapper {
+  background-color: black;
+}
+tr {
+  line-height: 1.5;
+  background: #1e1e1e;
+  margin-bottom: 2px;
+  border-radius: 5px;
+}
+
+/* .ToolBar {
+  position: absolute;
+  right: 12px;
+  width: 586px;
+  text-align: center;
+  z-index: 2;
+  font-size: 14px;
+  height: 28px;
+  margin: 5px;
+  background: #1e1e1e;
+} */
+.table-main {
+  font-size: 14px;
+  width: 600px;
+  text-align: center;
+  background: #000000;
+  margin: 5px;
+  border-collapse: separate;
+  border-spacing: 0px 5px;
+}
+
+.currentWarningCardTableBox {
+  position: absolute;
+  right: -400px;
+  bottom: 40px;
+  padding-left: 5px;
+  padding-right: 5px;
+  opacity: 0.3;
+  transition: 0.3s;
+}
+.currentWarningCardTableBox:hover,
+.currentWarningCardTableBox.show {
+  right: 10px;
+  transition: 0.3s;
+  opacity: 1;
+}
+.currentWarningCardTableBox.hide {
+  opacity: 0.3;
+  transition: 0.3s;
+  right: -200px;
+}
+</style>
+<style lang="less">
+.cellBase {
+  background: rgb(30, 30, 30) !important;
+  color: rgb(220, 220, 220);
+  padding: 3px;
+  font-size: 12px;
+}
+.cellBase.flicker {
+  animation: flicker 0.6s infinite;
+}
+@keyframes flicker {
+  0% {
+    color: rgb(220, 220, 220);
+  }
+  50% {
+    color: orangered;
+  }
+  100% {
+    color: rgb(220, 220, 220);
+  }
+}
+</style>

+ 524 - 422
src/components/focus/dataDetails.vue

@@ -1,459 +1,561 @@
 <template>
-    <div class="body">
-        <div :class="index<3?'showContents':'showContents'" v-for="(item, index) in station" :key="index">
-            <div class="stationName">
-                <div class="titleName">{{item.name}}</div>
-                <div class="titleNames" v-if="item.schedulingName">({{item.schedulingName}})</div>
-                <img v-if="(!allDate[item.id]?.Status?.value) || allDate[item.id]?.Status?.value === 0" class="statusIcons"
-                    src="../../assets/img/controlcenter/daraTrue.png">
-                <img v-else class="statusIcons"
-                    src="../../assets/img/controlcenter/dataFalse.png">
-                <div class="titleNames" v-if="allDate[item.id]?.Status?.value && allDate[item.id]?.Status?.value!== 0">
-                    {{((1-this.allDate[item.id]?.PowerSet?.value/this.allDate[item.id]?.InstalledCapacity?.value)*100).toFixed(2)}}%
-                </div>
-            </div>
-            <div class="dataList">
-                <div class="data" @dblclick="dbClicks(allDate[item.id]?.PowerSet,'有功设定限值')">
-                    <div class="name">有功设定限值:</div>
-                    <div :class="index<3?'nums':'nums'">{{allDate[item.id]?.PowerSet?.value??0}}</div>
-                    <div class="unit">MW</div>
-                </div>
-                <div class="data" @dblclick="dbClicks(allDate[item.id]?.ActualPower,'实发有功')">
-                    <div class="name">实发有功:</div>
-                    <div :class="index<3?'nums':'nums'">{{allDate[item.id]?.ActualPower?.value??0}}</div>
-                    <div class="unit">MW</div>
-                </div>
-                <div class="data" @dblclick="dbClicks(allDate[item.id]?.AgcUp,'AGC可调上限')">
-                    <div class="name">AGC可调上限:</div>
-                    <div :class="index<3?'nums':'nums'">{{allDate[item.id]?.AgcUp?.value??0}}</div>
-                    <div class="unit">MW</div>
-                </div>
-                <div class="data" @dblclick="dbClicks(allDate[item.id]?.TheoryPower,'理论功率')">
-                    <div class="name">理论功率:</div>
-                    <div :class="index<3?'nums':'nums'">{{allDate[item.id]?.TheoryPower?.value??0}}</div>
-                    <div class="unit">MW</div>
-                </div>
-                <div class="data" @dblclick="dbClicks(allDate[item.id]?.AgcLower,'AGC可调下限')">
-                    <div class="name">AGC可调下限:</div>
-                    <div :class="index<3?'nums':'nums'">{{allDate[item.id]?.AgcLower?.value??0}}</div>
-                    <div class="unit">MW</div>
-                </div>
-
-                <div class="data" @dblclick="dbClicks(allDate[item.id]?.ForecastPower,'预测功率')">
-                    <div class="name">预测功率:</div>
-                    <div :class="index<3?'nums':'nums'">{{allDate[item.id]?.ForecastPower?.value??0}}</div>
-                    <div class="unit">MW</div>
-                </div>
-            </div>
-            <div class="condition">
-                <div class="status">
-                    <div class="name">{{allDate[item.id]?.AgcIn?.name}}:</div>
-                    <img v-if="allDate[item.id]?.AgcIn?.value === 0" class="statusIcon"
-                        src="../../assets/img/controlcenter/daraTrue.png">
-                    <img v-else-if="allDate[item.id]?.AgcIn?.value === 1" class="statusIcon"
-                        src="../../assets/img/controlcenter/dataFalse.png">
-                    <div v-else-if="allDate[item.id]?.AgcIn?.value === ''">
-                        暂无数据
-                    </div>
-                </div>
-                <div class="status">
-                    <div class="name">{{allDate[item.id]?.AgcFar?.name}}:</div>
-                    <img v-if="allDate[item.id]?.AgcFar?.value === 0" class="statusIcon"
-                        src="../../assets/img/controlcenter/daraTrue.png">
-                    <img v-else-if="allDate[item.id]?.AgcFar?.value === 1" class="statusIcon"
-                        src="../../assets/img/controlcenter/dataFalse.png">
-                    <div v-else-if="allDate[item.id]?.AgcFar?.value === ''">
-                        暂无数据
-                    </div>
-                </div>
-                <div class="status">
-                    <div class="name">{{allDate[item.id]?.SumLock?.name}}:</div>
-                    <img v-if="allDate[item.id]?.SumLock?.value === 0" class="statusIcon"
-                        src="../../assets/img/controlcenter/daraTrue.png">
-                    <img v-else-if="allDate[item.id]?.SumLock?.value === 1" class="statusIcon"
-                        src="../../assets/img/controlcenter/dataFalse.png">
-                    <div v-else-if="allDate[item.id]?.SumLock?.value === ''">
-                        暂无数据
-                    </div>
-                </div>
-                <div class="status">
-                    <div class="name">{{allDate[item.id]?.SubLock?.name}}:</div>
-                    <img v-if="allDate[item.id]?.SubLock?.value === 0" class="statusIcon"
-                        src="../../assets/img/controlcenter/daraTrue.png">
-                    <img v-else-if="allDate[item.id]?.SubLock?.value === 1" class="statusIcon"
-                        src="../../assets/img/controlcenter/dataFalse.png">
-                    <div v-else-if="allDate[item.id]?.SubLock?.value === ''">
-                        暂无数据
-                    </div>
-                </div>
-            </div>
-            <div :id="item.id" class="echarts" @dblclick="handleClick(item.id)"></div>
+  <div class="body">
+    <div
+      :class="index < 3 ? 'showContents' : 'showContents'"
+      v-for="(item, index) in station"
+      :key="index"
+    >
+      <div class="stationName">
+        <div class="titleName">{{ item.name }}</div>
+        <div class="titleNames" v-if="item.schedulingName">
+          ({{ item.schedulingName }})
+        </div>
+        <img
+          v-if="
+            !allDate[item.id]?.Status?.value ||
+            allDate[item.id]?.Status?.value === 0
+          "
+          class="statusIcons"
+          src="../../assets/img/controlcenter/daraTrue.png"
+        />
+        <img
+          v-else
+          class="statusIcons"
+          src="../../assets/img/controlcenter/dataFalse.png"
+        />
+        <div
+          class="titleNames"
+          v-if="
+            allDate[item.id]?.Status?.value &&
+            allDate[item.id]?.Status?.value !== 0
+          "
+        >
+          {{
+            (
+              (1 -
+                this.allDate[item.id]?.PowerSet?.value /
+                  this.allDate[item.id]?.InstalledCapacity?.value) *
+              100
+            ).toFixed(2)
+          }}%
+        </div>
+      </div>
+      <div class="dataList">
+        <div
+          class="data"
+          @dblclick="dbClicks(allDate[item.id]?.PowerSet, '有功设定限值')"
+        >
+          <div class="name">有功设定限值:</div>
+          <div :class="index < 3 ? 'nums' : 'nums'">
+            {{ allDate[item.id]?.PowerSet?.value ?? 0 }}
+          </div>
+          <div class="unit">MW</div>
+        </div>
+        <div
+          class="data"
+          @dblclick="dbClicks(allDate[item.id]?.ActualPower, '实发有功')"
+        >
+          <div class="name">实发有功:</div>
+          <div :class="index < 3 ? 'nums' : 'nums'">
+            {{ allDate[item.id]?.ActualPower?.value ?? 0 }}
+          </div>
+          <div class="unit">MW</div>
+        </div>
+        <div
+          class="data"
+          @dblclick="dbClicks(allDate[item.id]?.AgcUp, 'AGC可调上限')"
+        >
+          <div class="name">AGC可调上限:</div>
+          <div :class="index < 3 ? 'nums' : 'nums'">
+            {{ allDate[item.id]?.AgcUp?.value ?? 0 }}
+          </div>
+          <div class="unit">MW</div>
+        </div>
+        <div
+          class="data"
+          @dblclick="dbClicks(allDate[item.id]?.TheoryPower, '理论功率')"
+        >
+          <div class="name">理论功率:</div>
+          <div :class="index < 3 ? 'nums' : 'nums'">
+            {{ allDate[item.id]?.TheoryPower?.value ?? 0 }}
+          </div>
+          <div class="unit">MW</div>
+        </div>
+        <div
+          class="data"
+          @dblclick="dbClicks(allDate[item.id]?.AgcLower, 'AGC可调下限')"
+        >
+          <div class="name">AGC可调下限:</div>
+          <div :class="index < 3 ? 'nums' : 'nums'">
+            {{ allDate[item.id]?.AgcLower?.value ?? 0 }}
+          </div>
+          <div class="unit">MW</div>
         </div>
 
-        <Details @closed="closed()" v-model="display" :partsName='partsName' echartsId="modelEcharts" :datas="modelDetails" :calc="this.modelData.calc"
-        @search-data="search" @original-data="originalData"></Details>
+        <div
+          class="data"
+          @dblclick="dbClicks(allDate[item.id]?.ForecastPower, '预测功率')"
+        >
+          <div class="name">预测功率:</div>
+          <div :class="index < 3 ? 'nums' : 'nums'">
+            {{ allDate[item.id]?.ForecastPower?.value ?? 0 }}
+          </div>
+          <div class="unit">MW</div>
+        </div>
+      </div>
+      <div class="condition">
+        <div class="status">
+          <div class="name">{{ allDate[item.id]?.AgcIn?.name }}:</div>
+          <img
+            v-if="allDate[item.id]?.AgcIn?.value === 0"
+            class="statusIcon"
+            src="../../assets/img/controlcenter/daraTrue.png"
+          />
+          <img
+            v-else-if="allDate[item.id]?.AgcIn?.value === 1"
+            class="statusIcon"
+            src="../../assets/img/controlcenter/dataFalse.png"
+          />
+          <div v-else-if="allDate[item.id]?.AgcIn?.value === ''">暂无数据</div>
+        </div>
+        <div class="status">
+          <div class="name">{{ allDate[item.id]?.AgcFar?.name }}:</div>
+          <img
+            v-if="allDate[item.id]?.AgcFar?.value === 0"
+            class="statusIcon"
+            src="../../assets/img/controlcenter/daraTrue.png"
+          />
+          <img
+            v-else-if="allDate[item.id]?.AgcFar?.value === 1"
+            class="statusIcon"
+            src="../../assets/img/controlcenter/dataFalse.png"
+          />
+          <div v-else-if="allDate[item.id]?.AgcFar?.value === ''">暂无数据</div>
+        </div>
+        <div class="status">
+          <div class="name">{{ allDate[item.id]?.SumLock?.name }}:</div>
+          <img
+            v-if="allDate[item.id]?.SumLock?.value === 0"
+            class="statusIcon"
+            src="../../assets/img/controlcenter/daraTrue.png"
+          />
+          <img
+            v-else-if="allDate[item.id]?.SumLock?.value === 1"
+            class="statusIcon"
+            src="../../assets/img/controlcenter/dataFalse.png"
+          />
+          <div v-else-if="allDate[item.id]?.SumLock?.value === ''">
+            暂无数据
+          </div>
+        </div>
+        <div class="status">
+          <div class="name">{{ allDate[item.id]?.SubLock?.name }}:</div>
+          <img
+            v-if="allDate[item.id]?.SubLock?.value === 0"
+            class="statusIcon"
+            src="../../assets/img/controlcenter/daraTrue.png"
+          />
+          <img
+            v-else-if="allDate[item.id]?.SubLock?.value === 1"
+            class="statusIcon"
+            src="../../assets/img/controlcenter/dataFalse.png"
+          />
+          <div v-else-if="allDate[item.id]?.SubLock?.value === ''">
+            暂无数据
+          </div>
+        </div>
+      </div>
+      <div :id="item.id" class="echarts" @dblclick="handleClick(item.id)"></div>
     </div>
-    
+
+    <Details
+      @closed="closed()"
+      v-model="display"
+      :partsName="partsName"
+      echartsId="modelEcharts"
+      :datas="modelDetails"
+      :calc="this.modelData.calc"
+      @search-data="search"
+      @original-data="originalData"
+    ></Details>
+  </div>
 </template>
 <script>
-    import * as echarts from "echarts";
-    import Details from "../basicDataDetails.vue";
-    import api from "api/index";
-    export default {
-        components: {
-            Details
-        },
-        data() {
-            return {
-                display: false,
-                modelData: {},
-                partsName: '',
-            };
-        },
-        props: {
-            allDate: {
-                type: String,
-                default: ''
+import * as echarts from "echarts";
+import Details from "../basicDataDetails.vue";
+import api from "api/index";
+export default {
+  components: {
+    Details,
+  },
+  data() {
+    return {
+      display: false,
+      modelData: {},
+      partsName: "",
+    };
+  },
+  props: {
+    allDate: {
+      type: String,
+      default: "",
+    },
+    allChartDate: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    station: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+  },
+  updated() {
+    // this.totleErtcher()
+  },
+  mounted() {},
+  methods: {
+    dbClicks(data, partsName, timeValues) {
+      this.modelData = data;
+      let date = new Date();
+      let endTs = timeValues
+        ? timeValues[1] > date.getTime()
+          ? date.getTime()
+          : timeValues[1]
+        : date.getTime();
+      let startTs = timeValues ? timeValues[0] : endTs - 28800000;
+      data.tag &&
+        api
+          .getPower({
+            tagName: data.tag,
+            startTs: startTs,
+            endTs: endTs,
+            interval: 60,
+          })
+          .then((res) => {
+            if (res.data.length > 0) {
+              this.partsName = partsName;
+              this.display = true;
+              this.modelDetails = res.data;
+            } else {
+              this.modelDetails = [];
+            }
+          });
+    },
+    original(data, partsName, timeValues) {
+      this.modelData = data;
+      let date = new Date();
+      let endTs = timeValues
+        ? timeValues[1] > date.getTime()
+          ? date.getTime()
+          : timeValues[1]
+        : date.getTime();
+      let startTs = timeValues ? timeValues[0] : endTs - 28800000;
+      api
+        .getOriginalPower({
+          tagName: data.tag,
+          startTs: startTs,
+          endTs: endTs,
+        })
+        .then((res) => {
+          if (res.data.length > 0) {
+            this.partsName = partsName;
+            this.display = true;
+            this.modelDetails = res.data;
+          } else {
+            this.modelDetails = [];
+          }
+        });
+    },
+    search(values, interval) {
+      this.interval = interval;
+      this.dbClicks(this.modelData, this.partsName, values);
+    },
+    originalData(values) {
+      this.original(this.modelData, this.partsName, values);
+    },
+    totleErtcher() {
+      this.allChartDate.forEach((item) => {
+        let chartDom = document.getElementById(item.id);
+        let myChart = echarts.init(chartDom, "#ffffff");
+        let option;
+        option = {
+          legend: {
+            show: true,
+            data: item.value.map((t) => {
+              return t.title;
+            }),
+            right: 56,
+            icon: "circle",
+            itemWidth: 6,
+            inactiveColor: "#606769",
+            textStyle: {
+              color: "#B3BDC0",
+              fontSize: 12,
             },
-            allChartDate: {
-                type: Array,
-                default: () => {
-                    return []
+          },
+
+          xAxis: [
+            {
+              type: "category",
+              boundaryGap: false,
+              axisLabel: {
+                // interval: 60,
+                showMinLabel: true,
+                showMaxLabel: true,
+                formatter: "{value}",
+                fontSize: 14,
+                textStyle: {
+                  color: "#606769",
                 },
+              },
+              axisLine: {
+                show: false,
+              },
+              data: item.value[0].value.map((items) => {
+                return items.text;
+              }),
             },
-            station: {
-                type: Array,
-                default: () => {
-                    return []
-                },
+          ],
+          yAxis: {
+            type: "value",
+            axisLabel: {
+              formatter: "{value}",
+              fontSize: 14,
             },
-        },
-        updated() {
-            // this.totleErtcher() 
-        },
-        mounted() {
-
-        },
-        methods: {
-            dbClicks(data, partsName, timeValues) {
-                this.modelData = data
-                let date = new Date()
-                let endTs = timeValues ? (timeValues[1] > date.getTime()) ? date.getTime() : timeValues[1] : date.getTime();
-                let startTs = timeValues ? timeValues[0] : endTs - 28800000;
-                data.tag&&api.getPower({
-                    tagName: data.tag,
-                    startTs: startTs,
-                    endTs: endTs,
-                    interval: 60,
-                }).then(res => {
-                    if (res.data.length > 0) {
-                        this.partsName = partsName
-                        this.display = true;
-                        this.modelDetails = res.data
-                    } else {
-                        this.modelDetails = []
-                    }
-                })
+            axisLine: {
+              show: false,
             },
-            original(data, partsName, timeValues) {
-                this.modelData = data
-                let date = new Date()
-                let endTs = timeValues ? (timeValues[1] > date.getTime()) ? date.getTime() : timeValues[1] : date.getTime();
-                let startTs = timeValues ? timeValues[0] : endTs - 28800000;
-                api.getOriginalPower({
-                    tagName: data.tag,
-                    startTs: startTs,
-                    endTs: endTs,
-                }).then(res => {
-                    if (res.data.length > 0) {
-                        this.partsName = partsName
-                        this.display = true;
-                        this.modelDetails = res.data
-                    } else {
-                        this.modelDetails = []
-                    }
-                })
+            splitLine: {
+              show: true,
+              lineStyle: {
+                color: "#606769",
+                type: "dashed",
+              },
             },
-            search(values, interval) {
-                this.interval = interval
-                this.dbClicks(this.modelData, this.partsName, values)
+          },
+          dataZoom: [
+            {
+              show: false,
+              type: "inside",
+              start: 0,
+              end: 100,
             },
-            originalData(values) {
-                this.original(this.modelData, this.partsName, values)
-            },
-            totleErtcher() {
-                this.allChartDate.forEach(item => {
-                    let chartDom = document.getElementById(item.id);
-                    let myChart = echarts.init(chartDom, '#ffffff');
-                    let option;
-                    option = {
-                        legend: {
-                            show: true,
-                            data: item.value.map((t) => {
-                                return t.title;
-                            }),
-                            right: 56,
-                            icon: "circle",
-                            itemWidth: 6,
-                            inactiveColor: '#606769',
-                            textStyle: {
-                                color: '#B3BDC0',
-                                fontSize: 12,
-                            },
-                        },
-
-                        xAxis: [
-                            {
-                                type: "category",
-                                boundaryGap: false,
-                                axisLabel: {
-                                    // interval: 60,
-                                    showMinLabel: true,
-                                    showMaxLabel: true,
-                                    formatter: "{value}",
-                                    fontSize: 14,
-                                    textStyle: {
-                                        color: '#606769',
-                                    },
-                                },
-                                axisLine: {
-                                    show: false,
-                                },
-                                data: item.value[0].value.map(items => {
-                                    return items.text;
-                                }),
-                            },
-                        ],
-                        yAxis: {
-                            type: "value",
-                            axisLabel: {
-                                formatter: "{value}",
-                                fontSize: 14,
-                            },
-                            axisLine: {
-                                show: false,
-                            },
-                            splitLine: {
-                                show: true,
-                                lineStyle: {
-                                    color: '#606769',
-                                    type: "dashed",
-                                },
-                            },
-                        },
-                        dataZoom: [
-                            {
-                                show: false,
-                                type: 'inside',
-                                start: 0,
-                                end: 100
-                            },
-                        ],
-                        series: [{
-                            name: item.value[0].title,
-                            smooth: true,
-                            showSymbol: false,
-                            data: item.value[0].value.map(items => {
-                                return items.value;
-                            }),
-                            type: 'line',
-                            lineStyle: {
-                                normal: {
-                                    color: 'rgba(75, 85, 174, 1)',
-                                    width: 1,
-                                },
-                            },
-                        },
-                        {
-                            name: item.value[1].title,
-                            smooth: true,
-                            showSymbol: false,
-                            data: item.value[1].value.map(items => {
-                                return items.value;
-                            }),
-                            type: 'line',
-                            lineStyle: {
-                                normal: {
-                                    color: 'rgba(05, 187, 76, 1)',
-                                    width: 1,
-                                },
-                            },
-                        }]
-                    };
-                    option && myChart.setOption(option);
-                })
-
-            },
-            handleClick(id) {
-                this.$emit('handleClick', id);
-            },
-            opened() {
-
+          ],
+          series: [
+            {
+              name: item.value[0].title,
+              smooth: true,
+              showSymbol: false,
+              data: item.value[0].value.map((items) => {
+                return items.value;
+              }),
+              type: "line",
+              lineStyle: {
+                normal: {
+                  color: "rgba(75, 85, 174, 1)",
+                  width: 1,
+                },
+              },
             },
-            closed() {
-                this.detailsDisplay = false 
-                this.display = false;
-            }
-        },
-        watch:{
-            allChartDate: {
-                handler: function (json) {
-                    if (json) {
-                    this.totleErtcher() 
-                    }
+            {
+              name: item.value[1].title,
+              smooth: true,
+              showSymbol: false,
+              data: item.value[1].value.map((items) => {
+                return items.value;
+              }),
+              type: "line",
+              lineStyle: {
+                normal: {
+                  color: "rgba(05, 187, 76, 1)",
+                  width: 1,
                 },
+              },
             },
+          ],
+        };
+        option && myChart.setOption(option);
+      });
+    },
+    handleClick(id) {
+      this.$emit("handleClick", id);
+    },
+    opened() {},
+    closed() {
+      this.detailsDisplay = false;
+      this.display = false;
+    },
+  },
+  watch: {
+    allChartDate: {
+      handler: function (json) {
+        if (json) {
+          this.totleErtcher();
         }
-    }
+      },
+    },
+  },
+};
 </script>
 
 <style scoped>
-    .showTitles {
-        display: flex;
-        flex-direction: row;
-        align-items: center;
-        justify-content: center;
-        margin-top: -10px;
-        font-size: 18px;
-        color: #FFFFFF;
-    }
+.showTitles {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: center;
+  margin-top: -10px;
+  font-size: 18px;
+  color: #ffffff;
+}
+
+.showContent {
+  width: 32%;
+  display: flex;
+  flex-direction: column;
+  border: 1px solid rgba(77, 77, 77, 1);
+  /* background-color: rgba(77, 77, 77, 1); */
+  margin-right: 10px;
+  margin-left: 10px;
+  height: 44vh;
+  margin-top: 20px;
+  align-items: center;
+}
 
-    .showContent {
-        width: 32%;
-        display: flex;
-        flex-direction: column;
-        border: 1px solid rgba(77, 77, 77, 1);
-        /* background-color: rgba(77, 77, 77, 1); */
-        margin-right: 10px;
-        margin-left: 10px;
-        height: 44vh;
-        margin-top: 20px;
-        align-items: center;
-    }
+.showContents {
+  width: 40%;
+  display: flex;
+  flex-direction: column;
+  border: 1px solid rgba(77, 77, 77, 1);
+  /* background-color: rgba(77, 77, 77, 1); */
+  margin-right: 10px;
+  margin-left: 10px;
+  height: 43vh;
+  margin-top: 20px;
+  align-items: center;
+}
 
-    .showContents {
-        width: 40%;
-        display: flex;
-        flex-direction: column;
-        border: 1px solid rgba(77, 77, 77, 1);
-        /* background-color: rgba(77, 77, 77, 1); */
-        margin-right: 10px;
-        margin-left: 10px;
-        height: 43vh;
-        margin-top: 20px;
-        align-items: center;
-    }
+.stationName {
+  font-size: 20px;
+  width: 400px;
+  height: 45px;
+  border: 1px solid rgba(77, 77, 77, 1);
+  display: flex;
+  flex-direction: row;
+  align-items: baseline;
+  justify-content: center;
+  color: #ffffff;
+  background-color: #000000;
+  margin-top: -15px;
+}
 
-    .stationName {
-        font-size: 20px;
-        width: 400px;
-        height: 45px;
-        border: 1px solid rgba(77, 77, 77, 1);
-        display: flex;
-        flex-direction: row;
-        align-items: baseline;
-        justify-content: center;
-        color: #FFFFFF;
-        background-color: #000000;
-        margin-top: -15px;
-    }
+.titleName {
+  margin-top: 10px;
+}
 
-    .titleName {
-        margin-top: 10px;
-    }
+.titleNames {
+  font-size: 12px;
+  margin-left: 10px;
+  margin-top: 10px;
+}
 
-    .titleNames {
-        font-size: 12px;
-        margin-left: 10px;
-        margin-top: 10px;
-    }
+.body {
+  background-color: black;
+  width: 100%;
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+  justify-content: center;
+  height: 90vh;
+  overflow-y: auto;
+}
 
-    .body {
-        background-color: black;
-        width: 100%;
-        display: flex;
-        flex-direction: row;
-        flex-wrap: wrap;
-        justify-content: center;
-    }
+.body::-webkit-scrollbar {
+  /*隐藏滚轮*/
+  display: none;
+}
 
-    .echarts {
-        width: 100%;
-        height: 500px;
-        margin-left: 10px;
-        padding-top: -20px;
-    }
+.echarts {
+  width: 100%;
+  height: 500px;
+  margin-left: 10px;
+  padding-top: -20px;
+}
 
-    .dataList {
-        display: flex;
-        flex-direction: row;
-        flex-wrap: wrap;
-        align-items: center;
-        padding-top: 27px;
-    }
+.dataList {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+  align-items: center;
+  padding-top: 27px;
+}
 
-    .data {
-        width: 50%;
-        display: flex;
-        flex-direction: row;
-        align-items: center;
-        margin-bottom: 12px;
-        justify-content: center;
-    }
+.data {
+  width: 50%;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin-bottom: 12px;
+  justify-content: center;
+}
 
-    .name {
-        display: flex;
-        flex-direction: row-reverse;
-        font-size: 12px;
-        color: #FFFFFF;
-    }
+.name {
+  display: flex;
+  flex-direction: row-reverse;
+  font-size: 12px;
+  color: #ffffff;
+}
 
-    .num {
-        margin-left: 59px;
-        font-size: 16px;
-        color: #05BB4C;
-        min-width: 40px;
-    }
+.num {
+  margin-left: 59px;
+  font-size: 16px;
+  color: #05bb4c;
+  min-width: 40px;
+}
 
-    .nums {
-        margin-left: 29px;
-        font-size: 16px;
-        color: #05BB4C;
-        min-width: 40px;
-    }
+.nums {
+  margin-left: 29px;
+  font-size: 16px;
+  color: #05bb4c;
+  min-width: 40px;
+}
 
-    .unit {
-        font-size: 16px;
-        color: #FFFFFF;
-        margin-left: 15px;
-    }
+.unit {
+  font-size: 16px;
+  color: #ffffff;
+  margin-left: 15px;
+}
 
-    .condition {
-        width: 100%;
-        display: flex;
-        flex-direction: row;
-        align-items: center;
-        margin-bottom: 20px;
-        border-bottom: 1px solid #3D3D3D;
-        padding-bottom: 10px;
-    }
+.condition {
+  width: 100%;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin-bottom: 20px;
+  border-bottom: 1px solid #3d3d3d;
+  padding-bottom: 10px;
+}
 
-    .status {
-        width: 25%;
-        display: flex;
-        flex-direction: row;
-        align-items: center;
-        justify-content: center;
-    }
+.status {
+  width: 25%;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: center;
+}
 
-    .statusIcon {
-        width: 14px;
-        height: 14px;
-        margin-left: 8px;
-    }
-    .statusIcons {
-        width: 14px;
-        height: 14px;
-        margin-left: 20px;
-    }
+.statusIcon {
+  width: 14px;
+  height: 14px;
+  margin-left: 8px;
+}
+.statusIcons {
+  width: 14px;
+  height: 14px;
+  margin-left: 20px;
+}
 </style>

+ 135 - 24
src/components/focus/focusArea.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="body">
+  <!-- <div class="body">
     <img class="logo" src="../../assets/img/logo.png" alt="" />
     <div class="title">关注区</div>
     <div class="agc" @click="showAGC">AGC监控</div>
@@ -12,17 +12,45 @@
       </el-scrollbar>
     </div>
     <AGCDetails v-model="display"></AGCDetails>
-    <StationSvgDetailPages
-    v-model="displayBooster"
-    @close="close"
-  >
-  </StationSvgDetailPages>
+    <StationSvgDetailPages v-model="displayBooster" @close="close">
+    </StationSvgDetailPages>
+  </div> -->
+  <div class="body">
+    <img class="logo" src="../../assets/img/logo.png" alt="" />
+    <div class="title">关注区</div>
+    <!-- <div class="agc" @click="showAGC">AGC监控</div>
+    <el-tooltip
+      v-if="$store.state.syzBtnFlicker"
+      class="box-item"
+      effect="light"
+      :content="`您有${$store.state.syzAlarmArray.length}条报警未处理`"
+      placement="left"
+    >
+      <div
+        class="syz"
+        :class="$store.state.syzBtnFlicker ? 'flicker' : ''"
+        @click="showSYZ"
+      >
+        升压站
+      </div>
+    </el-tooltip> -->
+    <!-- <div v-else class="syz" @click="showSYZ">升压站</div> -->
+    <div style="margin-top: 50px; margin-left: 10px; height: 24vh">
+      <el-scrollbar>
+        <div class="scoll" style="margin-left: 5px">
+          <FocusCard></FocusCard>
+        </div>
+      </el-scrollbar>
+    </div>
+    <!-- <AGCDetails v-model="display"></AGCDetails>
+    <SYZDetails v-model="$store.state.syzDialogShow"></SYZDetails> -->
   </div>
 </template>
 <script>
 import FocusCard from "./focusCard.vue";
-import AGCDetails from "./agcDetails.vue";
-import StationSvgDetailPages from "../stationSvgDetailPages.vue";
+// import AGCDetails from "./agcDetails.vue";
+// import StationSvgDetailPages from "../stationSvgDetailPages.vue";
+// import SYZDetails from "./syzDetails.vue";
 export default {
   data() {
     return {
@@ -32,24 +60,28 @@ export default {
   },
   components: {
     FocusCard,
-    AGCDetails,
-    StationSvgDetailPages
+    // AGCDetails,
+    // StationSvgDetailPages,
+    // SYZDetails,
   },
   methods: {
-    showAGC() {
-      this.display = true;
-    },
-    showBooster(){
-      this.displayBooster = true;
-    },
-    close() {
-      this.displayBooster = false;
-    },
+    // showAGC() {
+    //   this.display = true;
+    // },
+    // showBooster() {
+    //   this.displayBooster = true;
+    // },
+    // close() {
+    //   this.displayBooster = false;
+    // },
+    // showSYZ() {
+    //   this.$store.commit("syzDialogShow", true);
+    // },
   },
 };
 </script>
 <style scoped>
-.box {
+/* .box {
   width: 100px;
   height: 20px;
 
@@ -71,9 +103,7 @@ export default {
   color: #ffffff;
   font-size: 14px;
   margin-left: 32px;
-  /* margin-top: 12px; */
   margin-bottom: 10px;
-  /* width: 570px; */
   width: 29vw;
   height: 50px;
   display: flex;
@@ -87,7 +117,6 @@ export default {
   content: "";
   position: absolute;
   left: -18px !important;
-  /* top: 30px !important; */
   width: 5px;
   height: 5px;
   background-color: rgba(230, 191, 65, 1);
@@ -113,7 +142,7 @@ export default {
   justify-content: center;
   background-color: rgba(37, 116, 219, 1);
 }
-.booster{
+.booster {
   position: absolute;
   color: #ffffff;
   font-size: 14px;
@@ -125,5 +154,87 @@ export default {
   align-items: center;
   justify-content: center;
   background-color: rgba(37, 116, 219, 1);
+} */
+.body {
+  border: 1px solid #373737;
+  width: 100%;
+  margin-left: 15px;
+  margin-top: 10px;
+  height: 30.5vh;
+}
+
+.body .scoll {
+  height: 91%;
+}
+
+.title {
+  color: #ffffff;
+  font-size: 14px;
+  margin-left: 32px;
+  /* margin-top: 12px; */
+  margin-bottom: 10px;
+  /* width: 570px; */
+  width: 27vw;
+  height: 50px;
+  display: flex;
+  align-items: center;
+  position: absolute;
+  background-color: #000000;
+}
+
+.title::before {
+  z-index: 1;
+  content: "";
+  position: absolute;
+  left: -18px !important;
+  /* top: 30px !important; */
+  width: 5px;
+  height: 5px;
+  background-color: rgba(230, 191, 65, 1);
+  border-radius: 50%;
+}
+
+.logo {
+  position: absolute;
+  top: 2px;
+  left: 12px;
+}
+
+.agc,
+.syz {
+  position: absolute;
+  color: #ffffff;
+  font-size: 14px;
+  right: 0;
+  top: 23px;
+  width: 80px;
+  height: 30px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: rgba(37, 116, 219, 1);
+  cursor: pointer;
+}
+
+.syz {
+  right: 90px;
+  transition: 0.2s;
+}
+
+.syz.flicker {
+  right: 90px;
+  animation: flicker 0.8s infinite;
+}
+
+@keyframes flicker {
+  0% {
+    background: rgba(37, 116, 219);
+  }
+  50% {
+    background: orangered;
+  }
+  100% {
+    background: rgba(37, 116, 219);
+  }
 }
 </style>

+ 345 - 0
src/components/focus/syzDetails.vue

@@ -0,0 +1,345 @@
+<template>
+  <el-dialog
+    width="90%"
+    @open="opened"
+    @closed="closed"
+    :fullscreen="true"
+    :show-close="true"
+    class="dialogs"
+  >
+    <template #title>
+      <div class="showTitles currentShowTitles">
+        <div class="titles">升压站</div>
+      </div>
+    </template>
+    <div class="bodyy">
+      <el-tabs
+        type="border-card"
+        stretch
+        lazy
+        style="width: 100%; height: 100%"
+        v-model="activeTab"
+        @tab-click="tabClick"
+      >
+        <el-tab-pane
+          class="syzDetailsPaneItem"
+          v-for="(item, index) in syzArray"
+          :key="index"
+          :name="item.id"
+        >
+          <template #label>
+            <span v-if="pageshowMode % 2">
+              <el-badge is-dot v-if="item.isWarning === '1'">
+                <span>{{ item.name }}</span>
+              </el-badge>
+              <span v-else>{{ item.name }}</span>
+            </span>
+            <span v-else>
+              <el-badge is-dot v-if="item.isWarning === '1'">
+                <span>{{ item.name }}</span>
+              </el-badge>
+              <span v-else>{{ item.name }}</span>
+            </span>
+          </template>
+          <CL v-if="item.id === 'CL_FDC'" />
+          <KB v-if="item.id === 'KB_FDC'" />
+          <KB v-if="item.id === 'DX_FDC'" />
+          <div class="alarmIconBox" @click="switchAlarmSound(index)">
+            <el-tooltip
+              v-if="item.isMute"
+              effect="light"
+              :content="`当前${item.name}升压站报警已消音,请注意`"
+              placement="left"
+            >
+              <i
+                class="el-icon-close-notification"
+                style="color: orangered"
+              ></i>
+            </el-tooltip>
+            <i v-else class="el-icon-bell" style="color: rgb(219, 215, 0)"></i>
+          </div>
+        </el-tab-pane>
+      </el-tabs>
+      <CurrentWarningCard
+        :currentClass="$store.state.currentWarningCardClass"
+        :activeTab="activeTab || 'MHS_FDC'"
+      />
+    </div>
+  </el-dialog>
+</template>
+<script>
+import CL from "../BoosterStation/cl.vue";
+import DX from "../BoosterStation/dx.vue";
+import KB from "../BoosterStation/kb.vue";
+
+import CurrentWarningCard from "./currentWarningCard.vue";
+export default {
+  components: {
+    CL,
+    DX,
+    KB,
+    CurrentWarningCard,
+  },
+  data() {
+    return {
+      activeTab: this.$store.state.activeTab,
+      svgVisible: true,
+      audio: null,
+      timmer: null,
+      syzArray: this.$store.getters.syzArray || [],
+      pageshowMode: 0,
+    };
+  },
+  created() {},
+  mounted() {},
+  updated() {},
+  methods: {
+    // 初始化第一次报警并判断是否播放声音
+    initAlarm() {
+      let syzAlarmArray = this.$store.getters.syzAlarmArray;
+
+      const firstAlarmItem = syzAlarmArray.find((ele) => {
+        return !ele.isConfirm && ele.rank === this.$store.state.syzAlarmRank;
+      });
+
+      firstAlarmItem &&
+        this.audioPlay(this.getSound(firstAlarmItem.soundSource));
+
+      firstAlarmItem &&
+        this.$store.getters.syzAlarmArray.forEach((ele) => {
+          if (ele.stationId === firstAlarmItem.stationId) {
+            ele.isConfirm = true;
+          }
+        });
+
+      this.activeTab =
+        firstAlarmItem?.stationId ||
+        syzAlarmArray.find((ele) => {
+          return ele.rank === this.$store.state.syzAlarmRank;
+        })?.stationId ||
+        this.$store.getters.syzArray[0].id;
+
+      syzAlarmArray.forEach((ele) => {
+        if (ele.stationId === firstAlarmItem?.stationId) {
+          ele.isConfirm = true;
+          this.clearWarningTag(ele.stationId);
+        } else if (
+          !ele.isConfirm &&
+          ele.stationId !== firstAlarmItem?.stationId
+        ) {
+          this.renderWarningTag(ele.stationId);
+        }
+      });
+
+      this.$store.commit("syzAlarmArray", syzAlarmArray);
+    },
+
+    // 定时器循环数据判断小红点渲染及是否播放声音
+    renderAlarm(stationId = "", playSound = true) {
+      let syzAlarmArray = this.$store.getters.syzAlarmArray;
+
+      syzAlarmArray.forEach((ele) => {
+        if (ele.stationId === stationId) {
+          ele.isConfirm = true;
+          this.clearWarningTag(ele.stationId);
+        } else if (!ele.isConfirm && ele.stationId !== stationId) {
+          this.renderWarningTag(ele.stationId);
+        }
+      });
+
+      const res = syzAlarmArray.find((ele) => {
+        return !ele.isConfirm;
+      });
+
+      if (playSound) {
+        // this.audioPlay("./static/sound/syz.mp3");
+      }
+
+      this.$store.commit("syzAlarmArray", syzAlarmArray);
+    },
+
+    // 返回音频文件路径
+    getSound(fileName) {
+      return `./static/sound/${fileName}.mp3`;
+    },
+
+    // 播放音频
+    audioPlay(audioPath) {
+      let soundMuteSelf = [];
+      let soundMuteOther = [];
+
+      this.$store.getters.syzAlarmArray.forEach((ele) => {
+        if (ele.stationId === this.activeTab) {
+          soundMuteSelf.push(ele);
+        } else {
+          soundMuteOther.push(ele);
+        }
+      });
+
+      let alarmSelfLock = soundMuteSelf.some((ele) => {
+        return !ele.isConfirm;
+      });
+
+      let alarmOtherLock = soundMuteOther.some((ele) => {
+        return !ele.isConfirm;
+      });
+
+      if (alarmOtherLock) {
+        this.audio = new Audio(audioPath);
+        this.audio.play();
+      } else if (alarmSelfLock) {
+        this.$store.getters.syzArray.forEach((ele) => {
+          if (ele.stationId === this.activeTab) {
+            ele.isMute = false;
+            this.audio = new Audio(audioPath);
+            this.audio.play();
+          }
+        });
+      } else if (!alarmSelfLock) {
+        this.$store.getters.syzArray.forEach((ele) => {
+          if (ele.stationId === this.activeTab) {
+            if (!ele.isMute) {
+              this.audio = new Audio(audioPath);
+              this.audio.play();
+            }
+          }
+        });
+      }
+    },
+
+    // 显示某个小红点
+    renderWarningTag(stationId = "") {
+      this.$store.getters.syzArray.forEach((ele) => {
+        if (ele.id === stationId) {
+          ele.isWarning = "1";
+        }
+      });
+      this.pageshowMode++;
+    },
+
+    // 清除某个小红点
+    clearWarningTag(stationId = "") {
+      this.$store.getters.syzArray.forEach((ele) => {
+        if (ele.id === stationId) {
+          ele.isWarning = "0";
+        }
+      });
+      this.pageshowMode++;
+    },
+
+    // 切换报警声音开关
+    switchAlarmSound(index) {
+      this.$store.getters.syzArray[index].isMute =
+        !this.$store.getters.syzArray[index].isMute;
+    },
+
+    opened() {
+      this.initAlarm();
+      this.timmer = setInterval(() => {
+        this.renderAlarm();
+      }, 3000);
+    },
+
+    closed() {
+      clearInterval(this.timmer);
+      this.timmer = null;
+      this.$store.commit("activeTab", "");
+      this.$store.commit("syzDialogShow", false);
+    },
+
+    tabClick(res) {
+      this.$store.commit("activeTab", res.props.name);
+      this.renderAlarm(res.props.name, false);
+    },
+  },
+  watch: {
+    "$store.state.syzArray"(res) {
+      this.syzArray = res;
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.bodyy {
+  display: flex;
+  flex-direction: row;
+  background-color: black;
+  width: 98%;
+  margin-top: -30px;
+  height: 90vh;
+  position: relative;
+  overflow: hidden;
+  margin-left: 44px;
+
+  .syzDetailsPaneItem {
+    position: relative;
+
+    .alarmIconBox {
+      position: absolute;
+      right: 0;
+      top: 0;
+      cursor: pointer;
+
+      i {
+        font-size: 20px;
+      }
+    }
+  }
+}
+</style>
+<style lang="less">
+.bodyy {
+  .pop-up-main,
+  .paln-box {
+    width: 100%;
+    height: 90vh;
+    overflow: hidden;
+    position: relative;
+  }
+  .movableItem {
+    width: 100% !important;
+    height: 100% !important;
+
+    .svg {
+      width: 100%;
+      height: 92%;
+      margin-left: 0;
+      margin-top: 8%;
+    }
+  }
+
+  .el-badge__content.is-fixed.is-dot {
+    right: 0;
+    top: 10px;
+    background: #f25656;
+    animation: twinkle 0.75s infinite;
+    border-color: transparent;
+  }
+
+  @keyframes twinkle {
+    0% {
+      opacity: 0;
+    }
+    50% {
+      opacity: 1;
+    }
+    100% {
+      opacity: 0;
+    }
+  }
+}
+
+.currentShowTitles {
+  width: 100%;
+  position: relative;
+  .alarIcon {
+    position: absolute;
+    right: 50px;
+    top: 5;
+    font-size: 20px;
+    cursor: pointer;
+  }
+}
+
+</style>

+ 101 - 96
src/components/matrixBlock.vue

@@ -1,107 +1,112 @@
 <template>
-<div>
-  <div class="box" style="display: flex; flex-direction: row; flex-wrap: wrap">
+  <div>
     <div
-      :class="
-        item.active
-          ? 'box-' + item.status
-          : item.flashing && item.status === 5
-          ? 'unbox-flashing-' + item.status
-          : 'unbox-' + item.status
-      "
-      :id="item.windturbineId"
-      v-for="(item, index) in dataList"
-      :key="index"
-      @click="onSelectHandler(item)"
-      @dblclick="sendMsg(item)"
-      style="margin-right: 8px"
+      class="box"
+      style="display: flex; flex-direction: row; flex-wrap: wrap"
     >
       <div
-        :class="item.active ? 'left-' + item.status : 'unleft-' + item.status"
+        :class="
+          item.active
+            ? 'box-' + item.status
+            : item.flashing && item.status === 5
+            ? 'unbox-flashing-' + item.status
+            : 'unbox-' + item.status
+        "
+        :id="item.windturbineId"
+        v-for="(item, index) in dataList"
+        :key="index"
+        @click="onSelectHandler(item)"
+        @dblclick="sendMsg(item)"
+        style="margin-right: 8px"
       >
-        <!-- <div>{{ item.windturbineId.slice(0, 2) }}</div>
-                <div>{{ item.windturbineId.slice(5) }}</div> -->
-        <div>{{ item.windturbineId.slice(0, 2) }}</div>
-        <div>{{ item.code }}</div>
-      </div>
-      <div
-        :class="item.active ? 'right-' + item.status : 'unright-' + item.status"
-      >
-        <div class="rightrow">{{ item.windSpeed.toFixed(2) }} m/s</div>
-
-        <div class="rightrow">{{ item.power.toFixed(2) }} kw</div>
-
-        <div class="rightrow">
-          {{
-            item.modelId.indexOf("105") >= 0
-              ? (item.rollSpeed * 9.55).toFixed(2)
-              : item.rollSpeed.toFixed(2)
-          }}
-          rpm
+        <div
+          :class="item.active ? 'left-' + item.status : 'unleft-' + item.status"
+        >
+          <div>{{ item.windturbineId.slice(0, 2) }}</div>
+          <div>{{ item.windturbineId.slice(5) }}</div>
+          <!-- <div>{{ item.windturbineId.slice(0, 2) }}</div>
+        <div>{{ item.code }}</div> -->
         </div>
-      </div>
-      <div class="duration">
-        <el-popover
-          placement="bottom-start"
-          :width="200"
-          trigger="hover"
-          class="durationPopover"
-          :show-arrow="false"
-          @show="handleDeal(item.ts)"
+        <div
+          :class="
+            item.active ? 'right-' + item.status : 'unright-' + item.status
+          "
         >
-          <template #reference>
-            <img
-              :class="item.lockValue > 0 ? 'durationImgs' : 'durationImg'"
-              src="../assets/img/type/duration.png"
-              alt=""
+          <div class="rightrow">{{ item.windSpeed.toFixed(2) }} m/s</div>
+
+          <div class="rightrow">{{ item.power.toFixed(2) }} kw</div>
+
+          <div class="rightrow">
+            {{
+              item.modelId.indexOf("105") >= 0
+                ? (item.rollSpeed * 9.55).toFixed(2)
+                : item.rollSpeed.toFixed(2)
+            }}
+            rpm
+          </div>
+        </div>
+        <div class="duration">
+          <el-popover
+            placement="bottom-start"
+            :width="200"
+            trigger="hover"
+            class="durationPopover"
+            :show-arrow="false"
+            @show="handleDeal(item.ts)"
+          >
+            <template #reference>
+              <img
+                :class="item.lockValue > 0 ? 'durationImgs' : 'durationImg'"
+                src="../assets/img/type/duration.png"
+                alt=""
+              />
+            </template>
+            <input
+              class="lock_inputs"
+              type="text"
+              placeholder=""
+              :value="showVlaues"
+              disabled
             />
-          </template>
-          <input
-            class="lock_inputs"
-            type="text"
-            placeholder=""
-            :value="showVlaues"
-            disabled
-          />
-        </el-popover>
-      </div>
-      <div class="locks" v-if="item.lockValue > 0">
-        <el-popover
-          placement="bottom-start"
-          :width="150"
-          trigger="hover"
-          class="popoverBack"
-          :show-arrow="false"
-        >
-          <template #reference>
-            <img class="lock" src="../assets/img/type/lock.png" alt="" />
-          </template>
-          <input
-            class="lock_input"
-            type="text"
-            placeholder=""
-            :value="
-              item.lockValue === 9 ? item.lockValues : options[item.lockValue]
-            "
-            disabled
+          </el-popover>
+        </div>
+        <div class="locks" v-if="item.lockValue > 0">
+          <el-popover
+            placement="bottom-start"
+            :width="150"
+            trigger="hover"
+            class="popoverBack"
+            :show-arrow="false"
+          >
+            <template #reference>
+              <img class="lock" src="../assets/img/type/lock.png" alt="" />
+            </template>
+            <input
+              class="lock_input"
+              type="text"
+              placeholder=""
+              :value="
+                item.lockValue === 9 ? item.lockValues : options[item.lockValue]
+              "
+              disabled
+            />
+          </el-popover>
+        </div>
+        <div class="locks" v-if="item.reasonType">
+          <img
+            class="lock"
+            src="../assets/img/type/electricityRestrictions.png"
+            alt=""
           />
-        </el-popover>
-      </div>
-      <div class="locks" v-if="item.reasonType">
-        <img
-          class="lock"
-          src="../assets/img/type/electricityRestrictions.png"
-          alt=""
-        />
+        </div>
       </div>
     </div>
-  </div>
-  <WindturbineDetailPages
-    v-model="dialogVisible"
-    :showSvg="showSvg"
-    @close="handleClose"
-    :windturbine="currentWindturbine"
-  ></WindturbineDetailPages>
+    <WindturbineDetailPages
+      v-model="dialogVisible"
+      :showSvg="showSvg"
+      @close="handleClose"
+      :windturbine="currentWindturbine"
+    ></WindturbineDetailPages>
   </div>
 </template>
 <script>
@@ -665,10 +670,10 @@ export default {
 }
 
 .box-5 {
-  width: 133px;
-  height: 48px;
+  width: 135px;
+  height: 50px;
   color: #ffffff;
-  border: 2px solid rgba(186, 50, 55, 1);
+  border: 1px solid rgba(186, 50, 55, 1);
   background-color: rgba(186, 50, 55, 0.05);
   display: flex;
   flex-direction: row;

文件差异内容过多而无法显示
+ 695 - 495
src/components/modeControl/modeControl.vue


+ 93 - 0
src/components/panel/panel-no-title.vue

@@ -0,0 +1,93 @@
+<template>
+  <div class="com-panel" :class="{ 'no-title': !hasTitle }">
+    <div v-if="hasTitle" class="panel-header">
+      <div class="panel-title">
+        <i v-if="hasIcon" class="panel-icon" :class="icon"></i>
+        {{ title }}
+      </div>
+      <div class="panel-tools">{{ subTitle }}</div>
+    </div>
+    <div class="panel-body">
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "com-panel",
+  componentName: "com-panel",
+  props: {
+    title: String,
+    icon: String,
+    subTitle: String,
+  },
+  computed: {
+    hasTitle() {
+      if (this.title) return true;
+      return false;
+    },
+    hasIcon() {
+      if (this.icon) return true;
+      return false;
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.com-panel {
+  border-left: 0.185vh solid rgba(255, 255, 255, 50%);
+
+  &:before {
+    content: " ";
+    width: 0.37vh;
+    height: 0.37vh;
+    float: left;
+    background: #fff;
+    margin: 0.185vh 0.556vh 0vh 0.185vh;
+  }
+
+  &.no-title {
+    border-left: 0vh;
+  }
+
+  &.no-title::before {
+    display: none;
+  }
+
+  .panel-header {
+    display: flex;
+    font-size: @fontsize;
+    padding-left: 1.4815vh;
+    background: rgba(255, 255, 255, 10%);
+    line-height: 2.963vh;
+    margin-bottom: 1.481vh;
+
+    .panel-title {
+      color: rgba(255, 255, 255, 0.8);
+      flex: 1 1 auto;
+      .panel-icon {
+        margin-right: 0.741vh;
+      }
+    }
+
+    .panel-tools {
+      flex: 0 0 auto;
+      color: #fff;
+      opacity: 0.3;
+      padding: 0 0.741vh;
+      font-size: @fontsize-s;
+      letter-spacing: 0.093vh;
+    }
+  }
+
+  .panel-body {
+    padding-left: 1.111vh;
+    color: rgba(255, 255, 255, 0.8);
+  }
+
+  &.no-title .panel-body {
+    padding-left: 0vh;
+  }
+}
+</style>

+ 73 - 0
src/components/panel/panel-sand-toolbar.vue

@@ -0,0 +1,73 @@
+<template>
+    <div class="com-panel-sand">
+        <div class="com-panel-sand-header font-sm white">
+            {{ title }}<div class="com-panel-sand-sub-title"><slot name="tools"></slot></div>
+        </div>
+        <div class="com-panel-body">
+            <slot></slot>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    name: "com-panel-sand-toolbar",
+    componentName: "com-panel-sand-toolbar",
+    props: {
+        // 标题
+        title: {
+            type: String,
+            default: "",
+        },
+    },
+};
+</script>
+<style lang="less">
+.com-panel-sand {
+    background: #1a1f2fCC;
+    padding: 0 1.481vh 1.481vh 1.481vh;
+    border-top: 1px solid #15a952;
+    position: relative;
+
+    &::after {
+        content: "";
+        position: absolute;
+        width: 5px;
+        height: 5px;
+        background: #15a952;
+        right: -2.5px;
+        top: -2.5px;
+    }
+
+    .com-panel-sand-header {
+        text-align: center;
+        position: relative;
+        padding: 0.833vh 0;
+        border-bottom: 1px solid #15a95266;
+
+        &::after,
+        &::before {
+            content: "";
+            position: absolute;
+            bottom: -1px;
+            width: 15px;
+            height: 1px;
+            background: #15a952;
+        }
+
+        &::after {
+            left: 0;
+        }
+
+        &::before {
+            right: 0;
+        }
+
+        .com-panel-sand-sub-title {
+            position: absolute;
+            right: 0;
+            top: 0.833vh;
+        }
+    }
+}
+</style>

+ 78 - 0
src/components/panel/panel-sand.vue

@@ -0,0 +1,78 @@
+<template>
+    <div class="com-panel-sand">
+        <div class="com-panel-sand-header font-sm white">
+            {{ title }}<span class="com-panel-sand-sub-title font-sm gray">{{ subTitle }}</span>
+        </div>
+        <div class="com-panel-body">
+            <slot></slot>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    name: "com-panel-sand",
+    componentName: "com-panel-sand",
+    props: {
+        // 标题
+        title: {
+            type: String,
+            default: "",
+        },
+        // 副标题
+        subTitle: {
+            type: String,
+            default: "",
+        },
+    },
+};
+</script>
+<style lang="less">
+.com-panel-sand {
+    background: #1a1f2fCC;
+    padding: 0 1.481vh 1.481vh 1.481vh;
+    border-top: 1px solid #15a952;
+    position: relative;
+
+    &::after {
+        content: "";
+        position: absolute;
+        width: 5px;
+        height: 5px;
+        background: #15a952;
+        right: -2.5px;
+        top: -2.5px;
+    }
+
+    .com-panel-sand-header {
+        text-align: center;
+        position: relative;
+        padding: 0.833vh 0;
+        border-bottom: 1px solid #15a95266;
+
+        &::after,
+        &::before {
+            content: "";
+            position: absolute;
+            bottom: -1px;
+            width: 15px;
+            height: 1px;
+            background: #15a952;
+        }
+
+        &::after {
+            left: 0;
+        }
+
+        &::before {
+            right: 0;
+        }
+
+        .com-panel-sand-sub-title {
+            position: absolute;
+            right: 0;
+            top: 0.833vh;
+        }
+    }
+}
+</style>

+ 112 - 0
src/components/panel/panel.vue

@@ -0,0 +1,112 @@
+<template>
+  <div class="com-panel" :class="{ 'no-title': !hasTitle, line: showLine }">
+    <div v-if="hasTitle" class="panel-header">
+      <div class="panel-title">
+        <i v-if="hasIcon" class="panel-icon" :class="icon"></i>
+        {{ title }}
+      </div>
+      <div class="panel-tools">{{ subTitle }}</div>
+    </div>
+    <div class="panel-body" :class="{ blur: bgBlur }">
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "com-panel",
+  componentName: "com-panel",
+  props: {
+    // 标题
+    title: String,
+    // 图标
+    icon: String,
+    // 副标题
+    subTitle: String,
+    showLine: {
+      type: Boolean,
+      default: true,
+    },
+    bgBlur: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  computed: {
+    // 是否存在标题
+    // 标题为空时 不显示标题框
+    hasTitle() {
+      if (this.title) return true;
+      return false;
+    },
+    // 是否存在图标
+    hasIcon() {
+      if (this.icon) return true;
+      return false;
+    },
+  },
+};
+</script>
+<style lang="less">
+.com-panel {
+  &.line {
+    border-left: 1px solid @gray;
+  }
+
+  &.line:before {
+    content: " ";
+    width: 3px;
+    height: 3px;
+    float: left;
+    background: #c9c9c9;
+    margin: 0.185vh 0.556vh 0vh 0.185vh;
+  }
+
+  &.no-title {
+    border-left: 0vh;
+  }
+
+  &.no-title::before {
+    display: none;
+  }
+
+  .panel-header {
+    display: flex;
+    font-size: 14px;
+    padding-left: 1.185vh;
+    background: rgba(255, 255, 255, 10%);
+    line-height: 27px;
+    margin-bottom: 0.7407vh;
+    height: 27px;
+
+    .panel-title {
+      color: fade(#fff, 75);
+      flex: 1 1 auto;
+      .panel-icon {
+        margin-right: 0.741vh;
+      }
+    }
+
+    .panel-tools {
+      flex: 0 0 auto;
+      color: #ffffff4d;
+      padding: 0 0.741vh;
+      font-size: 12px;
+      letter-spacing: 0.093vh;
+    }
+  }
+
+  .panel-body {
+    position: relative;
+  }
+
+  &.line .panel-body {
+    padding-left: 1.185vh;
+  }
+
+  &.no-title .panel-body {
+    padding-left: 0vh;
+  }
+}
+</style>

+ 139 - 0
src/components/panel/panel2.vue

@@ -0,0 +1,139 @@
+<template>
+  <div class="com-panel2" :class="(hasTitle ? '' : 'no-title') + ' ' + color">
+    <div v-if="hasTitle" class="panel-header2">
+      <div class="panel-title2">
+        <i v-if="hasIcon" class="panel-icon2" :class="icon"></i>
+        {{ title }}
+      </div>
+      <div class="panel-tools2">{{ subTitle }}</div>
+    </div>
+    <div class="panel-body2">
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "ComPanel",
+  componentName: "ComPanel",
+  props: {
+    title: String,
+    icon: String,
+    subTitle: String,
+    color: String,
+  },
+  computed: {
+    hasTitle() {
+      if (this.title) return true;
+      return false;
+    },
+    hasIcon() {
+      if (this.icon) return true;
+      return false;
+    },
+  },
+};
+</script>
+<style lang="less">
+.com-panel2 {
+  border-left: 0.185vh solid rgba(255, 255, 255, 50%);
+  padding-left: 1.185vh;
+  position: relative;
+
+  &:before,
+  &:after {
+    content: " ";
+    width: 0.37vh;
+    height: 0.37vh;
+    background: @write;
+    position: absolute;
+    left: 0.185vh;
+  }
+
+  &:before {
+    top: 0.185vh;
+  }
+
+  &:after {
+    bottom: 0.185vh;
+  }
+
+  &.no-title {
+    border-left: 0vh;
+  }
+
+  &.no-title::before {
+    display: none;
+  }
+
+  &.green {
+    .panel-header2 {
+      &::after {
+        background-image: @greenLinearRight;
+        width: 10%;
+      }
+      .panel-title2 {
+        .panel-icon2 {
+          color: @green;
+        }
+      }
+    }
+  }
+
+  &.red {
+    .panel-header2 {
+      &::after {
+        background-image: @redLinearRight;
+        width: 10%;
+      }
+      .panel-title2 {
+        .panel-icon2 {
+          color: @red;
+        }
+      }
+    }
+  }
+
+  .panel-header2 {
+    display: flex;
+    font-size: @fontsize;
+    padding-left: 1.185vh;
+    background: fade(@gray, 20);
+    line-height: 2.963vh;
+    margin-bottom: 1.111vh;
+    position: relative;
+
+    &::after {
+      content: "";
+      position: absolute;
+      left: 0;
+      top: 0;
+      width: 40vh;
+      height: 100%;
+    }
+
+    .panel-title2 {
+      color: @write;
+
+      .panel-icon2 {
+        margin-right: 0.741vh;
+      }
+    }
+
+    .panel-tools2 {
+      color: #fff;
+      opacity: 0.3;
+      padding: 0 0.741vh;
+    }
+  }
+
+  .panel-body2 {
+    color: rgba(255, 255, 255, 0.8);
+  }
+
+  &.no-title .panel-body2 {
+    padding-left: 0vh;
+  }
+}
+</style>

+ 52 - 0
src/components/panel/panel3.vue

@@ -0,0 +1,52 @@
+<template>
+  <div class="com-panel-3">
+    <span class="dot top-left"></span>
+    <span class="dot bottom-left"></span>
+    <span class="dot top-rignt"></span>
+    <span class="dot bottom-right"></span>
+    <slot></slot>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "com-panel-3",
+  componentName: "com-panel-3",
+};
+</script>
+<style lang="less" scoped>
+.com-panel-3 {
+  position: relative;
+  background: rgba(255, 255, 255, 0.1);
+  padding: 1.4815vh;
+  display: inline-block;
+  border: 0.093vh solid #536268;
+
+  .dot {
+    position: absolute;
+    width: 0.370vh;
+    height: 0.370vh;
+    background: #fff;
+
+    &.top-left {
+      top: 0.556vh;
+      left: 0.556vh;
+    }
+
+    &.bottom-left {
+      bottom: 0.556vh;
+      left: 0.556vh;
+    }
+
+    &.top-rignt {
+      top: 0.556vh;
+      right: 0.556vh;
+    }
+
+    &.bottom-right {
+      bottom: 0.556vh;
+      right: 0.556vh;
+    }
+  }
+}
+</style>

+ 46 - 0
src/components/panel/toolbar-panel.vue

@@ -0,0 +1,46 @@
+<template>
+  <div class="com-panel" :class="{ 'no-title': !hasTitle, line: showLine }">
+    <div v-if="hasTitle" class="panel-header">
+      <div class="panel-title">
+        <i v-if="hasIcon" class="panel-icon" :class="icon"></i>
+        {{ title }}
+      </div>
+      <div class="panel-tools">
+        <slot name="tools"></slot>
+      </div>
+    </div>
+    <div class="panel-body">
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<script>
+// 副标题可嵌入html的panel
+export default {
+  name: "toolbar-panel",
+  componentName: "toolbar-panel",
+  props: {
+    // 标题
+    title: String,
+    // 图标
+    icon: String,
+    showLine: {
+      type: Boolean,
+      default: true,
+    },
+  },
+  computed: {
+    hasTitle() {
+      if (this.title) return true;
+      return false;
+    },
+    hasIcon() {
+      if (this.icon) return true;
+      return false;
+    },
+  },
+};
+</script>
+
+<style lang="less"></style>

+ 2 - 1
src/components/problem/ProblemArea.vue

@@ -34,6 +34,7 @@
 </script>
 <style scoped>
   .problem {
-    height: 100%;
+    height: 97%;
+    background-color: #000000;
   }
 </style>

+ 407 - 0
src/components/search/action.vue

@@ -0,0 +1,407 @@
+<template>
+  <el-dialog
+    width="70%"
+    @open="opened"
+    @closed="closed"
+    :fullscreen="true"
+    :show-close="true"
+    class="dialogs"
+  >
+    <template #title>
+      <div class="showTitles currentShowTitles">
+        <div class="titles">动作查询</div>
+      </div>
+    </template>
+    <div class="body">
+      <div class="bodyDetial">
+        <!-- <div style="width: 50%;height:200px;background-color:red;"></div>
+      <div style="width: 50%;height:200px;background-color:yellow;"></div> -->
+        <div class="left-item">
+          <el-scrollbar>
+            <el-input placeholder="输入关键字进行过滤" v-model="filterText">
+            </el-input>
+            <el-tree
+              class="filter-tree"
+              :data="showData"
+              :props="defaultProps"
+              :filter-node-method="filterNode"
+              node-key="id"
+              :default-expanded-keys="[0]"
+              ref="tree"
+              @node-click="handleChange"
+            >
+            </el-tree>
+          </el-scrollbar>
+        </div>
+        <div class="right-item">
+          <div class="dateBar">
+            <el-date-picker
+              class="pickers"
+              @change="changes"
+              v-model="timeValue"
+              type="datetimerange"
+              range-separator="至"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+            >
+            </el-date-picker>
+            <div class="buttons" @click="getControlRecord()">查询</div>
+          </div>
+          <el-scrollbar style="height: 94%">
+            <div class="tables">
+              <el-table
+                :data="recordData"
+                class="table"
+                style="width: 100%"
+                height="81vh"
+                :header-cell-style="{
+                  background: 'rgb(30,30,30)',
+                  color: 'rgb(220,220,220)',
+                  padding: '4px',
+                  fontSize: '14px',
+                  'border-bottom': 'solid 1px rgba(77, 77, 77, 1)',
+                }"
+                :cell-style="{
+                  height: '40px',
+                  background: 'rgb(30,30,30)',
+                  color: 'rgb(220,220,220)',
+                  padding: '3px',
+                  fontSize: '12px',
+                  'border-bottom': '1px solid #000000',
+                }"
+              >
+                <el-table-column
+                  prop="time"
+                  label="日期"
+                  width="120"
+                  align="center"
+                >
+                </el-table-column>
+                <el-table-column
+                  prop="showName"
+                  label="风机号"
+                  width="120"
+                  align="center"
+                >
+                </el-table-column>
+                <el-table-column
+                  prop="controls"
+                  label="控制命令"
+                  width="100"
+                  align="center"
+                >
+                </el-table-column>
+                <el-table-column prop="result" label="操作结果" align="center">
+                </el-table-column>
+                <el-table-column
+                  prop="userName"
+                  label="操作人"
+                  width="160"
+                  align="center"
+                >
+                </el-table-column>
+              </el-table>
+            </div>
+          </el-scrollbar>
+          <div class="paginations">
+            <el-pagination
+              :hide-on-single-page="true"
+              :page-size="currentPage"
+              background
+              layout="prev, pager, next"
+              :total="total"
+              @current-change="handleCurrentChange"
+            >
+            </el-pagination>
+          </div>
+        </div>
+      </div>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import dayjs from "dayjs";
+import api from "api/index";
+export default {
+  props: {},
+  updated() {
+    if (this.timeValue.length === 0) {
+      let date = new Date();
+      this.timeValue[0] = date.getTime() - 28800000;
+      this.timeValue[1] = date.getTime() + 3600000;
+    }
+  },
+  mounted() {},
+  data() {
+    return {
+      currentPage: 10,
+      filterText: "",
+      pageIndex: 1,
+      station: [],
+      datas: {},
+      chooseStation: {},
+      timeValue: [],
+      showData: [
+        {
+          id: 0,
+          windturbineId: "全部",
+          stationId: "",
+          children: [],
+        },
+      ],
+      defaultProps: {
+        children: "children",
+        label: "windturbineId",
+      },
+      recordData: [],
+      total: "",
+      controlErorCodes: [
+        "控制成功",
+        "控制命令发送失败",
+        "无效的控制地址",
+        "被控设备异常",
+        "无效的控制功能",
+        "网络连接错误,检查场站通信",
+        "控制结果读取超时",
+        "未知错误",
+        "控制命令错误",
+        "收到无法识别数据",
+        "未读取到数据包",
+        "未知错误",
+        "风机操作过频繁",
+        "风机被挂牌",
+        "风机操作与风机状态不符",
+        "需要登录",
+      ],
+    };
+  },
+  methods: {
+    // getWindturbineFdc() {
+    //   api.getWindturbineFdc().then((res) => {
+    //     this.station = res.data;
+    //     this.getControlRecord();
+    //   });
+    // },
+    dataDeal() {
+      let stationList = this.$store.state.stationList;
+      this.showData[0].children = [];
+      stationList.forEach((item, index) => {
+        let obj = {};
+        obj.id = index + 1;
+        obj.windturbineId = item.address;
+        obj.stationId = item.code;
+        obj.children = [];
+        this.showData[0].children.push(obj);
+      });
+      this.datas = this.$store.state.windturbinelist
+        ? this.$store.state.windturbinelist
+        : {};
+      let arr = Object.keys(this.datas).sort();
+      for (let id of arr) {
+        let item = this.datas[id];
+        this.showData[0].children
+          .filter((val) => val.stationId === item.stationId)[0]
+          .children.push(item);
+      }
+    },
+    handleChange(value) {
+      this.chooseStation = value;
+      this.pageIndex = 1;
+      this.getControlRecord(value);
+    },
+    closed() {
+      this.pageIndex = 1;
+      this.chooseStation = {};
+      this.showData = [
+        {
+          id: 0,
+          windturbineId: "全部",
+          stationId: "",
+          children: [],
+        },
+      ];
+      let stationList = this.$store.state.stationList;
+      stationList.forEach((item, index) => {
+        let obj = {};
+        obj.id = index + 1;
+        obj.windturbineId = item.address;
+        obj.stationId = item.code;
+        obj.children = [];
+        this.showData[0].children.push(obj);
+      });
+
+      this.$emit("closed");
+    },
+    filterNode(value, data) {
+      if (!value) return true;
+      return data.windturbineId.indexOf(value) !== -1;
+    },
+    handleCurrentChange(val) {
+      this.pageIndex = val;
+      this.getControlRecord();
+    },
+    opened() {
+      let date = new Date();
+      this.timeValue[0] = date.getTime() - 28800000;
+      this.timeValue[1] = date.getTime() + 3600000;
+      this.dataDeal();
+      this.getControlRecord();
+    },
+    getControlRecord() {
+      api
+        .controlRecord({
+          stationId: this.chooseStation.stationId
+            ? this.chooseStation.stationId
+            : "",
+          userName: "",
+          windturbineId: this.chooseStation.id
+            ? ""
+            : this.chooseStation.stationId
+            ? this.chooseStation.windturbineId
+            : "",
+          startTime: dayjs(this.timeValue[0]).format("YYYY/MM/DD HH:mm:ss"),
+          endTime: dayjs(this.timeValue[1]).format("YYYY/MM/DD HH:mm:ss"),
+          pageSize: this.currentPage,
+          pageIndex: this.pageIndex,
+        })
+        .then((res) => {
+          if (res) {
+            let types = {
+              Start: "启动",
+              Stop: "停止",
+              Reset: "复位",
+              Maintain: "维护",
+              UnMaintain: "取消维护",
+              Lock: "挂牌",
+              UnLock: "取消挂牌",
+            };
+            res.data.dataList.forEach((item) => {
+              item.time = dayjs(item.time).format("MM-DD HH:mm:ss");
+              item.result = this.controlErorCodes[item.errorCode];
+              item.controls = types[item.controlType];
+              item.showName = item.windturbineId;
+            });
+            this.total = res.data.total;
+            this.recordData = res.data.dataList;
+          }
+        });
+    },
+  },
+  watch: {
+    filterText(val) {
+      this.$refs.tree.filter(val);
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.body {
+  background-color: #000000;
+  height: 90vh;
+  width: 102%;
+  margin-left: -1%;
+  margin-top: -40px;
+}
+.searchTitle {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  align-items: center;
+}
+.bodyDetial {
+  display: flex;
+  flex-direction: row;
+  margin-left: 3vw;
+  padding-top: 10px;
+  color: #ffffff;
+  height: 98%;
+}
+
+.left-item {
+  width: 20%;
+  height: 100%;
+  background-color: rgba(77, 77, 77, 1);
+  border-right: 2px solid #000000;
+}
+
+.right-item {
+  width: 80%;
+  height: 100%;
+  background-color: rgba(77, 77, 77, 1);
+}
+
+.el-tree {
+  color: #ffffff !important;
+  background-color: rgba(77, 77, 77, 1) !important;
+}
+
+.el-tree-node:focus > .el-tree-node__content {
+  background-color: #000000 !important;
+}
+
+.el-tree-node__content:hover {
+  background-color: #000000 !important;
+}
+
+.dateBar {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-between;
+  margin-left: 20px;
+}
+
+.pickers {
+  margin-left: 20px;
+}
+
+.tables {
+  margin-top: 20px;
+  width: 95%;
+  margin-left: 3%;
+}
+
+.table {
+  background-color: rgba(77, 77, 77, 1) !important;
+}
+
+.el-table td,
+.el-table th.is-leaf {
+  border-bottom: 1px solid rgba(77, 77, 77, 1) !important;
+}
+
+.el-table__header {
+  width: 100% !important;
+}
+
+.el-table__body-wrapper {
+  background-color: rgba(77, 77, 77, 1) !important;
+}
+
+.el-table::before {
+  width: 0;
+}
+
+tr {
+  line-height: 1.5;
+  background: #1e1e1e;
+  margin-bottom: 2px;
+  border-radius: 5px;
+}
+
+.table-main {
+  font-size: 14px;
+  width: 600px;
+  text-align: center;
+  background: #000000;
+  margin: 5px;
+  border-collapse: separate;
+  border-spacing: 0px 5px;
+}
+
+.paginations {
+  display: flex;
+  flex-direction: row-reverse;
+}
+</style>

+ 348 - 0
src/components/search/fault.vue

@@ -0,0 +1,348 @@
+<template>
+  <el-dialog
+    width="70%"
+    @open="opened"
+    @closed="closed"
+    :fullscreen="true"
+    :show-close="true"
+    class="dialogs"
+  >
+    <template #title>
+      <div class="showTitles currentShowTitles">
+        <div class="titles">报警/故障查询</div>
+      </div>
+    </template>
+    <div class="body">
+      <div class="searchTitle">
+        <div class="search">
+          <div class="date">日期:</div>
+          <el-date-picker
+            class="pickers"
+            @change="changes"
+            v-model="timeValue"
+            type="datetimerange"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+          >
+          </el-date-picker>
+        </div>
+        <div class="search">
+          <div class="date">风场:</div>
+          <el-select
+            @change="listedChange(selectValue)"
+            class="inputs"
+            v-model="selectValue"
+            placeholder="请选择"
+          >
+            <el-option
+              v-for="item in stationList"
+              :key="item.id"
+              :label="item.address"
+              :value="item.id"
+            >
+            </el-option>
+          </el-select>
+        </div>
+        <div class="search">
+          <div class="date">风机名称:</div>
+          <el-select class="inputs" v-model="selectWind" placeholder="请选择">
+            <el-option
+              v-for="item in windturbinelist"
+              :key="item.code"
+              :label="item.code"
+              :value="item.code"
+            >
+            </el-option>
+          </el-select>
+        </div>
+        <div class="search">
+          <div class="date">关键字:</div>
+          <el-input
+            class="inputs"
+            placeholder="请输入"
+            v-model="inputVlaues"
+          ></el-input>
+        </div>
+
+        <div class="buttons" @click="getControlRecord()">查询</div>
+      </div>
+      <!-- <div class="lable">
+        <div class="lable-item" v-for="(item, index) in lableList" :key="index">
+          <div>{{item.name}}:</div>
+          <div style="margin-left: 10px;color:red;">{{item.value}}</div>
+        </div>
+      </div> -->
+      <div class="tables">
+        <el-table
+          :data="warningList"
+          class="table"
+          style="width: 100%"
+          height="82vh"
+          :header-cell-style="{
+            background: 'rgb(30,30,30)',
+            color: 'rgb(220,220,220)',
+            padding: '4px',
+            fontSize: '14px',
+            'border-bottom': 'solid 1px rgba(77, 77, 77, 1)',
+          }"
+          :cell-style="{
+            height: '40px',
+            background: 'rgb(30,30,30)',
+            color: 'rgb(220,220,220)',
+            padding: '3px',
+            fontSize: '12px',
+            'border-bottom': '1px solid #000000',
+          }"
+        >
+          <el-table-column
+            prop="alertTime"
+            label="发生时间"
+            width="150"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="stationName"
+            label="风场名称"
+            width="120"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="windturbineId"
+            label="风机名称"
+            width="120"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="rank"
+            label="报警等级"
+            width="100"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column label="状态" width="120" align="center">
+                <template #default="scope">
+                  <span>
+                    {{ scope.row.messageType  === 1 ? "未解除" : "已解除" }}
+                  </span>
+                </template>
+              </el-table-column>
+          <el-table-column
+            prop="snapId"
+            label="故障编号"
+            width="100"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column prop="alertText" label="故障信息" align="center">
+          </el-table-column>
+        </el-table>
+      </div>
+      <div class="paginations">
+        <el-pagination
+          :hide-on-single-page="true"
+          :page-size="currentPage"
+          background
+          layout="prev, pager, next"
+          :total="total"
+          @current-change="handleCurrentChange"
+        >
+        </el-pagination>
+      </div>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import dayjs from "dayjs";
+import api from "api/index";
+export default {
+  data() {
+    return {
+      current: 0,
+      pagenum: 1,
+      timeValue: [],
+      selectValue: "",
+      inputVlaues: "",
+      stationList: [],
+      selectWind: "",
+      windturbinelist: [],
+      warningList: [],
+      currentPage: 10,
+      lableList: [
+        {
+          name: "偏航系统故障",
+          value: "6996",
+        },
+        {
+          name: "偏航系统故障",
+          value: "6996",
+        },
+        {
+          name: "偏航系统故障",
+          value: "6996",
+        },
+        {
+          name: "偏航系统故障",
+          value: "6996",
+        },
+        {
+          name: "偏航系统故障",
+          value: "6996",
+        },
+        {
+          name: "偏航系统故障",
+          value: "6996",
+        },
+        {
+          name: "偏航系统故障",
+          value: "6996",
+        },
+        {
+          name: "偏航系统故障",
+          value: "6996",
+        },
+        {
+          name: "偏航系统故障",
+          value: "6996",
+        },
+        {
+          name: "偏航系统故障",
+          value: "6996",
+        },
+        {
+          name: "偏航系统故障",
+          value: "6996",
+        },
+        {
+          name: "偏航系统故障",
+          value: "6996",
+        },
+      ],
+    };
+  },
+  methods: {
+    ChangeBar(values) {
+      this.current = values;
+    },
+    opened() {
+      let date = new Date();
+      this.timeValue[0] = date.getTime() - 28800000;
+      this.timeValue[1] = date.getTime() + 3600000;
+      let stationList = this.$store.state.stationList;
+      this.selectValue = stationList[0].id;
+      this.stationList = stationList;
+      this.listedChange(this.selectValue);
+      this.getWarning();
+    },
+    closed() {
+      this.pagenum = 1;
+    },
+    getWarning() {
+      api
+        .getWindturbineWarning({
+          pagesize: this.currentPage,
+          pagenum: this.pagenum,
+          stationid: 'BY_FDC',
+          windturbineid: 'BY_001',
+          starttime: dayjs(this.timeValue[0]).format("YYYY-MM-DD HH:mm:ss"),
+          endtime: dayjs(this.timeValue[1]).format("YYYY-MM-DD HH:mm:ss"),
+          keyword: this.inputVlaues,
+        })
+        .then((msg) => {
+          if (msg.data) {
+            msg.data.records.forEach((item) => {
+              item.alertTime = dayjs(item.alertTime).format("MM-DD HH:mm:ss");
+            });
+            this.warningList = msg.data.records;
+          }
+        });
+    },
+    handleCurrentChange(val) {
+      this.pagenum = val;
+      this.getWarning();
+    },
+    listedChange(value) {
+      this.windturbinelist = [];
+      let windturbinelist = this.$store.state.windturbinelist;
+      let arr = Object.keys(windturbinelist).sort();
+      let windturbine = [];
+      for (const key of arr) {
+        let wind = windturbinelist[key];
+        if (wind.stationId === value) {
+          windturbine.push(wind);
+        }
+      }
+      this.selectWind = windturbine[0]?.code || "";
+      this.windturbinelist = windturbine;
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.body {
+  background-color: #000000;
+  height: 89vh;
+  width: 102%;
+  margin-left: -1%;
+  margin-top: -40px;
+}
+.searchTitle {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin-left: 3vw;
+  padding-top: 10px;
+  color: #ffffff;
+}
+.search {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin-right: 50px;
+}
+.date {
+  margin-right: 10px;
+  font-size: 16px;
+}
+.tables {
+  margin-left: 3vw;
+  padding-top: 10px;
+}
+.lable {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  flex-wrap: wrap;
+  width: 100%;
+  margin-left: 75px;
+  padding-top: 10px;
+}
+.lable-item {
+  font-size: 16px;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  width: 16%;
+  color: #ffffff;
+  margin-bottom: 10px;
+}
+.el-table {
+  position: static;
+  background-color: #141414;
+}
+.inputs {
+  border: none;
+  width: 174px !important;
+  background-color: #292929;
+  height: 40px;
+  color: #ffffff;
+}
+.paginations {
+  display: flex;
+  flex-direction: row-reverse;
+}
+</style>

+ 519 - 0
src/components/search/multiple-y-line-chart-normal.vue

@@ -0,0 +1,519 @@
+<template>
+  <div class="chart" :id="id"></div>
+</template>
+
+<script>
+import util from "@/utils/util.js";
+import partten from "@/utils/partten.js";
+import * as echarts from "echarts";
+
+export default {
+  name: "multiple-y-line-chart-normal",
+  componentName: "multiple-y-line-chart-normal",
+  props: {
+    width: {
+      type: String,
+      default: "100%",
+    },
+    height: {
+      type: String,
+      default: "13.889vh",
+    },
+    // 数据
+    list: {
+      type: Array,
+      default: () => [
+        {
+          title: "机舱震动x方向",
+          yAxisIndex: 0,
+          value: [
+            {
+              text: "-0.003",
+              value: -0.003,
+            },
+            {
+              text: "-0.002",
+              value: -0.002,
+            },
+            {
+              text: "-0.003",
+              value: -0.006,
+            },
+            {
+              text: "-0.003",
+              value: -0.003,
+            },
+            {
+              text: "-0.002",
+              value: -0.002,
+            },
+            {
+              text: "-0.003",
+              value: -0.006,
+            },
+            {
+              text: "-0.003",
+              value: -0.003,
+            },
+            {
+              text: "-0.002",
+              value: -0.002,
+            },
+            {
+              text: "-0.003",
+              value: -0.006,
+            },
+          ],
+        },
+        {
+          title: "机舱震动y方向",
+          yAxisIndex: 1,
+          value: [
+            {
+              text: "-0.01",
+              value: -0.01,
+            },
+            {
+              text: "-0.005",
+              value: -0.005,
+            },
+            {
+              text: "-0.008",
+              value: -0.008,
+            },
+            {
+              text: "-0.01",
+              value: -0.01,
+            },
+            {
+              text: "-0.005",
+              value: -0.005,
+            },
+            {
+              text: "-0.008",
+              value: -0.008,
+            },
+            {
+              text: "-0.01",
+              value: -0.01,
+            },
+            {
+              text: "-0.005",
+              value: -0.005,
+            },
+            {
+              text: "-0.008",
+              value: -0.008,
+            },
+          ],
+        },
+        {
+          title: "机舱震动最大偏移值",
+          yAxisIndex: 2,
+          value: [
+            {
+              text: "1",
+              value: 1,
+            },
+            {
+              text: "0.05",
+              value: 0.05,
+            },
+            {
+              text: "0.5",
+              value: 0.5,
+            },
+            {
+              text: "1",
+              value: 1,
+            },
+            {
+              text: "0.05",
+              value: 0.05,
+            },
+            {
+              text: "0.5",
+              value: 0.5,
+            },
+            {
+              text: "1",
+              value: 1,
+            },
+            {
+              text: "0.05",
+              value: 0.05,
+            },
+            {
+              text: "0.5",
+              value: 0.5,
+            },
+          ],
+        },
+        {
+          title: "风速1",
+          yAxisIndex: 3,
+          value: [
+            {
+              text: "1",
+              value: 1,
+            },
+            {
+              text: "5",
+              value: 5,
+            },
+            {
+              text: "3",
+              value: 1,
+            },
+            {
+              text: "1",
+              value: 1,
+            },
+            {
+              text: "5",
+              value: 5,
+            },
+            {
+              text: "3",
+              value: 1,
+            },
+            {
+              text: "1",
+              value: 1,
+            },
+            {
+              text: "5",
+              value: 5,
+            },
+            {
+              text: "3",
+              value: 1,
+            },
+          ],
+        },
+        {
+          title: "风速2",
+          yAxisIndex: 4,
+          value: [
+            {
+              text: "1",
+              value: 1,
+            },
+            {
+              text: "2",
+              value: 2,
+            },
+            {
+              text: "3",
+              value: 1,
+            },
+            {
+              text: "1",
+              value: 1,
+            },
+            {
+              text: "2",
+              value: 2,
+            },
+            {
+              text: "3",
+              value: 1,
+            },
+            {
+              text: "1",
+              value: 1,
+            },
+            {
+              text: "2",
+              value: 2,
+            },
+            {
+              text: "3",
+              value: 1,
+            },
+          ],
+        },
+      ],
+    },
+    showLegend: {
+      type: Boolean,
+      default: false,
+    },
+    default: {
+      type: Boolean,
+      default: false,
+    },
+    // 轴
+    yAxises: {
+      type: Array,
+      default: () => [
+        {
+          name: "机舱震动x方向",
+          min: -0.01,
+          max: 0,
+          unit: "",
+          position: "left",
+        },
+        {
+          name: "机舱震动y方向",
+          min: -0.01,
+          max: 0,
+          unit: "",
+          position: "right",
+        },
+        {
+          name: "机舱震动最大偏移值",
+          min: 0,
+          max: 1,
+          unit: "",
+          position: "left",
+        },
+        {
+          name: "风速1",
+          min: 0,
+          max: 10,
+          unit: "",
+          position: "right",
+        },
+        {
+          name: "风速2",
+          min: 0,
+          max: 10,
+          unit: "",
+          position: "left",
+        },
+      ],
+    },
+  },
+  data() {
+    return {
+      id: "",
+      chart: null,
+      color: ["#1DA0D7","#05BB4C","#323E6F", "#EDB32F", "#DB5520"],
+    };
+  },
+  computed: {
+    legend() {
+      return this.list.map((t) => {
+        return t.title;
+      });
+    },
+    xdata() {
+      if (this.list.length > 1) {
+        // this.list[1].value.forEach((lEle, lIndex) => {
+        //   console.log(
+        //     this.list[1].value.indexOf(
+        //       this.list[1].value[lIndex].text == "00:00"
+        //     )
+        //   );
+        // });
+        return this.list[1]?.value.map((t) => {
+          return t.text || new Date(t.ts).formatDate("hh:mm:ss");
+        });
+      } else if (this.list.length == 1) {
+        return this.list[0]?.value.map((t) => {
+          return t.text || new Date(t.ts).formatDate("hh:mm:ss");
+        });
+      }
+    },
+    yAxis() {
+      let result = [];
+      let p = { left: 0, right: 0 };
+      this.yAxises.forEach((item, index) => {
+        result.push({
+          type: "value",
+          name: `${item.name}${item.unit}`,
+          nameLocation: p[item.position] % 2 == 0 ? "end" : "start",
+          nameGap: 10,
+          min: item.min,
+          max: item.max,
+          position: item.position,
+          offset: p[item.position] * 50,
+          axisLabel: {
+            formatter: "{value}",
+            fontSize: 12,
+          },
+          //分格线
+          splitLine: {
+            lineStyle: {
+              color: this.$store.state.themeName === "dark" ? partten.getColor("gray") : partten.getColor("black"),
+              type: "dashed",
+            },
+          },
+          axisLine: {
+            show: true,
+          },
+          axisTick: {
+            show: true,
+          },
+        });
+        p[item.position]++;
+      });
+      return result;
+    },
+    series() {
+      let result = [];
+      this.list.forEach((value, index) => {
+        result.push({
+          name: value.title,
+          type: "line",
+          smooth: true,
+          zlevel: index,
+          lineStyle: {
+            normal: {
+              color: this.color[index],
+              width: 1,
+            },
+          },
+          showSymbol: false,
+          yAxisIndex: value.yAxisIndex,
+          data: value.value.map((t) => {
+            if (t.value || t.value === 0) {
+              return t.value;
+            } else if (t.doubleValue || t.doubleValue === 0) {
+              return t.doubleValue;
+            } else {
+              return t.longValue;
+            }
+          }),
+        });
+      });
+
+      return result;
+    },
+  },
+  methods: {
+    resize() {},
+    initChart() {
+		
+      const chart = echarts.init(this.$el);
+	
+      let option = this.option();
+      chart.clear();
+
+      chart.setOption(option);
+      if (this.default) {
+        chart.dispatchAction({
+          type: "showTip",
+          seriesIndex: 0, // 显示第几个series
+          dataIndex: this.list[0].value.length - 600, // 显示第几个数据
+        });
+      }
+
+      this.resize = function () {
+        chart.resize();
+      };
+
+      window.addEventListener("resize", this.resize);
+    },
+    option: function () {
+		let themeName = '';
+		this.$store.state.themeName === "dark" ? themeName = true : themeName = false;
+      return {
+        color: this.color,
+        tooltip: {
+          trigger: "axis",
+          triggerOn:this.default?"click":"mousemove",
+          alwaysShowContent:true,
+          backgroundColor: themeName ? "rgba(0,0,0,0.4)" : "rgba(255,255,255,0.5)",
+          borderColor: themeName ? partten.getColor("gray"): "#000",
+          textStyle: {
+            color: themeName ? "#fff" : "#000",
+            fontSize: 12,
+          },
+        },
+        legend: {
+          show: this.showLegend,
+          data: this.legend,
+          top: "top",
+          icon: "circle",
+          itemWidth: 6,
+          inactiveColor: themeName ? partten.getColor("gray"): "#000",
+          textStyle: {
+            color: themeName ? partten.getColor("grayl"): "#000",
+            fontSize: 12,
+          },
+        },
+        grid: {
+          top: 27,
+          left: 16,
+          right: 16,
+          bottom: 0,
+          containLabel: true,
+        },
+        xAxis: [
+          {
+            type: "category",
+            boundaryGap: false,
+            axisLabel: {
+              interval:
+                Number((this.xdata.length / 8).toFixed(0)) > 2
+                  ? Number((this.xdata.length / 8).toFixed(0))
+                  : 0,
+              showMinLabel: true,
+              showMaxLabel: true,
+              formatter: "{value}",
+              fontSize: 12,
+              textStyle: {
+                color: themeName ? partten.getColor("gray"): "#000",
+              },
+            },
+            data: this.xdata,
+          },
+        ],
+        yAxis: {
+          type: "value",
+          axisLabel: {
+            formatter: "{value}",
+            fontSize: 14,
+          },
+          axisLine: {
+            show: false,
+          },
+          splitLine: {
+            show: true,
+            lineStyle: {
+              color: "#606769",
+              type: "dashed",
+            },
+          },
+        },
+        // yAxis: this.yAxis,
+        series: this.series,
+      };
+    },
+    reload: function () {
+      const chart = echarts.getInstanceByDom(this.$el);
+      chart.clear();
+      let option = this.option();
+      chart.setOption(option);
+    },
+  },
+  created() {
+    this.id = "pie-chart-" + util.newGUID();
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.$el.style.width = this.width;
+      this.$el.style.height = this.height;
+      this.initChart();
+    });
+  },
+  beforeUpdate() {
+    this.$nextTick(() => {
+      this.initChart();
+    });
+  },
+  unmounted() {
+    window.removeEventListener("resize", this.resize);
+  },
+};
+</script>
+
+<style lang="less">
+.chart {
+  width: 100%;
+  height: 100%;
+  display: inline-block;
+}
+</style>

+ 56 - 0
src/components/search/status.vue

@@ -0,0 +1,56 @@
+<template>
+  <el-dialog
+    width="70%"
+    @open="opened"
+    @closed="closed"
+    :fullscreen="true"
+    :show-close="true"
+    class="dialogs"
+  >
+    <template #title>
+      <div class="showTitles currentShowTitles">
+        <div class="titles">状态时间查询</div>
+      </div>
+    </template>
+    <div class="body">
+      <div class="searchTitle">
+        <div class="search">
+
+        </div>
+      </div>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      current: 0,
+    };
+  },
+  methods: {
+    ChangeBar(values) {
+      this.current = values;
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.body {
+  background-color: #000000;
+  height: 90vh;
+  width: 102%;
+  margin-left: -1%;
+  margin-top: -40px;
+}
+.searchTitle {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  align-items: center;
+  margin-left: 3vw;
+  padding-top: 10px;
+  color: #ffffff;
+}
+</style>

+ 870 - 0
src/components/search/warning.vue

@@ -0,0 +1,870 @@
+<template>
+  <el-dialog
+    width="70%"
+    @open="opened"
+    @closed="closed"
+    :fullscreen="true"
+    :show-close="true"
+    class="dialogs"
+  >
+    <template #title>
+      <div class="showTitles currentShowTitles">
+        <div class="titles">预警查询</div>
+      </div>
+    </template>
+    <div class="body">
+      <div class="searchTitle">
+        <div class="search">
+          <div class="lable">风场:</div>
+          <div class="search-input">
+            <el-select
+              v-model="wpvalue"
+              clearable
+              placeholder="请选择"
+              popper-class="select"
+            >
+              <el-option
+                v-for="item in wpoptions"
+                :key="item.id"
+                :label="item.address"
+                :value="item.id"
+              >
+              </el-option>
+            </el-select>
+          </div>
+        </div>
+        <div class="search">
+          <div class="date">日期:</div>
+          <el-date-picker
+            class="pickers"
+            @change="changes"
+            v-model="timeValue"
+            type="datetimerange"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+          >
+          </el-date-picker>
+        </div>
+        <div class="search">
+          <div class="lable">规则:</div>
+          <el-cascader
+            style="width: 240px"
+            size="mini"
+            popper-class="search-select"
+            :options="cascaderOptions"
+            :props="cascaderProps"
+            v-model="cascaderSel"
+            collapse-tags
+            :clearable="true"
+          ></el-cascader>
+        </div>
+
+        <div class="buttons" @click="searchData()">搜索</div>
+        <div class="buttons" @click="searchTree()">筛选</div>
+        <div class="buttons" @click="fx()">分析</div>
+      </div>
+      <panel-3 class="table-panel">
+        <table-3 :data="tableData" :height="'82vh'">
+          <template v-for="(item, i) in column" :key="i" #[item]="scope">
+            <div class="bar" @click="showChart(scope)">
+              <div
+                class="bar-percent"
+                :style="{ width: scope?.data?.countStyle }"
+              ></div>
+              <span class="value">{{ scope?.data?.count }} 次数</span>
+            </div>
+
+            <div class="bar" @click="showChart(scope)">
+              <div
+                class="bar-percent"
+                :style="{ width: scope?.data?.timeStyle }"
+              ></div>
+              <span class="value">{{ scope?.data?.time }} 分钟</span>
+            </div>
+          </template>
+        </table-3>
+      </panel-3>
+    </div>
+    <el-dialog
+      :title="dialogTitle"
+      v-model="dialogVisible"
+      width="70%"
+      top="10vh"
+      custom-class="modal"
+      :close-on-click-modal="false"
+    >
+      <div class="model">
+        <div class="selects">
+          <el-select
+            @change="switchChange(selectValue)"
+            class="inputs"
+            v-model="selectValue"
+            placeholder="请选择"
+          >
+            <el-option
+              v-for="item in timeoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </div>
+        <div class="choose">
+          <!-- <div class="interval_on">等间隔</div> -->
+          <!-- <div class="original_on" @click="switchChange">原始数据</div> -->
+        </div>
+      </div>
+
+      <!-- <div class="searchForm">
+       <el-select
+        @change="searchTime(selectValue)"
+        class="inputs"
+        v-model="selectValue"
+        placeholder="请选择"
+      >
+        <el-option
+          v-for="item in timeoptions"
+          :key="item.value"
+          :label="item.label"
+          :value="item.value"
+        >
+        </el-option>
+      </el-select>
+      <div class="choose">
+        <button class="btn"
+          @click="switchChange(60)"
+        >
+          等间隔
+        </button>
+        <button class="btn"
+          @click="switchChange(0)"
+        >
+          原始数据
+        </button>
+      </div>
+    </div> -->
+
+      <multiple-y-line-chart-normal
+        height="500px"
+        :list="Analysis"
+        :yAxises="AnalysisYAxises"
+        :showLegend="true"
+      />
+    </el-dialog>
+    <!-- <el-dialog
+      :title="dialogTitleFX"
+      v-model="dialogVisibleFX"
+      width="70%"
+      top="10vh"
+      custom-class="modal"
+      :close-on-click-modal="false"
+      :destroy-on-close="true"
+    >
+      <FX :date="startdate" :wpid="wpvalue" />
+    </el-dialog> -->
+  </el-dialog>
+</template>
+
+<script>
+import Panel3 from "../panel/panel3.vue";
+import Table3 from "../table/table3.vue";
+import Yujing from "utils/yujing";
+import dayjs from "dayjs";
+import api from "api/index";
+import MultipleYLineChartNormal from "./multiple-y-line-chart-normal.vue";
+export default {
+  components: {
+    Panel3,
+    Table3,
+    MultipleYLineChartNormal,
+    // FX,
+  },
+  data() {
+    return {
+      dialogTitleFX: "",
+      dialogVisibleFX: false,
+      dialogTitle: "",
+      chooseStatus: false,
+      dialogVisible: false,
+      chooseTime: [],
+      timeValue: [],
+      wpvalue: "",
+      wpid: "",
+      wtId: "",
+      descName: "",
+      AnalysisName: "",
+      AnalysisUnit: "",
+      Analysis: [
+        {
+          title: "",
+          yAxisIndex: 0, // 使用单位
+          value: [],
+        },
+      ],
+      AnalysisYAxises: [
+        {
+          name: "",
+          min: "",
+          max: "",
+          unit: "",
+          position: "left",
+        },
+        {
+          name: "",
+          min: "",
+          max: "",
+          unit: "",
+          position: "right",
+        },
+      ],
+      selectValue: "60",
+      timeoptions: [
+        {
+          value: "60",
+          label: "一分钟",
+        },
+        {
+          value: "300",
+          label: "五分钟",
+        },
+        {
+          value: "600",
+          label: "十分钟",
+        },
+        {
+          value: "1800",
+          label: "三十分钟",
+        },
+        {
+          value: "3600",
+          label: "一小时",
+        },
+        {
+          value: "86400",
+          label: "一天",
+        },
+      ],
+      wpoptions: "",
+      options: [],
+      cascaderOptions: [],
+      cascaderSel: [],
+      cascaderProps: {
+        multiple: true,
+      },
+      column: [
+        "风机偏航过程震动",
+        "齿轮箱轴承温升超过40度",
+        "三相电流不平衡",
+        "断轴或联轴器打滑",
+        "风速突变",
+      ],
+      columnObj: [
+        {
+          name: "风机编号",
+          field: "name",
+          width: "100px",
+          minWidth: "100px",
+        },
+        {
+          name: "风机偏航过程震动",
+          field: "风机偏航过程震动",
+          align: "left",
+          slot: true,
+          sortable: true,
+          minWidth: "200px",
+        },
+        {
+          name: "齿轮箱轴承温升超过40度",
+          field: "齿轮箱轴承温升超过40度",
+          align: "left",
+          slot: true,
+          sortable: true,
+          minWidth: "200px",
+        },
+        {
+          name: "三相电流不平衡",
+          field: "三相电流不平衡",
+          align: "left",
+          slot: true,
+          sortable: true,
+          minWidth: "200px",
+        },
+        {
+          name: "断轴或联轴器打滑",
+          field: "断轴或联轴器打滑",
+          align: "left",
+          slot: true,
+          sortable: true,
+          minWidth: "200px",
+        },
+        {
+          name: "风速突变",
+          align: "left",
+          field: "风速突变",
+          slot: true,
+          sortable: true,
+          minWidth: "200px",
+        },
+      ],
+      startdate: dayjs(
+        new Date(new Date().setDate(new Date().getDate() - 1))
+      ).format("yyyy-MM-dd"),
+      enddate: dayjs(new Date()).format("yyyy-MM-dd"),
+      tableData: {
+        column: [
+          {
+            name: "风机编号",
+            field: "name",
+          },
+          {
+            name: "主轴温度温差大于8度",
+            field: "v1",
+            align: "left",
+            slot: true,
+          },
+          {
+            name: "浆叶角过小",
+            field: "v2",
+            align: "left",
+            slot: true,
+          },
+        ],
+        data: [
+          {
+            name: "MG01_01",
+            v1: {
+              count: 12,
+              time: 0,
+            },
+          },
+        ],
+      },
+    };
+  },
+  methods: {
+    opened() {
+      let date = new Date();
+      this.timeValue[0] = date.getTime() - 28800000;
+      this.timeValue[1] = date.getTime() + 3600000;
+      this.$nextTick(() => {
+        this.search();
+      });
+    },
+    //对比
+    showChart(column) {
+      let that = this;
+      that.dialogTitle = column.column.name;
+      that.wtId = column.row.name;
+      that.descName = column.column.name;
+
+      that.requestDetailData(
+        that.wpvalue,
+        this.timeValue[0],
+        this.timeValue[1],
+        60,
+        column.row.name,
+        column.column.name
+      );
+    },
+    requestDetailData(station, startTs, endTs, interval, wtId, name) {
+      api
+        .analysisDetail({
+          station: station,
+          startTs: startTs,
+          endTs: endTs,
+          interval: interval,
+          wtId: wtId,
+          name: name,
+        })
+        .then((res) => {
+          if (res.data.data.length == 1) {
+            this.dialogVisible = true;
+            let yaxises = [
+              {
+                name: "",
+                min: 0,
+                max: null,
+                unit: "",
+                position: "left",
+              },
+            ];
+            // yaxises.name = res.data[0].name;
+            yaxises.unit = res.data.data[0].unit;
+            this.AnalysisYAxises = yaxises;
+            let aKey1 = ["doubleValue"];
+            let aList1 = [
+              {
+                title: "",
+                // yAxisIndex:"",
+                smooth: true,
+                value: [],
+              },
+            ];
+            aKey1.forEach((keyEle, keyIndex) => {
+              aList1[keyIndex].title = res.data.data[keyIndex].name;
+              res.data.data[keyIndex].data.forEach((rEle) => {
+                aList1[keyIndex].value.push({
+                  text: dayjs(rEle.ts).format("hh:mm"),
+                  value: rEle.doubleValue,
+                });
+              });
+            });
+            this.Analysis = aList1;
+          } else if (res.data.data.length == 2) {
+            this.dialogVisible = true;
+            let aKey2 = ["doubleValue", "doubleValue"];
+            let aList2 = [
+              {
+                title: "",
+                //  yAxisIndex:"",
+                smooth: true,
+                value: [],
+              },
+              {
+                title: "",
+                // yAxisIndex:"",
+                smooth: true,
+                value: [],
+              },
+            ];
+            let yaxises1 = [
+              {
+                name: "",
+                min: 0,
+                max: null,
+                unit: "",
+                position: "left",
+              },
+              {
+                name: "",
+                min: 0,
+                max: null,
+                unit: "",
+                position: "right",
+              },
+            ];
+            yaxises1.forEach((aEle, aIndex) => {
+              res.data.data.forEach((rEle) => {
+                // aEle.name = rEle.name;
+                aEle.unit = rEle.unit;
+              });
+            });
+            this.AnalysisYAxises = yaxises1;
+            aKey2.forEach((keyEle, keyIndex) => {
+              aList2[keyIndex].title = res.data.data[keyIndex].name;
+              res.data.data[keyIndex].data.forEach((rEle) => {
+                aList2[keyIndex].value.push({
+                  text: dayjs(rEle.ts).format("hh:mm"),
+                  value: rEle.doubleValue,
+                });
+              });
+            });
+            // res.data.forEach((rEle,rIndex)=>{
+            // })
+            // aKey2.forEach((keyEle, keyIndex) => {
+            //   res.data.forEach((rEle) => {
+            //     // alist2[keyIndex].yAxisIndex = keyIndex;
+            //     aList2[keyIndex].title = res.data[keyIndex].name;
+            //     rEle.data.forEach((tEle,tIndex) => {
+            //       aList2[keyIndex].value.push({
+            //         text: new Date(tEle.ts).formatDate("hh:mm"),
+            //         // value: tEle[keyEle],
+            //         // value:res.data[keyIndex].data[tIndex].doubleValue
+
+            //       });
+            //     });
+            //   });
+            // });
+
+            this.Analysis = aList2;
+          } else if (res.data.data.length == 4) {
+            this.dialogVisible = true;
+            let aKey4 = [
+              "doubleValue",
+              "doubleValue",
+              "doubleValue",
+              "doubleValue",
+            ];
+            let aList4 = [
+              {
+                title: "",
+                // yAxisIndex:"",
+                smooth: true,
+                value: [],
+              },
+              {
+                title: "",
+                // yAxisIndex:"",
+                smooth: true,
+                value: [],
+              },
+              {
+                title: "",
+                // yAxisIndex:"",
+                smooth: true,
+                value: [],
+              },
+              {
+                title: "",
+                // yAxisIndex:"",
+                smooth: true,
+                value: [],
+              },
+            ];
+            let yaxises2 = [
+              {
+                name: "",
+                min: 0,
+                max: null,
+                unit: "",
+                position: "left",
+              },
+              {
+                name: "",
+                min: 0,
+                max: null,
+                unit: "",
+                position: "right",
+              },
+            ];
+            yaxises2.forEach((aEle, aIndex) => {
+              res.data.data.forEach((rEle) => {
+                // aEle.name = rEle.name;
+                aEle.unit = rEle.unit;
+              });
+            });
+            this.AnalysisYAxises = yaxises2;
+            aKey4.forEach((keyEle, keyIndex) => {
+              aList4[keyIndex].title = res.data.data[keyIndex].name;
+              res.data.data[keyIndex].data.forEach((rEle) => {
+                aList4[keyIndex].value.push({
+                  text: dayjs(rEle.ts).format("hh:mm"),
+                  value: rEle.doubleValue,
+                });
+              });
+            });
+            this.Analysis = aList4;
+          } else if (res.data.data.length == 0) {
+            this.dialogVisible = false;
+          }
+        });
+    },
+    //切换数据类型
+    switchChange(interval, status) {
+      if (status === "interval") {
+        this.chooseStatus = false;
+        this.selectValue = "60";
+      } else if (status === "original") {
+        this.chooseStatus = true;
+      }
+      this.requestDetailData(
+        this.wpvalue,
+        this.timeValue[0],
+        this.timeValue[1],
+        interval,
+        this.wtId,
+        this.descName
+      );
+    },
+
+    async search() {
+      let stationList = this.$store.state.stationList;
+      this.wpvalue = stationList[0].id;
+      this.wpoptions = stationList;
+      // const { data } = await this.API.requestData({
+      //   subUrl: "powercompare/windfarmAjax",
+      // });
+      // this.wpoptions = data.data;
+      // this.wpvalue = data.data[0].id;
+      this.searchData();
+    },
+
+    async searchTree() {
+      let arr = [];
+      let columnObj = [
+        {
+          name: "风机编号",
+          field: "name",
+          minWidth: "100px",
+        },
+      ];
+      this.cascaderSel.forEach((e) => {
+        let obj = {
+          name: e[1],
+          field: e[1],
+          align: "left",
+          slot: true,
+          sortable: true,
+          minWidth: "200px",
+        };
+        columnObj.push(obj);
+
+        arr.push(e[1]);
+      });
+      this.columnObj = columnObj;
+      this.column = arr;
+      this.searchData();
+    },
+
+    async searchData() {
+      let enddate = dayjs(
+        Date.parse(new Date(this.timeValue[1])) + 24 * 3600 * 1000
+      ).format("yyyy-MM-dd");
+      const { data } = Yujing;
+      // await api.alarmCountQuery({
+      //     stationid: this.wpvalue,
+      //     startdate: dayjs(this.timeValue[0]).format("yyyy-MM-dd"),
+      //     enddate: enddate,
+      // }).then()
+      // this.API.requestData({
+      //   showLoading: true,
+      //   baseURL: "http://192.168.1.18:8075/",
+      //   subUrl: "alarm/count/query/new2",
+      //   data: {
+      //     stationid: this.wpvalue,
+      //     startdate: dayjs(this.timeValue[0]).format("yyyy-MM-dd"),
+      //     enddate: enddate,
+      //   },
+      // });
+
+      ////////
+      this.tableData = [];
+      const resData = data;
+      // const resData =this.resdata;
+      const column = this.columnObj;
+      let dataAll = []; // 总数据集合
+      resData.forEach((e) => {
+        let obj = {
+          name: Object.keys(e)[0],
+        };
+        let wpid = Object.keys(e)[0];
+        this.wpid = wpid;
+
+        e[wpid].forEach((k) => {
+          column.forEach((c) => {
+            if (k.alertText == c.name) {
+              const countStyle = k.count / (k.count + k.time);
+              const timeStyle = k.time / (k.count + k.time);
+              let obj1 = {
+                count: k.count,
+                countStyle: countStyle ? countStyle * 100 + "px" : "0",
+                time: k.time,
+                timeStyle: timeStyle ? timeStyle * 100 + "px" : "0",
+              };
+              obj[k.alertText] = obj1;
+            }
+          });
+        });
+        dataAll.push(obj);
+      });
+
+      this.tableData.column = column;
+      this.tableData.data = dataAll;
+
+      ///////////////////// 获取规则list
+      const map = {};
+      var windNum = [];
+      for (let i in resData) {
+        for (let k in resData[i]) {
+          map[k] = resData[i][k];
+        }
+      }
+      // nmap为新的map 整理数据结构
+      const nmap = {};
+      for (let kv in map) {
+        var nchildMap = {};
+        var childrenMap = map[kv];
+        for (var ckv in childrenMap) {
+          var cckey = childrenMap[ckv].alertText;
+          var ccvalue = childrenMap[ckv];
+          nchildMap[cckey] = ccvalue;
+        }
+        nmap[kv] = nchildMap;
+      }
+      windNum = Object.keys(nmap);
+      var cascaderOptions = [];
+      var root = {}; // 原始根节点
+      var clumnsOnes = nmap[windNum[0]];
+      for (let k in clumnsOnes) {
+        let f = clumnsOnes[k].relatePartsText
+          ? clumnsOnes[k].relatePartsText
+          : "其他";
+        let fvalue = clumnsOnes[k].relateParts ? clumnsOnes[k].relateParts : "";
+
+        if (root[f]) {
+          // 已经存在此子节点
+          if (!root[f].children[k]) {
+            // 不存在子节点
+            root[f].children[k] = {};
+            root[f].children[k].value = root[f].children[k].label = k;
+            root[f].fobj.children.push(root[f].children[k]);
+          }
+        } else {
+          // 不存在子节点
+          root[f] = {};
+          // root[f].value = fvalue;
+          // root[f].label = f;
+          root[f].children = {};
+          root[f].children[k] = {};
+          root[f].children[k].value = root[f].children[k].label = k;
+
+          // 将对象放入 cascaderOptions
+          let childrenArray = [];
+          childrenArray.push(root[f].children[k]);
+          let fobj = {};
+          fobj.value = fvalue;
+          fobj.label = f;
+          fobj.children = childrenArray;
+          cascaderOptions.push(fobj);
+          root[f].fobj = fobj;
+        }
+      }
+      this.cascaderOptions = cascaderOptions;
+    },
+    fx() {
+      this.timeValue[0] = dayjs(this.timeValue[0]).format("yyyy-MM-dd");
+      this.dialogTitleFX = "预警分析";
+      this.dialogVisibleFX = true;
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.body {
+  background-color: #000000;
+  height: 90vh;
+  width: 102%;
+  margin-left: -1%;
+  margin-top: -40px;
+}
+.searchTitle {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin-left: 3vw;
+  padding-top: 10px;
+  color: #ffffff;
+  height: 55px;
+}
+.search {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin-right: 50px;
+}
+
+.table-panel {
+  width: 97%;
+  background: transparent;
+  padding: 0;
+  margin-left: 3vw;
+
+  .bar {
+    display: flex;
+    align-items: center;
+    height: 16px;
+    margin: 8px 0;
+
+    .bar-percent {
+      height: 100%;
+      background: #05bb4c;
+      margin-right: 8px;
+    }
+  }
+}
+.searchForm {
+  display: flex;
+  margin-left: 36px;
+  flex-direction: row-reverse;
+
+  .inputs {
+    width: 15%;
+    margin-right: 18px;
+  }
+}
+.model {
+  display: flex;
+  flex-direction: row-reverse;
+  align-items: center;
+  color: rgba(240, 240, 240, 1);
+  font-size: 12px;
+}
+
+.el-switch {
+  width: 453px;
+}
+
+.el-switch__label {
+  color: #999999 !important;
+}
+
+.el-switch__label.is-active {
+  color: rgba(37, 116, 219, 1) !important;
+}
+
+.selects {
+  margin-right: 16px;
+}
+
+.choose {
+  width: 160px;
+  height: 25px;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  color: #ffffff;
+}
+
+.interval {
+  width: 50%;
+  height: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: 1px solid rgba(77, 77, 77, 1);
+  border-top-left-radius: 12.5px;
+  border-bottom-left-radius: 12.5px;
+}
+
+.interval_on {
+  width: 50%;
+  height: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: rgba(29, 106, 235, 1);
+  border: 1px solid rgba(29, 106, 235, 1);
+  border-top-left-radius: 12.5px;
+  border-bottom-left-radius: 12.5px;
+}
+
+.original {
+  width: 50%;
+  height: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: 1px solid rgba(77, 77, 77, 1);
+  border-top-right-radius: 12.5px;
+  border-bottom-right-radius: 12.5px;
+}
+
+.original_on {
+  width: 50%;
+  height: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: rgba(29, 106, 235, 1);
+  border: 1px solid rgba(29, 106, 235, 1);
+  border-top-right-radius: 12.5px;
+  border-bottom-right-radius: 12.5px;
+}
+
+.inputs {
+  border: none;
+  width: 110px !important;
+}
+</style>

+ 221 - 0
src/components/table/check-table.vue

@@ -0,0 +1,221 @@
+<template>
+  <table class="com-table">
+    <thead>
+      <tr>
+        <th @click="onSort(0)" style="width:50px">排序</th>
+        <th @click="onSort(1)" style="width:50px"></th>
+        <th v-for="(col, index) of data.column" :key="index" :style="{ width: col.width }" :class="{ light: col.is_light }" @click="onSort(col)">{{ col.name }}</th>
+      </tr>
+    </thead>
+    <el-scrollbar>
+      <tbody :style="{ height: height }">
+        <tr v-for="(row, index) of tableData" :key="index">
+          <td v-if="allowIndex == true" style="width:50px" :class="{ light: hoverRow == row || hoverCol == 0, num: true }" @mouseenter="hover(row, col)" @mouseleave="leave()">
+            {{ startRow + index + 1 }}
+          </td>
+          <td :class="{ light: hoverRow == row || hoverCol == 1 }" style="width:50px" @mouseenter="hover(row, col)" @mouseleave="leave()">
+            <input class="check" type="CheckBox" :key="index" :id="'check-' + index" :checked="row.checked ? row.checked : false" @change="onCheck(row)" />
+          </td>
+          <td
+            v-for="(col, i) of data.column"
+            :key="i"
+            :style="{ width: col.width }"
+            :class="{ light: hoverRow == row || hoverCol == col + 2, num: col.is_num, 'always-light': col.is_light || row.is_light }"
+            @mouseenter="hover(row, col)"
+            @mouseleave="leave()"
+          >
+            <component :is="col.type ? col.type : 'div'" v-bind="col.props" v-html="template(col, row[col.field])" @click="onClick(col, row)"> </component>
+          </td>
+        </tr>
+      </tbody>
+    </el-scrollbar>
+    <el-pagination class="mg-t-8" v-if="pageable" @current-change="handleCurrentChange" :current-page="currentPage4" :page-size="pageSize" layout="total, prev, pager, next, jumper" :total="data.total" v-bind="elPaggingProps"> </el-pagination>
+  </table>
+</template>
+
+<script>
+export default {
+  // 名称
+  name: "ComTable",
+  // 使用组件
+  components: {},
+  // 传入参数
+  props: {
+    /**
+             * {
+                    column: [{
+                        name: "风机名称",
+                        field: "name",
+                        type:'div',
+                        is_num: false, // 是否为数字
+                        is_light: false, // 是否高亮
+                        template:function(){ }
+                        click:function(){} //点击事件
+                        sortable:fasle // 排序
+                        // 新增用于在表格中使用动态三方组件
+                        type:'el-tag', // * 新增 用于传入三方组件名称 实现三方组件引入  component :is 方式实现
+                        props:{}, // * 新增 用户传入三方组件的 props 与type同时使用
+                    },{
+                        name: "冷却风温度",
+                        field: "lqf",
+                        is_num: true,
+                        is_light: false
+                    }],
+                    data: [{
+                        name: "1E01",
+                        lqf: 15.78,
+                        is_light: false
+                    }]
+                }
+             */
+    data: Object,
+    // hover 样式
+    showHover: {
+      type: Boolean,
+      default: true,
+    },
+    canScroll: {
+      type: Boolean,
+      default: true,
+    },
+    pageSize: {
+      type: Number,
+      default: 0,
+    },
+    height: {
+      type: String,
+      default: "",
+    },
+    allowIndex: {
+      type: Boolean,
+      default: true,
+    },
+    elPaggingProps: {
+      type: Object,
+      default: () => {
+        return {
+          layout: "total, sizes, prev, pager, next, jumper",
+          // "page-sizes": [100, 200, 300, 400],
+        };
+      },
+    },
+  },
+  // 自定义事件
+  emits: {
+    // 分页事件
+    onPagging: null,
+    check: null,
+  },
+  // 数据
+  data() {
+    return {
+      hoverRow: -1,
+      hoverCol: -1,
+      sortCol: "",
+      sortType: "",
+      currentPage: 1,
+    };
+  },
+  computed: {
+    tableData() {
+      let that = this;
+      if (this.sortCol == "") {
+        return this.data.data;
+      } else {
+        let data = this.data.data;
+
+        data.sort((a, b) => {
+          let rev = 1;
+          if (that.sortType == "ASC") rev = 1;
+          else if (that.sortType == "DESC") rev = -1;
+
+          if (a[that.sortCol] > b[that.sortCol]) return rev * 1;
+          if (a[that.sortCol] < b[that.sortCol]) return rev * -1;
+          return 0;
+        });
+        return data;
+      }
+    },
+    pageable() {
+      return this.pageSize != 0;
+    },
+    pages() {
+      if (this.pageable) return parseInt(this.data.total / this.pageSize) + 1;
+      else return 0;
+    },
+    startRow() {
+      if (this.pageable) return (this.currentPage - 1) * this.pageSize;
+      else return 0;
+    },
+    endRow() {
+      if (this.pageable) return this.currentPage * this.pageSize;
+      else return this.data.data.length;
+    },
+  },
+  // 函数
+  methods: {
+    onClick(col, data) {
+      if (col.click) col.click(event, data);
+    },
+    onCheck(data) {
+      data.checked = event.target.checked;
+      this.$emit("check", { data: data, checked: data.checked });
+    },
+    onSort(col) {
+      if (col.sortable == true) {
+        this.sortCol = col.field;
+        switch (this.sortType) {
+          case "":
+            this.sortType = "DESC";
+            break;
+          case "DESC":
+            this.sortType = "ASC";
+            break;
+          case "ASC":
+            this.sortType = "";
+            break;
+        }
+      }
+    },
+    template(col, data) {
+      if (!col.template) return data;
+      else return col.template(data);
+    },
+    hover(row, col) {
+      if (this.showHover) {
+        this.hoverRow = row;
+        this.hoverCol = col;
+      }
+    },
+    leave() {
+      this.hoverRow = -1;
+      this.hoverCol = -1;
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+      this.$emit("onPagging", { pageIndex: this.currentPage, pageSize: this.pageSize, start: this.startRow, end: this.endRow });
+    },
+  },
+  // 生命周期钩子
+  beforeCreate() {
+    // 创建前
+  },
+  created() {
+    // 创建后
+  },
+  beforeMount() {
+    // 渲染前
+  },
+  mounted() {
+    // 渲染后
+  },
+  beforeUpdate() {
+    // 数据更新前
+  },
+  updated() {
+    // 数据更新后
+  },
+};
+</script>
+
+<style lang="less"></style>

+ 304 - 0
src/components/table/group-table.vue

@@ -0,0 +1,304 @@
+<template>
+  <el-table class="custom-table" :show-summary="summary" :class="customClass" stripe :data="data.data" :height="height" style="width: 100%" @cell-click="onClick" @header-click="onHeaderClick" ref="groupTable">
+    <template v-for="(col, cIndex) in data.column" :key="col">
+      <el-table-column v-if="col.child && col.child.length > 0" :label="col.name" :key="col">
+  
+        <el-table-column
+          v-for="(sub, sindex) in col.child"
+          :key="sub"
+          :index="cIndex"
+          :class-name="getClassName(cIndex, sindex)"
+          :label="sub.name"
+          :prop="sub.field"
+          :width="sub.width"
+          :sortable="sub.sortable"
+          :show-overflow-tooltip="!sub.slot"
+          :fixed="sub.fixed"
+          :align="sub.align ? sub.align : 'center'"
+          :resizable="sub.resizable"
+          :header-align="'center'"
+        >
+          <template v-if="sub.slot == true" #default="item">
+            <slot :name="sub.field" :column="sub" :row="item.row" :all="item" :data="item.row[item.field]"></slot>
+          </template>
+        </el-table-column>
+        
+
+      </el-table-column>
+
+      <el-table-column
+        v-if="!col.child"
+        :label="col.name"
+        :prop="col.field"
+        :width="col.width"
+        :sortable="col.sortable"
+        :show-overflow-tooltip="!col.slot"
+        :fixed="col.fixed"
+        :align="col.align ? col.align : 'center'"
+        :resizable="col.resizable"
+        :header-align="'center'"
+      >
+        <template v-if="col.slot == true" #default="item">
+          <slot :name="col.field" :column="col" :row="item.row" :all="item" :data="item.row[col.field]"></slot>
+        </template>
+      </el-table-column>
+      
+    </template>
+  </el-table>
+  <el-pagination class="mg-t-8"
+   v-if="pageable" @current-change="handleCurrentChange"
+    :current-page="currentPage" :page-size="pageSize" :total="data.total" v-bind="elPaggingProps">
+     </el-pagination>
+</template>
+
+<script>
+export default {
+  // 名称
+  name: "ComTable",
+  // 使用组件
+  components: {},
+  // 传入参数
+  props: {
+    /**
+             * {
+                    column: [{
+                        name: "风机名称",
+                        child:[{
+                            field: "name",
+                            width:'', // 宽度
+                            click:function(){} // 点击事件
+                            sortable:fasle,
+                            slot:false,
+                            fixed:false,
+                            align:'center',
+                            resizable :false,
+                        }]
+                    }],
+                    total:200
+                }
+             */
+    data: Object,
+    height: {
+      type: String,
+      default: "",
+    },
+    pageSize: {
+      type: Number,
+      default: 0,
+    },
+    customClass: {
+      type: String,
+      default: "",
+    },
+    elPaggingProps: {
+      type: Object,
+      default: () => {
+        return {
+          layout: "total, sizes, prev, pager, next, jumper",
+          // "page-sizes": [100, 200, 300, 400],
+        };
+      },
+    },
+    isColumnLight: {
+      type: Boolean,
+      default: true,
+    },
+    summary: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  emits: {
+    onPagging: null,
+    headerClick: null,
+  },
+  // 数据
+  data() {
+    return {
+      currentPage: 1,
+      headerIndex: -1,
+      subIndex: -1,
+    };
+  },
+  computed: {
+    tableData() {
+      let that = this;
+      if (this.sortCol == "") {
+        return this.data.data;
+      } else {
+        let data = this.data.data;
+
+        data.sort((a, b) => {
+          let rev = 1;
+          if (that.sortType == "ASC") rev = 1;
+          else if (that.sortType == "DESC") rev = -1;
+
+          if (a[that.sortCol] > b[that.sortCol]) return rev * 1;
+          if (a[that.sortCol] < b[that.sortCol]) return rev * -1;
+          return 0;
+        });
+        return data;
+      }
+    },
+    pageable() {
+      return this.pageSize != 0;
+    },
+    pages() {
+      if (this.pageable) return parseInt(this.data.total / this.pageSize) + 1;
+      else return 0;
+    },
+    startRow() {
+      if (this.pageable) return (this.currentPage - 1) * this.pageSize;
+      else return 0;
+    },
+    endRow() {
+      if (this.pageable) return this.currentPage * this.pageSize;
+      else return this.data.data.length;
+    },
+  },
+  // 函数
+  methods: {
+    onClick(row, column, cell, event) {
+      if (column.rawColumnKey.click) column.rawColumnKey.click(event, row);
+    },
+    onHeaderClick(column, event) {
+      if (column.level == 2) {
+        this.headerIndex = column.index;
+        this.subIndex = column.no;
+      }
+      this.$emit("headerClick", { level: column.level,  event: event, col: column.rawColumnKey, data: this.data.data });
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+      this.$emit("onPagging", {
+        pageIndex: this.currentPage,
+        pageSize: this.pageSize,
+        start: this.startRow,
+        end: this.endRow,
+      });
+    },
+    getClassName(cindex, sindex) {
+      if (this.isColumnLight == true && cindex == this.headerIndex && sindex == this.subIndex) return "light";
+      return "";
+    },
+  },
+  // 生命周期钩子
+  beforeCreate() {
+    // 创建前
+  },
+  created() {
+    // 创建后
+  },
+  beforeMount() {
+    // 渲染前
+  },
+  mounted() {
+    // 渲染后
+  },
+  beforeUpdate() {},
+  updated() {},
+};
+</script>
+
+<style lang="less">
+@titleGray: #9ca5a8;
+@rowGray: #606769;
+@darkBack: #536268;
+.com-table {
+  width: 100%;
+  border-collapse: collapse;
+
+  thead {
+    tr {
+      display: table;
+      table-layout: fixed;
+      width: 100%;
+
+      th {
+        background-color: fade(@darkBack, 20%);
+        height: 30px;
+        line-height: 30px;
+        color: @titleGray;
+        font-weight: 400;
+        font-size: @fontsize-s;
+        position: sticky;
+        top: 0;
+        cursor: pointer;
+
+        &.light,
+        &.always-light {
+          color: @green;
+        }
+      }
+    }
+  }
+
+  tbody {
+    display: block;
+
+    tr {
+      display: table;
+      table-layout: fixed;
+      width: 100%;
+
+      &:nth-child(2n) {
+        background-color: fade(@rowGray, 20%);
+      }
+
+      td {
+        padding: 0.556vh 0;
+        color: @rowGray;
+        text-align: center;
+        font-size: @fontsize-s;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+
+        &.light,
+        &.always-light {
+          color: @green !important;
+        }
+
+        &.num {
+          font-family: "Bicubik";
+          font-weight: 400;
+        }
+      }
+    }
+  }
+
+  .el-pagination {
+    color: @gray;
+    .el-pagination__total {
+      color: @gray;
+    }
+
+    button {
+      &.btn-next,
+      &.btn-prev {
+        background: center center no-repeat fade(@gray, 20);
+        color: @gray-l;
+      }
+      &:disabled {
+        color: @gray-l;
+        background-color: fade(@gray, 20);
+        cursor: not-allowed;
+      }
+    }
+
+    .el-pager li {
+      color: @gray-l;
+      background: fade(@gray, 20);
+      &.active {
+        color: @green;
+      }
+    }
+
+    .el-input__inner {
+      color: @gray-l;
+      background: fade(@gray, 20);
+      border: 1px solid fade(@gray, 20);
+    }
+  }
+}
+</style>

+ 333 - 0
src/components/table/table-page.vue

@@ -0,0 +1,333 @@
+<template>
+    <div class="table-page">
+        <div class="toolbar">
+            <div class="title" v-if="grid.title.show">
+                <i :class="grid.title.icon"></i>
+                <span>{{grid.title.text}}</span>
+            </div>
+            <div class="page-bar">
+                <span class="btn" @click="firstPage()">首页</span>
+                <span class="btn" @click="prevPage()">上一页</span>
+                <span v-for="(bar, index) of pageBar" :key="index" @click="gotoPage(bar)"
+                    :class="bar.type + ' ' + (bar.type != 'dot' && page == bar.text ? 'active' : '')">{{bar.text}}</span>
+                <span class="btn" @click="nextPage()">下一页</span>
+                <span class="btn" @click="lastPage()">尾页</span>
+            </div>
+            <div class="page-num">
+                <span>共</span>
+                <span>{{pages}}</span>
+                <span>页</span>
+                <span class="total">{{grid.data.total}}</span>
+                <span>条数据</span>
+            </div>
+            <div class="return" v-if="showReturn" @click="onReturn">
+                返回
+            </div>
+        </div>
+        <div class="sub-title" v-if="grid.subTitle.show">
+            <div class="text">{{grid.subTitle.text}}</div>
+            <div class="sub-text">{{grid.subTitle.subText}}</div>
+        </div>
+        <div class="ct">
+            <table class="com-table">
+                <thead>
+                    <tr>
+                        <th v-for="(col, index) of grid.column" :key="index" :class="{ 'light': col.is_light }">{{col.name}}
+                        </th>
+                    </tr>
+                </thead>
+                <tbody>
+                    <tr v-for="(row, index) of data" :key="index">
+                        <td v-for="(col, i) of grid.column" :key="i" :class="{ 'light': col.is_light || row.is_light, 'num': col.is_num }">
+                            {{row[col.field]}}</td>
+                    </tr>
+                </tbody>
+            </table>
+        </div>
+    </div>
+
+</template>
+
+<script>
+    export default {
+        // 名称
+        name: "ComTable",
+        // 使用组件
+        components: {},
+        // 传入参数
+        props: {
+            grid: Object,
+            showReturn: Boolean
+        },
+        // 自定义事件
+        emits: {
+            onReturn: null,
+        },
+        // 数据
+        data() {
+            return {
+                pages: 0,
+                page: 1,
+                pageBar: [],
+                data: []
+            }
+        },
+        // 函数
+        methods: {
+            createPageBar: function() {
+                let pb = [];
+                const p = this.page;
+                const ps = this.pages;
+                if (p >= 4) {
+                    pb.push({
+                        type: "dot",
+                        text: "...",
+                    })
+                }
+                for (let i = p - 2; i <= p + 2 && i <= ps; i++) {
+                    if (i <= 0) {
+                        continue;
+                    }
+                    pb.push({
+                        type: "btn num",
+                        text: i,
+                    })
+                }
+                if (ps > p + 2) {
+                    pb.push({
+                        type: "dot",
+                        text: "...",
+                    })
+                }
+                this.pageBar = pb;
+            },
+            createData: function () {
+                let d = [];
+                let p = this.page;
+                let l = this.grid.limit;
+                let t = this.grid.data.list.length;
+                for (let i = l * (p - 1); i < l * (p - 1) + l && i < t; i++) {
+                    d.push(this.grid.data.list[i]);
+                }
+                this.data = d;
+            },
+            gotoPage: function(item) {
+                if (item.type != 'dot') {
+                    this.page = item.text;
+                    this.createPageBar();
+                    this.createData();
+                }
+            },
+            prevPage: function() {
+                let p = this.page - 1;
+                if (p > 0) {
+                    this.page = p;
+                    this.createPageBar();
+                    this.createData();
+                }
+            },
+            nextPage: function() {
+                let p = this.page + 1;
+                if (p <= this.pages) {
+                    this.page = p;
+                    this.createPageBar();
+                    this.createData();
+                }
+            },
+            firstPage: function() {
+                this.page = 1;
+                this.createPageBar();
+                this.createData();
+            },
+            lastPage: function() {
+                this.page = this.pages;
+                this.createPageBar();
+                this.createData();
+            },
+            onReturn: function() {
+                this.$emit('onReturn');
+            }
+        },
+        // 生命周期钩子
+        beforeCreate() {
+            // 创建前
+        },
+        created() {
+            // 创建后
+            this.pages = Math.ceil(this.grid.data.list.length / this.grid.limit);
+            this.createPageBar();
+            this.createData();
+        },
+        beforeMount() {
+            // 渲染前
+        },
+        mounted() {
+            // 渲染后
+        },
+        beforeUpdate() {
+            // 数据更新前
+        },
+        updated() {
+            // 数据更新后
+        },
+    }
+</script>
+
+<style lang="less">
+    @titleGray: #9CA5A8;
+    @rowGray: #606769;
+    @darkBack: #536268;
+
+    .table-page {
+        display: flex;
+        flex-direction: column;
+        
+        .toolbar {
+            background-color: fade(@darkgray, 40%);
+            display: flex;
+
+            .title {
+                padding: 0.741vh 0;
+                color: @green;
+                font-size: @fontsize;
+
+                i {
+                    margin: 0 0.556vh 0 1.481vh;
+                }
+            }
+
+            .page-bar {
+                margin-left: auto;
+                font-size: @fontsize;
+                color: @gray;
+                display: flex;
+                align-items: center;
+
+                span {
+                    border-radius: 0.370vh;
+                    padding: 0.185vh 0.278vh;
+                    margin-right: 0.556vh;
+
+                    &.btn {
+                        cursor: pointer;
+
+                        &:hover {
+                            color: @green;
+                            border-color: @green;
+                        }
+                    }
+
+                }
+
+                .num {
+                    font-weight: 600;
+                    width: 2.315vh;
+                    text-align: center;
+                    border: 0.093vh solid @darkgray;
+
+                    &.active {
+                        color: @green;
+                        border-color: @green;
+                    }
+                }
+
+            }
+
+            .page-num {
+                margin-left: 1.481vh;
+                margin-right: 1.481vh;
+                font-size: @fontsize;
+                color: @gray;
+                display: flex;
+                align-items: center;
+
+                .total {
+                    margin-left: 0.741vh;
+                }
+            }
+
+            .return {
+                margin-right: 1.481vh;
+                font-size: @fontsize;
+                color: @gray;
+                display: flex;
+                align-items: center;
+                cursor: pointer;
+
+                &:hover {
+                    color: @green;
+                }
+            }
+        }
+
+        .sub-title {
+            background-color: fade(@darkgray, 40%);
+            display: flex;
+            padding: 0.741vh 2.222vh;
+            font-size: @fontsize;
+            margin-top: 1.481vh;
+
+            .text {
+                color: @write;
+            }
+
+            .sub-text {
+                margin-left: auto;
+                color: @write;
+            }
+        }
+        
+        .ct {
+            flex-grow: 1;
+            overflow: auto;
+        }
+        
+        .com-table {
+            width: 100%;
+            border-collapse: collapse;
+        
+            thead {
+                tr {
+                    th {
+                        background-color: fade(@darkBack, 60%);
+                        padding: 0.556vh 0;
+                        color: @titleGray;
+                        font-weight: 400;
+                        font-size: @fontsize-s;
+                        position: sticky;
+                        top: 0;
+                        
+                        &.light {
+                            color: @green;
+                        }
+                    }
+                }
+            }
+        
+            tbody {
+                tr {
+                    &:nth-child(2n) {
+                        background-color: fade(@rowGray, 20%);
+                    }
+        
+                    td {
+                        padding: 0.556vh 0;
+                        color: @rowGray;
+                        text-align: center;
+                        font-size: @fontsize-s;
+                        
+                        &.light {
+                            color: @green;
+                        }
+                        
+                        &.num {
+                            font-family: "Bicubik";
+                            font-weight: 400;
+                        }
+                    }
+                }
+            }
+        }
+        
+    }
+</style>

+ 497 - 0
src/components/table/table-qc.vue

@@ -0,0 +1,497 @@
+<template>
+  <table class="com-table">
+    <thead>
+      <tr>
+        <th
+          v-for="(col, index) of data.column"
+          :key="index"
+          :class="{ light: col.is_light }"
+          :style="{ width: col.width }"
+          @click="onSort(col)"
+        >{{ col.name }}</th>
+      </tr>
+    </thead>
+    <el-scrollbar>
+      <tbody :style="{ height: height }">
+        <tr v-for="(row, index) of tableData" :key="index">
+          <td
+            v-for="(col, i) of data.column"
+            :key="i"
+            :style="{ width: col.width }"
+            :class="{ light: hoverRow == row || hoverCol == col, num: col.is_num, 'always-light': col.is_light || row.is_light }"
+            @mouseenter="hover(row, col)"
+            @mouseleave="leave()"
+          >
+            <component
+              :is="col.type ? col.type : 'div'"
+              v-bind="col.props"
+              v-html="template(col, row[col.field])"
+              @click="onClick(col, row)"
+            ></component>
+          </td>
+        </tr>
+      </tbody>
+    </el-scrollbar>
+    <el-pagination
+      class="mg-t-8"
+      v-if="pageable"
+      @current-change="handleCurrentChange"
+      :current-page="currentPage4"
+      :page-size="pageSize"
+      layout="total, prev, pager, next, jumper"
+      :total="data.total"
+    ></el-pagination>
+    <el-dialog
+      :title="dialogTitle"
+      v-model="dialogShow"
+      width="70%"
+      top="10vh"
+      custom-class="modal"
+      :close-on-click-modal="true"
+    >
+      <div class="chart" id="chartDiv" height="500px"></div>
+    </el-dialog>
+  </table>
+</template>
+
+<script>
+import * as echarts from "echarts";
+export default {
+  // 名称
+  name: "ComTable",
+  // 使用组件
+  components: {},
+  // 传入参数
+  props: {
+    data: Object,
+    // hover 样式
+    showHover: {
+      type: Boolean,
+      default: true
+    },
+    // 列高亮
+    showColHover: {
+      type: Boolean,
+      default: false
+    },
+    canScroll: {
+      type: Boolean,
+      default: true
+    },
+    pageSize: {
+      type: Number,
+      default: 0
+    },
+    height: {
+      type: String,
+      default: ""
+    }
+  },
+  // 自定义事件
+  emits: {
+    // 分页事件
+    onPagging: null
+  },
+  // 数据
+  data() {
+    let that = this;
+    return {
+      hoverRow: -1,
+      hoverCol: -1,
+      sortCol: "",
+      sortType: "",
+      currentPage: 1,
+      dialogShow: false,
+      dialogTitle: "",
+      dialogData: {},
+      myChart : null
+    };
+  },
+  computed: {
+    tableData() {
+      let that = this;
+      if (this.sortCol == "") {
+        return this.data.data;
+      } else {
+        let data = this.data.data;
+
+        data.sort((a, b) => {
+          let rev = 1;
+          if (that.sortType == "ASC") rev = 1;
+          else if (that.sortType == "DESC") rev = -1;
+
+          if (a[that.sortCol] > b[that.sortCol]) return rev * 1;
+          if (a[that.sortCol] < b[that.sortCol]) return rev * -1;
+          return 0;
+        });
+        return data; 
+      }
+    },
+    pageable() {
+      return this.pageSize != 0;
+    },
+    pages() {
+      if (this.pageable) return parseInt(this.data.total / this.pageSize) + 1;
+      else return 0;
+    },
+    startRow() {
+      if (this.pageable) return (this.currentPage - 1) * this.pageSize;
+      else return 0;
+    },
+    endRow() {
+      if (this.pageable) return this.currentPage * this.pageSize;
+      else return this.data.data.length;
+    }
+  },
+  // 函数
+  methods: {
+    clearCheckBox(time) {
+      this.$nextTick(() => {
+        setTimeout(() => {
+          const domArray = document.querySelectorAll(".curCheckBox");
+          for (let i = 0; i < domArray.length; i++) {
+            domArray[i].checked = false;
+          }
+        }, time || 300);
+      });
+    },
+    onClick(col, row) {
+      this.clearChart();
+      let subUrl = "";
+      let data = {};
+      let method = "POST";
+      if ("sjbz" == col.field) {
+        subUrl = "/leaderboard/curveMonthchatAjax";
+        data["type"] = "sjbz";
+      } else if ("sjzy" == col.field) {
+        subUrl = "/leaderboard/curveMonthchatAjax";
+        data["type"] = "sjzy";
+      } else if ("zybz" == col.field) {
+        subUrl = "/leaderboard/curveMonthchatAjax";
+        data["type"] = "zybz";
+      } else if ("hb" == col.field) {
+        subUrl = "/leaderboard/curveMonthchatAjaxhb";
+        data["type"] = "hb";
+        method = "GET";
+      } else if ("tb" == col.field) {
+        subUrl = "/leaderboard/curveMonthchatAjaxtb";
+        data["type"] = "tb";
+        method = "GET";
+      } else if ("bbgfj" == col.field) {
+        subUrl = "/leaderboard/curveMonthchatAjaxbg";
+        data["type"] = "bg";
+        method = "GET";
+      } else {
+        return 0;
+      }
+      this.dialogShow = true;
+      this.dialogTitle = "曲线偏差率排行";
+      const date = new Date();
+      let year = date.getFullYear();
+      let month = date.getMonth() + 1;
+      let pdate = this.$parent.date.split("-");
+      if (pdate && pdate.length > 1) {
+        data["year"] = pdate[0];
+        data["month"] = pdate[1];
+      }
+      data["wtId"] = row.fj;
+      let that = this;
+      that.API.requestData({
+        method: method,
+        subUrl: subUrl,
+        data: data,
+        success(res) {
+          if (res.code === 200) {
+            const linedata1 = [];
+            const linedata2 = [];
+            const names = [res.data.name1, res.data.name2];
+            res.data.datas.forEach((item, index) => {
+              linedata1.push(item["value2"]);
+              linedata2.push(item["value3"]);
+            });
+
+            that.dialogShow = true;
+            that.dialogTitle = "曲线偏差率排行";
+            that.initChart(linedata1, linedata2, names);
+          }
+        }
+      });
+    },
+    clearChart(){
+      // echarts.init(document.getElementById("chartDiv"));
+      // TODO 未实现 点开后先清空曲线。mychart 不能定义为全局变量。Echarts bug
+    },
+    initChart(data1, data2, names) {
+      let that = this;
+      let myChart = echarts.init(document.getElementById("chartDiv"));
+      let option = {
+        color: ["#05bb4c", "#4b55ae"],
+        tooltip: {
+          trigger: "axis"
+        },
+        legend: {
+          show: true,
+          data: names,
+          right: 56,
+          icon: "circle",
+          itemWidth: 6,
+          inactiveColor: "#606769",
+          textStyle: {
+            color: "#B3BDC0",
+            fontSize: 12
+          }
+        },
+        grid: {
+          top: 32,
+          left: 40,
+          right: 40,
+          bottom: 24
+        },
+        xAxis: [
+          {
+            type: "category",
+            boundaryGap: false,
+            axisLabel: {
+              formatter: "{value}",
+              fontSize: 9.35925925925926,
+              textStyle: {
+                color: "#606769"
+              }
+            },
+            axisLine: {
+              show: false
+            },
+            data: [
+              "0",
+              "1",
+              "2",
+              "3",
+              "4",
+              "5",
+              "6",
+              "7",
+              "8",
+              "9",
+              "10",
+              "11",
+              "12",
+              "13",
+              "14",
+              "15",
+              "16",
+              "17",
+              "18",
+              "19",
+              "20",
+              "21",
+              "22",
+              "23",
+              "24",
+              "25"
+            ]
+          }
+        ],
+        yAxis: [
+          {
+            type: "value",
+            name: "(W)",
+            axisLabel: {
+              formatter: "{value}",
+              fontSize: 9.35925925925926
+            },
+            axisLine: {
+              show: false
+            },
+            splitLine: {
+              show: true,
+              lineStyle: {
+                color: "#606769",
+                type: "dashed"
+              }
+            }
+          }
+        ],
+        series: [
+          {
+            name: names[0],
+            type: "line",
+            smooth: true,
+            showSymbol: false,
+            zlevel: 0,
+            lineStyle: {
+              normal: {
+                color: "#05bb4c",
+                width: 1
+              },
+              emphasis: {
+                color: "#05bb4c"
+              }
+            },
+            areaStyle: {
+              normal: {
+                color: {
+                  colorStops: [
+                    {
+                      offset: 0,
+                      color: "rgba(5,187,76,0.3)"
+                    },
+                    {
+                      offset: 1,
+                      color: "rgba(5,187,76,0.1)"
+                    }
+                  ],
+                  x: 0,
+                  y: 0,
+                  x2: 0,
+                  y2: 1,
+                  type: "linear",
+                  global: false
+                },
+                shadowColor: "rgba(5,187,76,0.1)",
+                shadowBlur: 10
+              },
+              emphasis: {
+                color: {
+                  colorStops: [
+                    {
+                      offset: 0,
+                      color: "rgba(5,187,76,0.3)"
+                    },
+                    {
+                      offset: 1,
+                      color: "rgba(5,187,76,0.1)"
+                    }
+                  ],
+                  x: 0,
+                  y: 0,
+                  x2: 0,
+                  y2: 1,
+                  type: "linear",
+                  global: false
+                },
+                shadowColor: "rgba(5,187,76,0.1)",
+                shadowBlur: 10
+              }
+            },
+
+            yAxisIndex: 0,
+            data: data1
+          },
+          {
+            name: names[1],
+            type: "line",
+            smooth: true,
+            showSymbol: false,
+            zlevel: 2,
+            lineStyle: {
+              normal: {
+                color: "#606769",
+                width: 1
+              },
+              emphasis: {
+                color: "#fa8c16"
+              }
+            },
+            areaStyle: {
+              normal: {
+                color: "transparent",
+                shadowColor: "rgba(250,140,22,0.1)",
+                shadowBlur: 10
+              },
+              emphasis: {
+                color: {
+                  colorStops: [
+                    {
+                      offset: 0,
+                      color: "rgba(250,140,22,0.3)"
+                    },
+                    {
+                      offset: 1,
+                      color: "rgba(250,140,22,0.1)"
+                    }
+                  ],
+                  x: 0,
+                  y: 0,
+                  x2: 0,
+                  y2: 1,
+                  type: "linear",
+                  global: false
+                },
+                shadowColor: "rgba(250,140,22,0.1)",
+                shadowBlur: 10
+              }
+            },
+
+            yAxisIndex: 0,
+            data: data2
+          }
+        ]
+      };
+      myChart.clear();
+      myChart.setOption(option);
+      this.resize = function() {
+        myChart.resize();
+      };
+      window.addEventListener("resize", this.resize);
+      myChart.resize();
+    },
+    onSort(col) {
+      if (col.sortable == true) {
+        this.sortCol = col.field;
+        switch (this.sortType) {
+          case "":
+            this.sortType = "DESC";
+            break;
+          case "DESC":
+            this.sortType = "ASC";
+            break;
+          case "ASC":
+            this.sortType = "";
+            break;
+        }
+      }
+    },
+    template(col, data) {
+      if (!col.template) return data;
+      else return col.template(data);
+    },
+    hover(row, col) {
+      if (this.showHover) {
+        this.hoverRow = row;
+        if (this.showColHover) this.hoverCol = col;
+      }
+    },
+    leave() {
+      this.hoverRow = -1;
+      this.hoverCol = -1;
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+      this.$emit("onPagging", {
+        pageIndex: this.currentPage,
+        pageSize: this.pageSize,
+        start: this.startRow,
+        end: this.endRow
+      });
+    }
+  },
+  // 生命周期钩子
+  // 创建前
+  beforeCreate() {},
+  // 创建后
+  created() {},
+  // 渲染前
+  beforeMount() {},
+  // 渲染后
+  mounted() {},
+  beforeUpdate() {},
+  updated() {}
+};
+</script>
+
+<style lang="less">
+.chart {
+  width: 100%;
+  height: 500px;
+}
+</style>

+ 139 - 0
src/components/table/table-span.vue

@@ -0,0 +1,139 @@
+<template>
+  <table class="com-table">
+    <thead>
+      <tr>
+        <th v-for="(col, index) of data.column" :key="index" :class="{ light: col.is_light }">{{ col.name }}<br v-if="col.unit != ''" />{{ col.unit }}</th>
+      </tr>
+    </thead>
+    <tbody>
+      <tr v-for="(row, index) of data.data" :key="index">
+        <td :rowspan="rowspan(row, col)" :colspan="colspan(row, col)" v-for="(col, i) of data.column" :key="i" :class="{ light: col.is_light || row.is_light, num: col.is_num, remove: row[col.field] == '' }">
+          {{ row[col.field] || "a" }}
+        </td>
+      </tr>
+    </tbody>
+  </table>
+</template>
+
+<script>
+export default {
+  // 名称
+  name: "ComTable",
+  // 使用组件
+  components: {},
+  // 传入参数
+  props: {
+    data: Object,
+  },
+  // 自定义事件
+  emits: {},
+  // 数据
+  data() {
+    return {};
+  },
+  computed: {},
+  // 函数
+  methods: {
+    rowspan: function(row, col) {
+      if (row.row_span.length == 0) {
+        return 1;
+      } else {
+        let row_span = row.row_span.find((t) => t[0] == col.field);
+        if (row_span) {
+          return row_span[1];
+        } else {
+          return 1;
+        }
+      }
+    },
+    colspan: function(row, col) {
+      if (row.col_span.length == 0) {
+        return 1;
+      } else {
+        let col_span = row.col_span.find((t) => t[0] == col.field);
+        if (col_span) {
+          return col_span[1];
+        } else {
+          return 1;
+        }
+      }
+    },
+  },
+  // 生命周期钩子
+  beforeCreate() {
+    // 创建前
+  },
+  created() {
+    // 创建后
+  },
+  beforeMount() {
+    // 渲染前
+  },
+  mounted() {
+    // 渲染后
+  },
+  beforeUpdate() {
+    // 数据更新前
+  },
+  updated() {
+    // 数据更新后
+  },
+};
+</script>
+
+<style lang="less">
+@titleGray: #9ca5a8;
+@rowGray: #606769;
+@darkBack: #536268;
+
+.com-table {
+  width: 100%;
+  border-collapse: collapse;
+
+  thead {
+    tr {
+      th {
+        background-color: fade(@darkBack, 60%);
+        padding: 0.741vh 0;
+        color: @titleGray;
+        font-weight: 400;
+        font-size: @fontsize-s;
+        position: sticky;
+        top: 0;
+
+        &.light {
+          color: @green;
+        }
+      }
+    }
+  }
+
+  tbody {
+    tr {
+      &:nth-child(2n) {
+        background-color: fade(@rowGray, 20%);
+      }
+
+      td {
+        padding: 0.556vh 0;
+        color: @rowGray;
+        text-align: center;
+        font-size: @fontsize-s;
+
+        &.light {
+          color: @green;
+        }
+
+        &.num {
+          font-family: "Bicubik";
+          font-weight: 400;
+        }
+
+        &.remove {
+          display: none;
+        }
+      }
+    }
+  }
+}
+</style>

+ 216 - 0
src/components/table/table-unpage.vue

@@ -0,0 +1,216 @@
+<template>
+  <table class="com-table">
+    <thead>
+      <tr>
+        <th v-for="(col, index) of data.column" :key="index" :class="{ light: col.is_light }" :style="{ width: col.width }" @click="onSort(col)">
+          {{ col.name }}
+        </th>
+      </tr>
+    </thead>
+    <el-scrollbar>
+      <tbody :style="{ height: height }">
+        <tr v-for="(row, index) of tableData" :key="index">
+          <td
+            v-for="(col, i) of data.column"
+            :key="i"
+            :style="{ width: col.width }"
+            :class="{ light: hoverRow == row || hoverCol == col, num: col.is_num, 'always-light': col.is_light || row.is_light }"
+            @mouseenter="hover(row, col)"
+            @mouseleave="leave()"
+          >
+            <component :is="col.type ? col.type : 'div'" v-bind="col.props" v-html="template(col, row[col.field])" @click="onClick(col, row)"> </component>
+          </td>
+        </tr>
+      </tbody>
+    </el-scrollbar>
+  </table>
+</template>
+
+<script>
+export default {
+  // 名称
+  name: "ComTable",
+  // 使用组件
+  components: {},
+  // 传入参数
+  props: {
+    /**
+             * {
+                    column: [{
+                        name: "风机名称",
+                        field: "name",
+                        type:'div',
+                        width:'', // 宽度
+                        is_num: false, // 是否为数字
+                        is_light: false, // 是否高亮
+                        template:function(){ }
+                        click:function(){} //点击事件
+                        sortable:fasle // 排序
+                        // 新增用于在表格中使用动态三方组件
+                        type:'el-tag', // * 新增 用于传入三方组件名称 实现三方组件引入  component :is 方式实现
+                        props:{}, // * 新增 用户传入三方组件的 props 与type同时使用
+                    },{
+                        name: "冷却风温度",
+                        field: "lqf",
+                        is_num: true,
+                        is_light: false
+                    }],
+                    data: [{
+                        name: "1E01",
+                        lqf: 15.78,
+                        is_light: false
+                    }],
+                    total:200
+                }
+             */
+    data: Object,
+    // hover 样式
+    showHover: {
+      type: Boolean,
+      default: true,
+    },
+    // 列高亮
+    showColHover: {
+      type: Boolean,
+      default: false,
+    },
+    canScroll: {
+      type: Boolean,
+      default: true,
+    },
+    pageSize: {
+      type: Number,
+      default: 0,
+    },
+    height: {
+      type: String,
+      default: "",
+    },
+  },
+  // 自定义事件
+  emits: {
+    // 分页事件
+    onPagging: null,
+  },
+  // 数据
+  data() {
+    return {
+      hoverRow: -1,
+      hoverCol: -1,
+      sortCol: "",
+      sortType: "",
+      currentPage: 1,
+    };
+  },
+  computed: {
+    tableData() {
+      let that = this;
+      if (this.sortCol == "") {
+        return this.data.data;
+      } else {
+        let data = this.data.data;
+
+        data.sort((a, b) => {
+          let rev = 1;
+          if (that.sortType == "ASC") rev = 1;
+          else if (that.sortType == "DESC") rev = -1;
+
+          if (a[that.sortCol] > b[that.sortCol]) return rev * 1;
+          if (a[that.sortCol] < b[that.sortCol]) return rev * -1;
+          return 0;
+        });
+        return data;
+      }
+    },
+    pageable() {
+      return this.pageSize != 0;
+    },
+    pages() {
+      if (this.pageable) return parseInt(this.data.total / this.pageSize) + 1;
+      else return 0;
+    },
+    startRow() {
+      if (this.pageable) return (this.currentPage - 1) * this.pageSize;
+      else return 0;
+    },
+    endRow() {
+      if (this.pageable) return this.currentPage * this.pageSize;
+      else return this.data.data.length;
+    },
+  },
+  // 函数
+  methods: {
+    clearCheckBox(time){
+      this.$nextTick(()=>{
+        setTimeout(()=>{
+          const domArray = document.querySelectorAll(".curCheckBox");
+          for(let i=0;i<domArray.length;i++){
+            domArray[i].checked=false;
+          }
+        },(time || 300));
+      });
+    },
+    onClick(col, data) {
+      if (col.click) col.click(event, data);
+    },
+    onSort(col) {
+    
+      if (col.sortable == true) {
+        this.sortCol = col.field;
+        switch (this.sortType) {
+          case "":
+            this.sortType = "DESC";
+            break;
+          case "DESC":
+            this.sortType = "ASC";
+            break;
+          case "ASC":
+            this.sortType = "DESC";
+            break;
+        }
+      }
+    },
+    template(col, data) {
+      if (!col.template) return data;
+      else return col.template(data);
+    },
+    hover(row, col) {
+      if (this.showHover) {
+        this.hoverRow = row;
+        if (this.showColHover) this.hoverCol = col;
+      }
+    },
+    leave() {
+      this.hoverRow = -1;
+      this.hoverCol = -1;
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+      this.$emit("onPagging", {
+        pageIndex: this.currentPage,
+        pageSize: this.pageSize,
+        start: this.startRow,
+        end: this.endRow,
+      });
+    },
+  },
+  // 生命周期钩子
+  beforeCreate() {
+    // 创建前
+  },
+  created() {
+    // 创建后
+  },
+  beforeMount() {
+    // 渲染前
+  },
+  mounted() {
+    // 渲染后
+  },
+  beforeUpdate() {},
+  updated() {},
+};
+</script>
+
+<style lang="less">
+</style>

+ 277 - 0
src/components/table/table.vue

@@ -0,0 +1,277 @@
+<template>
+  <table class="com-table">
+    <thead>
+      <tr>
+        <th
+          v-for="(col, index) of data.column"
+          :key="index"
+          :class="{ light: col.is_light }"
+          :style="{ width: col.width }"
+          @click="onSort(col)"
+        >
+          {{ col.name }}
+        </th>
+      </tr>
+    </thead>
+    <el-scrollbar>
+      <tbody :style="{ height: height }">
+        <tr v-for="(row, index) of tableData" :key="index">
+          <td
+            v-for="(col, i) of data.column"
+            :key="i"
+            :style="{ width: col.width }"
+            :class="{
+              light: hoverRow == row || hoverCol == col,
+              num: col.is_num,
+              'always-light': col.is_light || row.is_light,
+            }"
+            @mouseenter="hover(row, col)"
+            @mouseleave="leave()"
+          >
+            <component
+              :is="col.type ? col.type : 'span'"
+              v-bind="col.props"
+              v-html="template(col, row[col.field])"
+              @click="onClick(col, row)"
+            >
+            </component>
+          </td>
+        </tr>
+      </tbody>
+    </el-scrollbar>
+    <el-pagination
+      class="mg-t-8"
+      v-if="pageable"
+      @size-change="sizeChange"
+      @current-change="handleCurrentChange"
+      @prev-click="prevClick"
+      @next-click="nextClick"
+      :current-page="currentPage"
+      :page-size="pageSize"
+      :total="data.total"
+      v-bind="elPaggingProps"
+    >
+    </el-pagination>
+  </table>
+</template>
+
+<script>
+export default {
+  // 名称
+  name: "ComTable",
+  // 使用组件
+  components: {},
+  // 传入参数
+  props: {
+    /**
+             * {
+                    column: [{
+                        name: "风机名称",
+                        field: "name",
+                        type:'div',
+                        width:'', // 宽度
+                        is_num: false, // 是否为数字
+                        is_light: false, // 是否高亮
+                        template:function(){ }
+                        click:function(){} //点击事件
+                        sortable:fasle // 排序
+                        // 新增用于在表格中使用动态三方组件
+                        type:'el-tag', // * 新增 用于传入三方组件名称 实现三方组件引入  component :is 方式实现
+                        props:{}, // * 新增 用户传入三方组件的 props 与type同时使用
+                    },{
+                        name: "冷却风温度",
+                        field: "lqf",
+                        is_num: true,
+                        is_light: false
+                    }],
+                    data: [{
+                        name: "1E01",
+                        lqf: 15.78,
+                        is_light: false
+                    }],
+                    total:200
+                }
+             */
+    data: Object,
+    // hover 样式
+    showHover: {
+      type: Boolean,
+      default: true,
+    },
+    // 列高亮
+    showColHover: {
+      type: Boolean,
+      default: false,
+    },
+    canScroll: {
+      type: Boolean,
+      default: true,
+    },
+    pageSize: {
+      type: Number,
+      default: 0,
+    },
+    height: {
+      type: String,
+      default: "",
+    },
+    // 新增 支持 pagging 组件
+    elPaggingProps: {
+      type: Object,
+      default: () => {
+        return {
+          layout: "total, sizes, prev, pager, next, jumper",
+          // "page-sizes": [100, 200, 300, 400],
+        };
+      },
+    },
+  },
+  // 自定义事件
+  emits: {
+    // 分页事件
+    onPagging: null,
+  },
+  // 数据
+  data() {
+    return {
+      hoverRow: -1,
+      hoverCol: -1,
+      sortCol: "",
+      sortType: "",
+      currentPage: 1,
+    };
+  },
+  computed: {
+    tableData() {
+      let that = this;
+      if (this.sortCol == "") {
+        return this.data.data;
+      } else {
+        let data = this.data.data;
+
+        data.sort((a, b) => {
+          let rev = 1;
+          if (that.sortType == "ASC") rev = 1;
+          else if (that.sortType == "DESC") rev = -1;
+
+          if (a[that.sortCol] > b[that.sortCol]) return rev * 1;
+          if (a[that.sortCol] < b[that.sortCol]) return rev * -1;
+          return 0;
+        });
+        return data;
+      }
+    },
+    pageable() {
+      return this.pageSize >= 0;
+    },
+    pages() {
+      if (this.pageable) return parseInt(this.data.total / this.pageSize) + 1;
+      else return 0;
+    },
+    startRow() {
+      if (this.pageable) return (this.currentPage - 1) * this.pageSize;
+      else return 0;
+    },
+    endRow() {
+      if (this.pageable) return this.currentPage * this.pageSize;
+      else return this.data.data.length;
+    },
+  },
+  // 函数
+  methods: {
+    clearCheckBox(time) {
+      this.$nextTick(() => {
+        setTimeout(() => {
+          const domArray = document.querySelectorAll(".curCheckBox");
+          for (let i = 0; i < domArray.length; i++) {
+            domArray[i].checked = false;
+          }
+        }, time || 300);
+      });
+    },
+    onClick(col, data) {
+      if (col.click) col.click(event, data);
+    },
+    onSort(col) {
+      if (col.sortable == true) {
+        this.sortCol = col.field;
+        switch (this.sortType) {
+          case "":
+            this.sortType = "DESC";
+            break;
+          case "DESC":
+            this.sortType = "ASC";
+            break;
+          case "ASC":
+            this.sortType = "DESC";
+            break;
+        }
+      }
+    },
+    template(col, data) {
+      if (!col.template) return data;
+      else return col.template(data);
+    },
+    hover(row, col) {
+      if (this.showHover) {
+        this.hoverRow = row;
+        if (this.showColHover) this.hoverCol = col;
+      }
+    },
+    leave() {
+      this.hoverRow = -1;
+      this.hoverCol = -1;
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+      this.$emit("onPagging", {
+        pageIndex: this.currentPage,
+        pageSize: this.pageSize,
+        start: this.startRow,
+        end: this.endRow,
+      });
+    },
+    sizeChange(res) {
+      this.$emit("sizeChange", {
+        pageSize: res,
+      });
+    },
+    prevClick() {
+      this.pageClick({
+        type: "prev",
+        pageNo: this.currentPage,
+      });
+    },
+    nextClick() {
+      this.pageClick({
+        type: "next",
+        pageNo: this.currentPage,
+      });
+    },
+    pageClick(res) {
+      this.$emit("pageClick", res);
+    },
+  },
+  // 生命周期钩子
+  beforeCreate() {
+    // 创建前
+  },
+  created() {
+    // 创建后
+  },
+  beforeMount() {
+    // 渲染前
+  },
+  mounted() {
+    // 渲染后
+  },
+  beforeUpdate() {},
+  updated() {},
+};
+</script>
+
+<style lang="less">
+.com-table{
+  height: 100%;
+}
+</style>

+ 301 - 0
src/components/table/table2.vue

@@ -0,0 +1,301 @@
+<template>
+  <el-table
+    class="custom-table"
+    stripe
+    :data="data.data"
+    :height="height"
+    style="width: 100%"
+    @cell-click="onClick"
+    @header-click="onHeaderClick"
+    ref="table"
+  >
+    <el-table-column
+      v-for="(col, cindex) of data.column"
+      :key="col"
+      :prop="col.field"
+      :label="col.name"
+      :width="col.width"
+      :min-width="col.minWidth"
+      :sortable="col.sortable"
+      :sort-orders="sortOrder"
+      :show-overflow-tooltip="!col.slot"
+      :fixed="col.fixed"
+      :align="'center'"
+      :resizable="col.resizable"
+      :header-align="'center'"
+      :class-name="getClassName(cindex)"
+    >
+      <template v-if="col.slot == true" #default="item">
+        <slot
+          :name="col.field"
+          :column="col"
+          :row="item.row"
+          :all="item"
+          :data="item.row[col.field]"
+        ></slot>
+      </template>
+    </el-table-column>
+  </el-table>
+  <el-pagination
+    class="mg-t-8"
+    v-if="pageable"
+    @current-change="handleCurrentChange"
+    :current-page="currentPage"
+    v-modal:page-size="selfPageSize"
+    :total="data.total"
+    v-bind="elPaggingProps"
+  >
+  </el-pagination>
+</template>
+
+<script>
+export default {
+  // 名称
+  name: "ComTable",
+  // 使用组件
+  components: {},
+  // 传入参数
+  props: {
+    /**
+             * {
+                    column: [{
+                        name: "风机名称",
+                        field: "name",
+                        width:'', // 宽度
+                        click:function(){} // 点击事件
+                        sortable:fasle,
+                        slot:false,
+                        fixed:false,
+                        align:'center',
+                        resizable :false,
+                    }],
+                    total:200
+                }
+             */
+    data: Object,
+    height: {
+      type: String,
+      default: "100%",
+    },
+    pageSize: {
+      type: Number,
+      default: 0,
+    },
+    elPaggingProps: {
+      type: Object,
+      default: () => {
+        return {
+          layout: "total, sizes, prev, pager, next, jumper",
+          // "page-sizes": [100, 200, 300, 400],
+        };
+      },
+    },
+    isColumnLight: {
+      type: Boolean,
+      default: true,
+    },
+  },
+  // 自定义事件
+  emits: {
+    // 分页事件
+    onPagging: null,
+  },
+  // 数据
+  data() {
+    return {
+      currentPage: 1,
+      headerIndex: -1,
+    };
+  },
+  computed: {
+    tableData() {
+      let that = this;
+      if (this.sortCol == "") {
+        return this.data.data;
+      } else {
+        let data = this.data.data;
+
+        data.sort((a, b) => {
+          let rev = 1;
+          if (that.sortType == "ASC") rev = 1;
+          else if (that.sortType == "DESC") rev = -1;
+
+          if (a[that.sortCol] > b[that.sortCol]) return rev * 1;
+          if (a[that.sortCol] < b[that.sortCol]) return rev * -1;
+          return 0;
+        });
+        return data;
+      }
+    },
+    pageable() {
+      return this.pageSize != 0;
+    },
+    pages() {
+      if (this.pageable) return parseInt(this.data.total / this.pageSize) + 1;
+      else return 0;
+    },
+    startRow() {
+      if (this.pageable) return (this.currentPage - 1) * this.pageSize;
+      else return 0;
+    },
+    endRow() {
+      if (this.pageable) return this.currentPage * this.pageSize;
+      else return this.data.data.length;
+    },
+    sortOrder:{
+      type:Array,
+      default:()  =>{
+        return ['descending', 'ascending', null]
+      }
+    }
+  },
+  // 函数
+  methods: {
+    onClick(row, column, cell, event) {
+      if (column.rawColumnKey.click) column.rawColumnKey.click(event, row);
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+      this.$emit("onPagging", {
+        pageIndex: this.currentPage,
+        pageSize: this.pageSize,
+        start: this.startRow,
+        end: this.endRow,
+      });
+    },
+    onHeaderClick(column, event) {
+      this.headerIndex = column.no;
+      this.$emit("headerClick", { index: column.no, event: event, col: column.rawColumnKey, data: this.data.data });
+    },
+    getClassName(cindex) {
+      if (this.isColumnLight == true && cindex == this.headerIndex) return "light";
+      return "";
+    },
+  },
+  // 生命周期钩子
+  beforeCreate() {
+    // 创建前
+  },
+  created() {
+    // 创建后
+    this.selfPageSize = this.pageSize
+
+  },
+  beforeMount() {
+    // 渲染前
+  },
+  mounted() {
+    // 渲染后
+  },
+  beforeUpdate() {
+    this.$nextTick(() => { //在数据加载完,重新渲染表格
+      // 数据刷新是闪烁,加上这个就不闪了 
+      this.$refs['table'].doLayout();
+    })
+  },
+  updated() {},
+};
+</script>
+
+<style lang="less">
+@titleGray: #9ca5a8;
+@rowGray: #606769;
+@darkBack: #536268;
+.com-table {
+  width: 100%;
+  border-collapse: collapse;
+
+  thead {
+    tr {
+      display: table;
+      table-layout: fixed;
+      width: 100%;
+
+      th {
+        background-color: fade(@darkBack, 20%);
+        height: 30px;
+        line-height: 30px;
+        color: @titleGray;
+        font-weight: 400;
+        font-size: @fontsize-s;
+        position: sticky;
+        top: 0;
+        cursor: pointer;
+
+        &.light,
+        &.always-light {
+          color: @green;
+        }
+      }
+    }
+  }
+
+  tbody {
+    display: block;
+
+    tr {
+      display: table;
+      table-layout: fixed;
+      width: 100%;
+
+      &:nth-child(2n) {
+        background-color: fade(@rowGray, 20%);
+      }
+
+      td {
+        padding: 0.556vh 0;
+        color: @rowGray;
+        text-align: center;
+        font-size: @fontsize-s;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+
+        &.light,
+        &.always-light {
+          color: @green !important;
+        }
+
+        &.num {
+          font-family: "Bicubik";
+          font-weight: 400;
+        }
+      }
+    }
+  }
+
+  .el-pagination {
+    color: @gray;
+    .el-pagination__total {
+      color: @gray;
+    }
+
+    button {
+      &.btn-next,
+      &.btn-prev {
+        background: center center no-repeat fade(@gray, 20);
+        color: @gray-l;
+      }
+      &:disabled {
+        color: @gray-l;
+        background-color: fade(@gray, 20);
+        cursor: not-allowed;
+      }
+    }
+
+    .el-pager li {
+      color: @gray-l;
+      background: fade(@gray, 20);
+      &.active {
+        color: @green;
+      }
+    }
+
+    .el-input__inner {
+      color: @gray-l;
+      background: fade(@gray, 20);
+      border: 1px solid fade(@gray, 20);
+    }
+  }
+}
+</style>

+ 303 - 0
src/components/table/table3.vue

@@ -0,0 +1,303 @@
+<template>
+  <el-table
+    class="custom-table"
+    stripe
+    :data="data.data"
+    :height="height"
+    style="width: 100%"
+    @cell-click="onClick"
+    v-if="data && data.data"
+    :header-cell-style="{
+      background: 'rgb(30,30,30)',
+      color: 'rgb(220,220,220)',
+      padding: '4px',
+      fontSize: '14px',
+      'border-bottom': 'solid 1px rgba(77, 77, 77, 1)',
+    }"
+    :cell-style="{
+      height: '40px',
+      background: 'rgb(30,30,30)',
+      color: 'rgb(220,220,220)',
+      padding: '3px',
+      fontSize: '12px',
+      'border-bottom': '1px solid #000000',
+    }"
+  >
+    <el-table-column
+      v-for="col in data.column"
+      :key="col"
+      :prop="col.field"
+      :label="col.name"
+      :width="col.width"
+      :min-width="col.minWidth"
+      :sortable="col.sortable"
+      :sort-orders="sortOrder"
+      :sort-by="col.field + '.count'"
+      :show-overflow-tooltip="!col.slot"
+      :fixed="col.fixed"
+      :align="'center'"
+      :resizable="col.resizable"
+      :header-align="'center'"
+    >
+      <template v-if="col.slot == true" #default="item">
+        <slot
+          :name="col.field"
+          :column="col"
+          :row="item.row"
+          :all="item"
+          :data="item.row[col.field]"
+        ></slot>
+      </template>
+    </el-table-column>
+  </el-table>
+  <el-pagination
+    class="mg-t-8"
+    v-if="pageable"
+    @current-change="handleCurrentChange"
+    :current-page="currentPage"
+    v-modal:page-size="selfPageSize"
+    :total="data.total"
+    v-bind="elPaggingProps"
+  >
+  </el-pagination>
+</template>
+
+<script>
+export default {
+  // 名称
+  name: "ComTable",
+  // 使用组件
+  components: {},
+  // 传入参数
+  props: {
+    /**
+             * {
+                    column: [{
+                        name: "风机名称",
+                        field: "name",
+                        width:'', // 宽度
+                        click:function(){} // 点击事件
+                        sortable:fasle,
+                        slot:false,
+                        fixed:false,
+                        align:'center',
+                        resizable :false,
+                    }],
+                    total:200
+                }
+             */
+    data: Object,
+    height: {
+      type: String,
+      default: "",
+    },
+    pageSize: {
+      type: Number,
+      default: 0,
+    },
+    elPaggingProps: {
+      type: Object,
+      default: () => {
+        return {
+          layout: "total, sizes, prev, pager, next, jumper",
+          // "page-sizes": [100, 200, 300, 400],
+        };
+      },
+    },
+    sortOrder: {
+      type: Array,
+      default: () => {
+        return ["descending", "ascending", null];
+      },
+    },
+  },
+  // 自定义事件
+  emits: {
+    // 分页事件
+    onPagging: null,
+  },
+  // 数据
+  data() {
+    return {
+      currentPage: 1,
+    };
+  },
+  computed: {
+    tableData() {
+      let that = this;
+      if (this.sortCol == "") {
+        return this.data.data;
+      } else {
+        let data = this.data.data;
+
+        data.sort((a, b) => {
+          let rev = 1;
+          if (that.sortType == "ASC") rev = 1;
+          else if (that.sortType == "DESC") rev = -1;
+
+          if (a[that.sortCol] > b[that.sortCol]) return rev * 1;
+          if (a[that.sortCol] < b[that.sortCol]) return rev * -1;
+          return 0;
+        });
+        return data;
+      }
+    },
+    pageable() {
+      return this.pageSize != 0;
+    },
+    pages() {
+      if (this.pageable) return parseInt(this.data.total / this.pageSize) + 1;
+      else return 0;
+    },
+    startRow() {
+      if (this.pageable) return (this.currentPage - 1) * this.pageSize;
+      else return 0;
+    },
+    endRow() {
+      if (this.pageable) return this.currentPage * this.pageSize;
+      else return this.data.data.length;
+    },
+    // sortOrder: {
+    //   type: Array,
+    //   default: () => {
+    //     return ["descending", "ascending", null];
+    //   },
+    // },
+  },
+  // 函数
+  methods: {
+    onClick(row, column, cell, event) {
+      if (column.rawColumnKey.click) column.rawColumnKey.click(event, row);
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+      this.$emit("onPagging", {
+        pageIndex: this.currentPage,
+        pageSize: this.pageSize,
+        start: this.startRow,
+        end: this.endRow,
+      });
+    },
+  },
+  // 生命周期钩子
+  beforeCreate() {
+    // 创建前
+  },
+  created() {
+    // 创建后
+    this.selfPageSize = this.pageSize;
+  },
+  beforeMount() {
+    // 渲染前
+  },
+  mounted() {
+    // 渲染后
+  },
+  beforeUpdate() {},
+  updated() {},
+};
+</script>
+
+<style lang="less" scoped>
+@titleGray: #9ca5a8;
+@rowGray: #606769;
+@darkBack: #536268;
+.com-table {
+  width: 100%;
+  border-collapse: collapse;
+
+  thead {
+    tr {
+      display: table;
+      table-layout: fixed;
+      width: 100%;
+
+      th {
+        background-color: fade(@darkBack, 20%);
+        height: 30px;
+        line-height: 30px;
+        color: @titleGray;
+        font-weight: 400;
+        font-size: 12px;
+        position: sticky;
+        top: 0;
+        cursor: pointer;
+
+        &.light,
+        &.always-light {
+          color: #05bb4c;
+        }
+      }
+    }
+  }
+
+  tbody {
+    display: block;
+
+    tr {
+      display: table;
+      table-layout: fixed;
+      width: 100%;
+
+      &:nth-child(2n) {
+        background-color: fade(@rowGray, 20%);
+      }
+
+      td {
+        padding: 0.556vh 0;
+        color: @rowGray;
+        text-align: center;
+        font-size: 12px;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+
+        &.light,
+        &.always-light {
+          color: #05bb4c !important;
+        }
+
+        &.num {
+          font-family: "Bicubik";
+          font-weight: 400;
+        }
+      }
+    }
+  }
+
+  .el-pagination {
+    color: #606769;
+    .el-pagination__total {
+      color: #606769;
+    }
+
+    button {
+      &.btn-next,
+      &.btn-prev {
+        background: center center no-repeat fade(#606769, 20);
+        color: #b3bdc0;
+      }
+      &:disabled {
+        color: #b3bdc0;
+        background-color: fade(#606769, 20);
+        cursor: not-allowed;
+      }
+    }
+
+    .el-pager li {
+      color: #b3bdc0;
+      background: fade(#606769, 20);
+      &.active {
+        color: #05bb4c;
+      }
+    }
+
+    .el-input__inner {
+      color: #b3bdc0;
+      background: fade(#606769, 20);
+      border: 1px solid fade(#606769, 20);
+    }
+  }
+}
+
+</style>

+ 270 - 0
src/components/temperatureMatrix.vue

@@ -0,0 +1,270 @@
+<template>
+  <el-dialog
+    width="70%"
+    @open="opened"
+    @closed="closed"
+    :fullscreen="true"
+    :show-close="true"
+    class="dialogs"
+  >
+    <template #title>
+      <div class="showTitles currentShowTitles">
+        <div class="titles">温度矩阵</div>
+      </div>
+    </template>
+    <div class="body">
+      <div class="title">
+        <div
+          :class="current === item.id ? 'title-onItem' : 'title-item'"
+          v-for="(item, index) in stationList"
+          :key="index"
+          @click="handleChange(item.id)"
+        >
+          {{ item.address }}
+        </div>
+      </div>
+      <div class="tables">
+        <el-table
+          :data="tableData"
+          class="table"
+          style="width: 100%"
+          height="83vh"
+          stripe
+          :header-cell-style="{
+            background: 'rgb(30,30,30)',
+            color: 'rgb(220,220,220)',
+            padding: '4px',
+            fontSize: '14px',
+            border: 'solid 1px rgba(77, 77, 77, 1)',
+          }"
+          :cell-style="tableCellStyle"
+        >
+          <el-table-column
+            prop="windturbineId"
+            label="风机"
+            width="100"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="stationId"
+            label="风场"
+            width="100"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="windSpeed"
+            label="风速"
+            width="100"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column prop="power" label="功率" width="100" align="center">
+          </el-table-column>
+          <el-table-column
+            prop="rollSpeed"
+            label="发电机转速"
+            width="100"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column
+            v-for="(item, index) in contentList"
+            :key="index"
+            :label="item.name"
+            align="center"
+          >
+            <el-table-column
+              v-for="(res, index) in item.children"
+              :prop="res.name"
+              :key="index"
+              :label="res.name"
+              align="center"
+            >
+            </el-table-column>
+          </el-table-column>
+        </el-table>
+      </div>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import api from "api/index";
+export default {
+  data() {
+    return {
+      contentList: [],
+      tableData: [],
+      partsArr: [],
+      coordinates: [],
+      stationList: [],
+      current: "all",
+    };
+  },
+  mounted() {},
+  methods: {
+    opened() {
+      let stationList = [
+        {
+          id: "all",
+          address: "全部风机",
+        },
+      ];
+      let stations = this.$store.state.stationList;
+      stations.forEach((item) => {
+        if (item.id.indexOf("FDC") != -1) {
+          stationList.push(item);
+        }
+      });
+      this.stationList = stationList;
+      this.coordinates = [];
+      this.getData("");
+    },
+    handleChange(val) {
+      this.current = val;
+      this.getData(val === "all" ? "" : val);
+    },
+    getData(val) {
+      api.temperatureInfo(val).then((res) => {
+        let contentList = [];
+        let tableDatas = [];
+        res.data.forEach((item, index) => {
+          let tableData = {};
+          tableData.windturbineId = item.windturbineId;
+          tableData.windSpeed = item.windSpeed.toFixed(1);
+          tableData.stationId = item.stationId;
+          tableData.rollSpeed = item.rollSpeed.toFixed(1);
+          tableData.power = item.power.toFixed(1);
+          item.temperatureComponentInfos.forEach((val) => {
+            if (index === 0) {
+              let obj = {
+                children: [],
+              };
+              obj.name = val.name;
+              val.temperatureItemInfos.forEach((temp) => {
+                if (index === 0) {
+                  let str = {};
+                  str.name = temp.name;
+                  obj.children.push(str);
+                }
+                tableData[temp.name] = temp.value.toFixed(1);
+                tableData[`${temp.name}Status`] = temp.status;
+              });
+              contentList.push(obj);
+            } else {
+              val.temperatureItemInfos.forEach((temp) => {
+                tableData[temp.name] = temp.value.toFixed(1);
+                tableData[`${temp.name}Status`] = temp.status;
+              });
+            }
+          });
+          tableDatas.push(tableData);
+        });
+        this.contentList = contentList;
+        let arr = [];
+        this.contentList.forEach((item) => {
+          item.children.forEach((val) => {
+            arr.push(val.name);
+          });
+        });
+        this.partsArr = arr;
+        tableDatas.forEach((item, indexx) => {
+          for (const key in item) {
+            if (item[key] === "BadPoint") {
+              this.partsArr.forEach((val, indexy) => {
+                if (key === `${val}Status`) {
+                  this.coordinates.push(`${indexx},${indexy + 5}`);
+                }
+              });
+            }
+          }
+        });
+        this.tableData = tableDatas;
+      });
+    },
+    tableCellStyle({ row, column, rowIndex, columnIndex }) {
+      let warningColor = false;
+      let obj = {};
+      this.coordinates.forEach((item) => {
+        let arr = item.split(",");
+        if (Number(arr[0]) === rowIndex && Number(arr[1]) === columnIndex) {
+          warningColor = true;
+        }
+      });
+      if (warningColor) {
+        obj = {
+          height: "40px",
+          background: "rgba(186, 50, 55, 1)",
+          color: "#FFFFFF",
+          padding: "3px",
+          fontSize: "12px",
+          "border-top": "0px solid #000000",
+          "border-bottom": "1px solid #000000",
+          "border-right": "1px solid #000000",
+        };
+      } else {
+        obj = {
+          height: "40px",
+          background: "rgb(30,30,30)",
+          color: "rgb(220,220,220)",
+          padding: "3px",
+          fontSize: "12px",
+          "border-top": "0px solid #000000",
+          "border-bottom": "1px solid #000000",
+          "border-right": "1px solid #000000",
+        };
+      }
+
+      return obj;
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.body {
+  background-color: #000000;
+  height: 89vh;
+  width: 102%;
+  margin-left: -1%;
+  margin-top: -40px;
+}
+.title {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin-left: 3vw;
+  padding-top: 8px;
+  position: absolute;
+  width: 100%;
+  background-color: #000000;
+  padding-bottom: 10px;
+
+  .title-item {
+    background-color: #242424;
+    border-radius: 4px;
+    padding: 8px 27px 7px 25px;
+    font-size: 14px;
+    color: #b4bdc0;
+    margin-right: 10px;
+  }
+  .title-onItem {
+    background-color: rgba(37, 116, 219, 1);
+    border-radius: 4px;
+    padding: 8px 27px 7px 25px;
+    font-size: 14px;
+    color: #b4bdc0;
+    margin-right: 10px;
+  }
+}
+.tables {
+  margin-left: 3vw;
+  padding-top: 50px;
+}
+.el-table {
+  position: static;
+  background-color: #141414;
+  border: 1px solid #000000;
+}
+</style>

+ 848 - 0
src/components/unpaidMatrixBlock.vue

@@ -0,0 +1,848 @@
+<template>
+  <div>
+    <div class="box">
+      <div
+        :class="item.active ? 'box-' + item.status : 'unbox-' + item.status"
+        :id="item.windturbineId"
+        v-for="(item, index) in dataList"
+        :key="index"
+        @click="onSelectHandler(item)"
+        @dblclick="sendMsg(item)"
+      >
+        <div class="info">
+          <div
+            :class="
+              item.active ? 'left-' + item.status : 'unleft-' + item.status
+            "
+          >
+            <div>{{ item.windturbineId.slice(0, 2) }}</div>
+            <div>{{ item.windturbineId.slice(5) }}</div>
+            <!-- <div>{{ item.windturbineId.slice(0, 2) }}</div>
+            <div>{{ item.code }}</div> -->
+          </div>
+          <div
+            :class="
+              item.active ? 'right-' + item.status : 'unright-' + item.status
+            "
+          >
+            <div class="rightrow">{{ item.windSpeed.toFixed(2) }} m/s</div>
+
+            <div class="rightrow">{{ item.power.toFixed(2) }} kw</div>
+
+            <div class="rightrow">
+              {{
+                item.modelId.indexOf("105") >= 0
+                  ? (item.rollSpeed * 9.55).toFixed(2)
+                  : item.rollSpeed.toFixed(2)
+              }}
+              rpm
+            </div>
+          </div>
+          <div class="locks" v-if="item.lockValue > 0">
+            <el-popover
+              placement="bottom-start"
+              :width="150"
+              trigger="hover"
+              class="popoverBack"
+              :show-arrow="false"
+            >
+              <template #reference>
+                <img class="lock" src="../assets/img/type/lock.png" alt="" />
+              </template>
+              <input
+                class="lock_input"
+                type="text"
+                placeholder=""
+                :value="
+                  item.lockValue === 9
+                    ? item.lockValues
+                    : options[item.lockValue]
+                "
+                disabled
+              />
+            </el-popover>
+          </div>
+        </div>
+        <div :class="'unpaid-' + item.status">
+          <div
+            class="progress"
+            :style="`width: ${((item.power / item.powerProduction) * 100 >= 100
+              ? 100
+              : (item.power / item.powerProduction) * 100
+            ).toFixed(2)}%;background-color: ${
+              unpaidColor[item.undeliveredStatus]
+            };height: 50%;`"
+          ></div>
+        </div>
+      </div>
+    </div>
+    <WindturbineDetailPages
+      v-model="dialogVisible"
+      :showSvg="showSvg"
+      @close="handleClose"
+      :windturbine="currentWindturbine"
+    ></WindturbineDetailPages>
+  </div>
+</template>
+<script>
+import WindturbineDetailPages from "./WindturbineDetailPages.vue";
+export default {
+  components: {
+    WindturbineDetailPages,
+  },
+  props: {
+    dataList: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+  },
+  mounted() {
+    // this.getWindturbineFdc();
+  },
+  updated() {},
+  methods: {
+    onSelectHandler(values) {
+      this.$emit("choose-click", values);
+    },
+    sendMsg: function (itm) {
+      // this.dialogVisible = true;
+      this.$emit("on-click", itm);
+      // this.currentWindturbine = itm;
+    },
+    handleClose() {
+      this.dialogVisible = false;
+      this.showSvg = false;
+    },
+  },
+  data() {
+    return {
+      dialogVisible: false,
+      showSvg: false,
+      currentWindturbine: {},
+      showVlaues: "",
+      // station: [],
+      options: {
+        8: "检修",
+        7: "故障维修",
+        2: "场内受累检修",
+        3: "场内受累故障",
+        4: "场外受累电网",
+        5: "场外受累天气",
+      },
+      unpaidColor: {
+        0: "#57cf3a",
+        1: "#0ec7dc",
+        2: "#1974ff",
+        3: "#cd4cdd",
+        3: "#ff3c80",
+      },
+    };
+  },
+};
+</script>
+<style lang="less" scoped>
+.box {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+}
+
+.info {
+  display: flex;
+  flex-direction: row;
+  height: 50px;
+  width: 100%;
+  justify-content: space-between;
+}
+.box-0 {
+  width: 135px;
+  height: 60px;
+  color: #ffffff;
+  border: 1px solid rgba(255, 255, 255, 1);
+  background-color: rgba(255, 255, 255, 0.05);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-right: 10px;
+  margin-top: 10px;
+  box-shadow: 0px 0px 6px #ffffff;
+}
+
+.unbox-0 {
+  width: 135px;
+  height: 60px;
+  color: #ffffff;
+  border: 1px solid rgba(255, 255, 255, 1);
+  background-color: rgba(255, 255, 255, 0.2);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-right: 10px;
+  margin-top: 10px;
+}
+.unpaid-0 {
+  display: flex;
+  align-items: center;
+  width: 100%;
+  height: 10px;
+  border-top: 1px solid rgba(255, 255, 255, 1);
+}
+.left-0 {
+  width: 35%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(255, 255, 255, 1);
+  font-weight: 600;
+  line-height: 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+
+.unleft-0 {
+  width: 35%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(255, 255, 255, 1);
+  font-weight: 600;
+  line-height: 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+
+.right-0 {
+  width: 69%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(255, 255, 255, 1);
+  line-height: 15px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.unright-0 {
+  width: 69%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(255, 255, 255, 1);
+  line-height: 15px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+.box-1 {
+  width: 135px;
+  height: 60px;
+  color: #ffffff;
+  border: 1px solid rgba(197, 48, 200, 1);
+  background-color: rgba(197, 48, 200, 0.05);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-right: 10px;
+  margin-top: 10px;
+  box-shadow: 0px 0px 6px #ef3af2;
+}
+
+.unbox-1 {
+  width: 135px;
+  height: 60px;
+  color: #ffffff;
+  border: 1px solid rgba(197, 48, 200, 1);
+  background-color: rgba(197, 48, 200, 0.2);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-right: 10px;
+  margin-top: 10px;
+}
+.unpaid-1 {
+  display: flex;
+  align-items: center;
+  width: 100%;
+  height: 10px;
+  border-top: 1px solid rgba(197, 48, 200, 1);
+}
+.left-1 {
+  width: 35%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(197, 48, 200, 1);
+  font-weight: 600;
+  line-height: 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+
+.unleft-1 {
+  width: 35%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(197, 48, 200, 1);
+  font-weight: 600;
+  line-height: 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+
+.right-1 {
+  width: 69%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(197, 48, 200, 1);
+  line-height: 15px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.unright-1 {
+  width: 69%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(197, 48, 200, 1);
+  line-height: 15px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+.box-2 {
+  width: 135px;
+  height: 60px;
+  color: #ffffff;
+  border: 1px solid rgba(05, 187, 76, 1);
+  background-color: rgba(05, 187, 76, 0.05);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-right: 10px;
+  margin-top: 10px;
+  box-shadow: 0px 0px 6px #09e45e;
+}
+
+.unbox-2 {
+  width: 135px;
+  height: 60px;
+  color: #ffffff;
+  border: 1px solid rgba(05, 187, 76, 1);
+  background-color: rgba(05, 187, 76, 0.2);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-right: 10px;
+  margin-top: 10px;
+}
+
+.unpaid-2 {
+  display: flex;
+  align-items: center;
+  width: 100%;
+  height: 10px;
+  border-top: 1px solid rgba(05, 187, 76, 1);
+}
+
+.left-2 {
+  width: 35%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(05, 187, 76, 1);
+  font-weight: 600;
+  line-height: 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+
+.unleft-2 {
+  width: 35%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(05, 187, 76, 1);
+  font-weight: 600;
+  line-height: 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+
+.right-2 {
+  width: 69%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(05, 187, 76, 1);
+  line-height: 15px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.unright-2 {
+  width: 69%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(05, 187, 76, 1);
+  line-height: 15px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.box-3 {
+  width: 135px;
+  height: 60px;
+  color: #ffffff;
+  border: 1px solid rgba(05, 187, 76, 1);
+  background-color: rgba(05, 187, 76, 0.05);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-right: 10px;
+  margin-top: 10px;
+  box-shadow: 0px 0px 6px #09e45e;
+}
+
+.unbox-3 {
+  width: 135px;
+  height: 60px;
+  color: #ffffff;
+  border: 1px solid rgba(05, 187, 76, 1);
+  background-color: rgba(05, 187, 76, 0.2);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-right: 10px;
+  margin-top: 10px;
+}
+
+.unpaid-3 {
+  display: flex;
+  align-items: center;
+  width: 100%;
+  height: 10px;
+  border-top: 1px solid rgba(05, 187, 76, 1);
+}
+
+.left-3 {
+  width: 35%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(05, 187, 76, 1);
+  font-weight: 600;
+  line-height: 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+
+.unleft-3 {
+  width: 35%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(05, 187, 76, 1);
+  font-weight: 600;
+  line-height: 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+
+.right-3 {
+  width: 69%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(05, 187, 76, 1);
+  line-height: 15px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.unright-3 {
+  width: 69%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(05, 187, 76, 1);
+  line-height: 15px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.box-4 {
+  width: 135px;
+  height: 60px;
+  color: #ffffff;
+  border: 1px solid rgba(75, 85, 174, 1);
+  background-color: rgba(75, 85, 174, 0.05);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-right: 10px;
+  margin-top: 10px;
+  box-shadow: 0px 0px 6px #6876f2;
+}
+
+.unbox-4 {
+  width: 135px;
+  height: 60px;
+  color: #ffffff;
+  border: 1px solid rgba(75, 85, 174, 1);
+  background-color: rgba(75, 85, 174, 0.2);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-right: 10px;
+  margin-top: 10px;
+}
+
+.unpaid-4 {
+  display: flex;
+  align-items: center;
+  width: 100%;
+  height: 10px;
+  border-top: 1px solid rgba(75, 85, 174, 1);
+}
+
+.left-4 {
+  width: 35%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(75, 85, 174, 1);
+  font-weight: 600;
+  line-height: 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+
+.unleft-4 {
+  width: 35%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(75, 85, 174, 1);
+  font-weight: 600;
+  line-height: 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+
+.right-4 {
+  width: 69%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(75, 85, 174, 1);
+  line-height: 15px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.unright-4 {
+  width: 69%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(75, 85, 174, 1);
+  line-height: 15px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+.box-5 {
+  width: 135px;
+  height: 60px;
+  color: #ffffff;
+  border: 1px solid rgba(186, 50, 55, 1);
+  background-color: rgba(186, 50, 55, 0.05);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-right: 10px;
+  margin-top: 10px;
+  box-shadow: 0px 0px 6px #ff1313;
+}
+
+.unbox-5 {
+  width: 135px;
+  height: 60px;
+  color: #ffffff;
+  border: 1px solid rgba(186, 50, 55, 1);
+  background-color: rgba(186, 50, 55, 0.2);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-right: 10px;
+  margin-top: 10px;
+}
+
+
+.unpaid-5 {
+  display: flex;
+  align-items: center;
+  width: 100%;
+  height: 10px;
+  border-top: 1px solid rgba(186, 50, 55, 1);
+}
+
+.left-5 {
+  width: 35%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(186, 50, 55, 1);
+  font-weight: 600;
+  line-height: 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+
+.unleft-5 {
+  width: 35%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(186, 50, 55, 1);
+  font-weight: 600;
+  line-height: 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+
+.right-5 {
+  width: 69%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(186, 50, 55, 1);
+  line-height: 15px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.unright-5 {
+  width: 69%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(186, 50, 55, 1);
+  line-height: 15px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.box-6 {
+  width: 135px;
+  height: 60px;
+  color: #ffffff;
+  border: 1px solid rgba(225, 125, 36, 1);
+  background-color: rgba(225, 125, 36, 0.05);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-right: 10px;
+  margin-top: 10px;
+  box-shadow: 0px 0px 6px #f28627;
+}
+
+.unbox-6 {
+  width: 135px;
+  height: 60px;
+  color: #ffffff;
+  border: 1px solid rgba(225, 125, 36, 1);
+  background-color: rgba(225, 125, 36, 0.2);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-right: 10px;
+  margin-top: 10px;
+}
+
+.unpaid-6 {
+  display: flex;
+  align-items: center;
+  width: 100%;
+  height: 10px;
+  border-top: 1px solid rgba(225, 125, 36, 1);
+}
+
+.left-6 {
+  width: 35%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(225, 125, 36, 1);
+  font-weight: 600;
+  line-height: 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+
+.unleft-6 {
+  width: 35%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(225, 125, 36, 1);
+  font-weight: 600;
+  line-height: 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+
+.right-6 {
+  width: 69%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(225, 125, 36, 1);
+  line-height: 15px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.unright-6 {
+  width: 69%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(225, 125, 36, 1);
+  line-height: 15px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.box-7 {
+  width: 135px;
+  height: 60px;
+  color: #ffffff;
+  border: 1px solid rgba(96, 103, 105, 1);
+  background-color: rgba(96, 103, 105, 0.05);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-right: 10px;
+  margin-top: 10px;
+  box-shadow: 0px 0px 6px #ffffff;
+}
+
+.unbox-7 {
+  width: 135px;
+  height: 60px;
+  color: #ffffff;
+  border: 1px solid rgba(96, 103, 105, 1);
+  background-color: rgba(96, 103, 105, 0.2);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-right: 10px;
+  margin-top: 10px;
+}
+
+.unpaid-7 {
+  display: flex;
+  align-items: center;
+  width: 100%;
+  height: 10px;
+  border-top: 1px solid rgba(96, 103, 105, 1);
+}
+
+.left-7 {
+  width: 35%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(96, 103, 105, 1);
+  font-weight: 600;
+  line-height: 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+
+.unleft-7 {
+  width: 35%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(96, 103, 105, 1);
+  font-weight: 600;
+  line-height: 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+
+.right-7 {
+  width: 69%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(96, 103, 105, 1);
+  line-height: 15px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.unright-7 {
+  width: 69%;
+  height: 100%;
+  font-size: 12px;
+  color: rgba(96, 103, 105, 1);
+  line-height: 15px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+.lock {
+  width: 10px;
+  height: 10px;
+  position: relative;
+  right: 4px;
+}
+
+.lock-on {
+  width: 0px;
+  height: 0px;
+  opacity: 0;
+}
+
+.locks:hover .lock-on {
+  position: fixed;
+  display: flex;
+  align-items: center;
+  width: 80px;
+  height: 30px;
+  border: 1px solid #999999;
+  background-color: #999999;
+  opacity: 1;
+  color: #ffffff;
+  z-index: 999;
+}
+
+.lock_input {
+  width: 140px;
+  background-color: #292929;
+  height: 40px;
+  color: #ffffff;
+}
+</style>

+ 1 - 1
src/components/warning/warningArea.vue

@@ -54,7 +54,7 @@ export default {
         /* margin-top: 12px; */
         margin-bottom: 10px;
         /* width: 570px; */
-        width: 29vw;
+        width: 28vw;
         height: 50px;
         display: flex;
         align-items: center;

+ 194 - 26
src/components/warning/warningCard.vue

@@ -4,7 +4,7 @@
     <el-table
       :data="values"
       class="table"
-      height="20vh"
+      height="19vh"
       :header-cell-style="{
         background: '#000000',
         color: 'rgb(220,220,220)',
@@ -12,12 +12,7 @@
         fontSize: '14px',
         'border-bottom': 'solid 1px black',
       }"
-      :cell-style="{
-        background: 'rgb(30,30,30)',
-        color: 'rgb(220,220,220)',
-        padding: '3px',
-        fontSize: '12px',
-      }"
+      :cell-class-name="setCellClassName"
       @row-dblclick="itemDblclick"
     >
       <el-table-column
@@ -42,7 +37,7 @@
           </span>
         </template>
       </el-table-column>
-      <el-table-column prop="alertText" align="center" label="描述" width="200">
+      <el-table-column prop="alertText" align="center" label="描述" width="160">
       </el-table-column>
       <el-table-column prop="isSelected" align="center" label="确认">
         <template v-slot="scope">
@@ -89,28 +84,30 @@ export default {
   props: {},
   data() {
     return {
-      values: [],
+      values: ["-"],
       dialogVisible: false,
       showSvg: false,
       svgVisible: false,
       svgWeb: "",
+      stationName: "",
       currentWindturbine: {},
+      audio: null,
     };
   },
   methods: {
-    compare(property) {
-      return function (a, b) {
-        var value1 = a[property];
-        var value2 = b[property];
-        if (value1 < value2) {
-          return 1;
-        } else if (value1 > value2) {
-          return -1;
-        } else {
-          return 0;
-        }
-      };
-    },
+    // compare(property) {
+    //   return function (a, b) {
+    //     var value1 = a[property];
+    //     var value2 = b[property];
+    //     if (value1 < value2) {
+    //       return 1;
+    //     } else if (value1 > value2) {
+    //       return -1;
+    //     } else {
+    //       return 0;
+    //     }
+    //   };
+    // },
     initData() {
       let mb = MessageBridge.getInstance();
       let vs = [
@@ -122,27 +119,169 @@ export default {
       mb.register(vs);
     },
     faultMessage(json) {
+      // let val = json ? JSON.parse(json) : this.$store.state.warning;
+      // if (Object.keys(val).length > 0) {
+      //   let sleected = {};
+      //   this.values.forEach((it) => {
+      //     if (it.isSelected) {
+      //       sleected[it.id] = 0;
+      //     }
+      //   });
+      //   let values = [];
+      //   for (let v in val) {
+      //     let vl = val[v];
+      //     if (sleected[vl.id] == 0 && BackgroundData.getInstance().LoginUser) {
+      //       vl.isSelected = true;
+      //     }
+      //     if (vl.category1 !== "GF" && vl.objectId.indexOf("GDC") < 0) {
+      //       values.push(vl);
+      //     }
+      //   }
+      //   this.values = values.sort(this.compare("category1"));
+      // }
       let val = json ? JSON.parse(json) : this.$store.state.warning;
+
       if (Object.keys(val).length > 0) {
+        let syzAlarmArray = this.$store.state.syzAlarmArray || [];
+        val.forEach((ele) => {
+          if (
+            ele.category1 === "SYZ" &&
+            ele.rank === this.$store.state.syzAlarmRank
+          ) {
+            let item = syzAlarmArray.find((findEle) => {
+              return ele.idString === findEle.idString;
+            });
+            if (!item) {
+              ele.soundSource = "syz";
+              ele.isConfirm = false;
+              syzAlarmArray.push(ele);
+            }
+          }
+        });
+
+        this.$store.commit("syzAlarmArray", syzAlarmArray);
+
+        const syzAlarmItem = this.$store.getters.syzAlarmArray.some((ele) => {
+          return (
+            ele.category1 === "SYZ" &&
+            ele.rank === this.$store.state.syzAlarmRank
+          );
+        });
+
+        const syzDialogShow = this.$store.getters.syzAlarmArray.some((ele) => {
+          return !ele.isConfirm;
+        });
+
+        syzDialogShow && this.$store.commit("syzDialogShow", syzDialogShow);
+
+        let syzBtnFlicker = syzAlarmArray.some((ele) => {
+          return ele.rank === this.$store.state.syzAlarmRank;
+        });
+
+        this.$store.commit("syzBtnFlicker", syzBtnFlicker);
+
         let sleected = {};
         this.values.forEach((it) => {
           if (it.isSelected) {
             sleected[it.id] = 0;
           }
         });
-        let values = [];
+        this.values = new Array();
         for (let v in val) {
           let vl = val[v];
+          if (vl.stationId != "QS_FDC" && vl.category1 == "FJ") {
+            vl.alertText = vl.windturbineName + "-" + vl.alertText;
+          }
           if (sleected[vl.id] == 0 && BackgroundData.getInstance().LoginUser) {
             vl.isSelected = true;
           }
           if (vl.category1 !== "GF" && vl.objectId.indexOf("GDC") < 0) {
-            values.push(vl);
+            this.values.push(vl);
           }
         }
-        this.values = values.sort(this.compare("category1"));
+
+        let fjAlarArray = [];
+        let fjDataArray = [];
+
+        this.values.forEach((ele) => {
+          if (ele.category1 === "FJ") {
+            if (ele.rank >= this.$store.state.fjAlarmRank) {
+              fjAlarArray.push(ele);
+            } else {
+              fjDataArray.push(ele);
+            }
+          }
+        });
+
+        if (syzAlarmItem) {
+          this.syzAudioPlay(syzAlarmArray);
+        } else if (!syzAlarmItem && fjAlarArray.length) {
+          this.audioPlay(this.getSound(fjAlarArray[0].soundSource || "wd"));
+        }
+
+        this.values = [].concat(fjAlarArray, fjDataArray);
       }
     },
+    // 返回音频文件路径
+    getSound(fileName) {
+      return `./static/sound/${fileName}.mp3`;
+    },
+
+    // 播放音频
+    audioPlay(audioPath) {
+      this.audio = new Audio(audioPath);
+      this.audio.play();
+    },
+
+    // 升压站报警播放逻辑,因升压站报警声音是否播放牵扯的分支很多,所以单独声明函数处理
+    syzAudioPlay(syzAlarmArray) {
+      let syzArray = this.$base.deepCopy(this.$store.getters.syzArray);
+      syzArray.forEach((pEle) => {
+        pEle.alarmList = [];
+        syzAlarmArray.forEach((cEle) => {
+          if (pEle.id === cEle.stationId) {
+            pEle.alarmList.push(cEle);
+          }
+        });
+      });
+
+      let alarmSoundLock1 = false;
+      let alarmSoundLock2 = false;
+
+      syzArray.forEach((pEle) => {
+        pEle.alarmList.forEach((cEle) => {
+          if (!cEle.isConfirm) {
+            pEle.isMute = false;
+            alarmSoundLock1 = true;
+            if (cEle.stationId === this.$store.state.activeTab) {
+              cEle.isConfirm = true;
+            }
+          }
+        });
+      });
+
+      if (alarmSoundLock1) {
+        this.audioPlay(this.getSound("syz"));
+      } else {
+        for (let i = 0; i < syzArray.length; i++) {
+          if (syzArray[i].alarmList.length) {
+            alarmSoundLock2 = syzArray[i].alarmList.some((ele) => {
+              return (
+                !syzArray[i].isMute &&
+                ele.rank === this.$store.state.syzAlarmRank
+              );
+            });
+          }
+        }
+      }
+      alarmSoundLock2 && this.audioPlay(this.getSound("syz"));
+
+      syzArray.forEach((ele) => {
+        Array.isArray(ele.alarmList) && delete ele.alarmList;
+      });
+      this.$store.commit("syzArray", syzArray);
+    },
+
     /* 行双击 */
     itemDblclick(row) {
       if (row.category1 === "FJ") {
@@ -201,6 +340,13 @@ export default {
           });
         });
     },
+    setCellClassName({ row }) {
+      if (row.rank >= this.$store.state.fjAlarmRank) {
+        return "cellBase flicker";
+      } else {
+        return "cellBase";
+      }
+    },
   },
 };
 </script>
@@ -264,4 +410,26 @@ tr {
   border-collapse: separate;
   border-spacing: 0px 5px;
 }
-</style>
+</style>
+<style lang="less">
+.cellBase {
+  background: rgb(30, 30, 30) !important;
+  color: rgb(220, 220, 220);
+  padding: 3px;
+  font-size: 12px;
+}
+.cellBase.flicker {
+  animation: flicker 0.6s infinite;
+}
+@keyframes flicker {
+  0% {
+    color: rgb(220, 220, 220);
+  }
+  50% {
+    color: orangered;
+  }
+  100% {
+    color: rgb(220, 220, 220);
+  }
+}
+</style>

+ 33 - 0
src/store/index.js

@@ -15,6 +15,15 @@ const store = createStore({
                current: 1,
                faultList: [],
                currentStation: "",
+               syzAlarmArray: [],
+               syzDialogShow: false,
+               syzAlarmRank: "6", // 升压站报警级别, === 此级别会报警
+               fjAlarmRank: "6", // 风机报警级别, >= 此级别会报警
+               currentWarningCardClass: "", // 升压站弹窗右下角表格 class 
+               syzBtnFlicker: false, // 升压站按钮本身是否闪烁以提示有未处理报警
+               // 升压站列表
+               syzArray: [],
+               activeTab: "" // 升压站弹窗所停留的tab页
           }
      },
 
@@ -38,6 +47,12 @@ const store = createStore({
           currentStation(state) {
                return state.currentStation;
           },
+          syzAlarmArray(state) {
+               return state.syzAlarmArray;
+          },
+          syzArray(state) {
+               return state.syzArray;
+          },
      },
 
      // 数据更新 使用: this.$store.commit('函数名','val')
@@ -72,6 +87,24 @@ const store = createStore({
           currentStation(state, data) {
                state.currentStation = data;
           },
+          syzAlarmArray(state, data) {
+               state.syzAlarmArray = data;
+          },
+          syzDialogShow(state, data) {
+               state.syzDialogShow = data;
+          },
+          currentWarningCardClass(state, data) {
+               state.currentWarningCardClass = data;
+          },
+          syzBtnFlicker(state, data) {
+               state.syzBtnFlicker = data;
+          },
+          syzArray(state, data) {
+               state.syzArray = data;
+          },
+          activeTab(state, data) {
+               state.activeTab = data;
+          },
      }
 })
 

+ 1 - 1
src/utils/MessageBridge.js

@@ -20,7 +20,7 @@ export default class MessageBridge {
     this.windFlag = (new Date()).getTime();
     // this.reconnect()
     this.calcSocket = new WebSocket(`ws://${process.env.VUE_APP_APIS}/wisdom_service`, this.onmessage, ["/topic/suggestion", "/topic/sync-command-result", "/topic/fault-count",
-      "/topic/alarm-count", "/topic/fault-popup", "/topic/popup-remove", "/topic/heartbeat-data", "/topic/title-info", "/topic/attention"]);
+      "/topic/alarm-count", "/topic/fault-popup", "/topic/popup-remove", "/topic/heartbeat-data", "/topic/title-info", "/topic/attention","/topic/temperature-count"]);
     this.adapterSocket = new WebSocket(`ws://${process.env.VUE_APP_ADAPTERURLS}/wisdom`, this.onmessage, ["/topic/windturbine", "/topic/pv"]);
   }
 

+ 268 - 0
src/utils/baseTool.js

@@ -0,0 +1,268 @@
+
+let loadingStatus = null;
+
+import { ElMessage } from 'element-plus';
+import { ElLoading } from 'element-plus';
+
+export default {
+  /**
+   * 页面顶部出现消息提示
+   * @param {Object} options 传入一个对象为配置项,其中:
+   * @param {Boolean} showClose 是否显示可手动关闭的 x 于提示框右侧,默认 false
+   * @param {Boolean} center 消息提示内容是否居中,默认 true
+   * @param {String} msg 消息提示的内容
+   * @param {String} type 消息提示的类型,可选值为 ['success(成功)','warning(警告)','error(错误)',或者直接传入空字符串],默认 error
+   */
+  showMsg(options) {
+    
+    ElMessage({
+      showClose: (options.showClose == true || options.showClose == false) ? options.showClose : false,
+      center: (options.center == true || options.center == false) ? options.center : true,
+      message: options.msg,
+      type: (options.type || options.type === '') ? options.type : 'error'
+    });
+  },
+
+  /**
+   * 显示防穿透点击 loading 蒙版
+   * @param {Objectr} opt 传入一个对象为配置项,其中:
+   * @param {String} target 此蒙版需要绑定的 DOM 标签 ID 或者 CLASS 或者 TAGNAME,默认绑在 body 上
+   * @param {Boolean} body 是否插入蒙版至 boyd 上,默认 true
+   * @param {Boolean} fullscreen 蒙版是否全屏蒙住整个 html 页面,默认 true
+   * @param {Boolean} lock 蒙版出现时,是否锁定屏幕滚动,默认 false
+   * @param {String} text 蒙版上显示的提示文本
+   * @param {String} background 蒙版的背景颜色,写死 50% 透明度的纯黑色
+   */
+  showLoading(opt) {
+    let options = opt || {};
+    loadingStatus = ElLoading.service({
+      target: options.target || 'body',
+      body: (options.body == true || options.body == false) ? options.body : false,
+      fullscreen: (options.fullscreen == true || options.fullscreen == false) ? options.fullscreen : true,
+      lock: (options.lock == true || options.lock == false) ? options.lock : false,
+      text: options.text || '请稍等...',
+      background: 'rgba(0,0,0,.5)',
+    });
+  },
+
+  /**
+   * 获取标签上的自定义属性
+   * @param {any} node 传入 字符串 或 标准DOM对象 或 jQuery DOM对象 ,函数自动判断传入的类型并返回其 dataset 属性。
+   */
+  getCurrentData(node) {
+    // 如果传入的是 jQuery 对象
+    if (window.jQuery && node instanceof jQuery) {
+      return node[0].dataset;
+    } else {
+      // 判断传入的是否是标准 DOM 对象
+      let isDom = (typeof node === 'object') ?
+        function (obj) {
+          return obj instanceof HTMLElement;
+        } :
+        function (obj) {
+          return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
+        };
+
+      // 如果是标准 DOM 对象,输出 dataset
+      if (isDom(node)) {
+        return node.dataset;
+      } else {
+        // 如果是不是,则表示传入的是字符串,根据字符串取 DOM 后输出 dataset
+        let dom = document.querySelector(node);
+        return dom.dataset;
+      }
+    }
+  },
+
+  /**
+   * 关闭loading
+   */
+  closeLoading() {
+    loadingStatus.close();
+  },
+
+  /**
+   * 深拷贝 json 数组
+   * @param {Array} jsonArray 传入 Json 数组,返回一个指向新指针拷贝份数据
+   */
+  deepCopy(jsonArray) {
+    return JSON.parse(JSON.stringify(jsonArray));
+  },
+
+  /**
+   * 根据后端返回的 ID 遍历树形结构包装组件编辑用数据函数
+   * @param {String} key 需要找到的 ID
+   * @param {Array} treeData 树形 Array
+   */
+  getTreeDeepArr(key, treeData) {
+
+    let arr = []; // 在递归时操作的数组
+    let returnArr = []; // 存放结果的数组
+    let depth = 0; // 定义全局层级
+
+    // 定义递归函数
+    function childrenEach(childrenData, depthN) {
+
+      for (var j = 0; j < childrenData.length; j++) {
+
+        depth = depthN; // 将执行的层级赋值 到 全局层级
+        arr[depthN] = (childrenData[j].id);
+
+        if (childrenData[j].id == key) {
+
+          returnArr = arr.slice(0, depthN + 1); //将目前匹配的数组,截断并保存到结果数组
+          break;
+
+        } else {
+
+          if (childrenData[j].children) {
+
+            depth++;
+            childrenEach(childrenData[j].children, depth);
+
+          }
+
+        }
+
+      }
+
+      return returnArr;
+
+    }
+
+    return childrenEach(treeData, depth);
+
+  },
+
+  /**
+   * 获取数据的类型
+   * @param {any} options 传入一个数据,返回其类型 (object, array, string, number等)
+   */
+  getType(options) {
+    return Object.prototype.toString.call(options).slice(8, Object.prototype.toString.call(options).length - 1).toLowerCase();
+  },
+
+  /**
+   * 控制页面滚动到指定位置
+   * @param {Object} options 传入一个配置项,其中:
+   * @param {String} el 需要滚动的 DOM 元素选择器,可以为 CLASS 或 ID
+   * @param {Number} scrollTop 需要滚动到顶部的位置,数值越低滚动的越靠近顶部,默认 0
+   * @param {Number} scrollLeft 需要滚动到顶部的位置,数值越低滚动的越靠近顶部,默认 0
+   * @param {Number} speed 滚动到指定位置需要的时间 (动画时间),默认 200
+   * @param {Function} success 滚动执行完毕后的回调函数
+   */
+  scrollTo(options) {
+    if (!options || !options.el) {
+      this.showMsg({
+        msg: 'scrollTo() 方法需要传入 el 属性'
+      });
+      return;
+    }
+    if ($(options.el)[0] && ($(options.el)[0].scrollHeight > (window.innerHeight || document.documentElement.clientHeight))) {
+      $(options.el).animate({
+        scrollTop: options.scrollTop || 0,
+        scrollLeft: options.scrollLeft || 0,
+      }, options.speed || 200, () => {
+        options.success && options.success();
+      });
+    } else {
+      options.success && options.success();
+    }
+  },
+
+  /**
+   * JS 触发全屏功能
+   */
+  requestFullscreen() {
+    //全屏
+    const docElm = document.documentElement;
+    //W3C
+    if (docElm.requestFullscreen) {
+      docElm.requestFullscreen();
+    }
+
+    //FireFox
+    else if (docElm.mozRequestFullScreen) {
+      docElm.mozRequestFullScreen();
+    }
+
+    //Chrome等
+    else if (docElm.webkitRequestFullScreen) {
+      docElm.webkitRequestFullScreen();
+    }
+
+    //IE11
+    else if (docElm.msRequestFullscreen) {
+      docElm.msRequestFullscreen();
+    }
+  },
+
+  /**
+   * 颜色进制转换  16 <--> 10 互转
+   * @param {String} colorStr 传入一个颜色字符串, 16进制 或者 10进制 ,返回转换后的结果,例:传入 #1890ff ,返回 rgb(24, 144, 255),反之亦然
+   */
+  replaceColor(colorStr) {
+    if (!colorStr) return '';
+
+    let colorString = colorStr.replace(/#|rgb|\(|\)|\|;|\s+/g, "");
+
+    if (colorString.indexOf(",") === -1) {
+      let color10 = [];
+      for (let i = 0; i < colorString.length; i++) {
+        if (!((i + 1) % 2)) {
+          color10.push(parseInt((colorString[i - 1] + colorString[i]), 16));
+        }
+      }
+      return "rgb(" + color10.toString() + ")";
+    } else {
+      let colorArray = colorString.split(',');
+      let color16 = '';
+      colorArray.forEach(ele => {
+        color16 += (parseInt(ele).toString(16));
+      });
+      return "#" + color16;
+    }
+  },
+
+  /**
+   * 生成指定范围内的随机数
+   * @param {Int} minNum 范围下限
+   * @param {Int} maxNum 范围上限
+   * @returns 
+   */
+  randomNum(minNum, maxNum) {
+    switch (arguments.length) {
+      case 1:
+        return parseInt(Math.random() * minNum + 1, 10);
+      case 2:
+        return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
+      default:
+        return 0;
+    }
+  },
+
+  // 正则表达式
+  regs: {
+    // 是否为手机号
+    isPhone: /^1(3|4|5|6|7|8|9)\d{9}$/,
+    // 是否为合法 15 或 18 位身份证号
+    isIdentityCard: /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/,
+    // 是否是邮箱
+    isMail: /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/,
+    // 是否是数字
+    isNumber: /^(-?\d+)(\.\d+)?$/
+  },
+
+  // elementUI 自定义表单效验规则
+  elCkeck: {
+    isNumber(rule, value, callback) {
+      if (value === '') {
+        callback(new Error('该值不可为空'));
+      } else if (!/^(-?\d+)(\.\d+)?$/.test(value)) {
+        callback(new Error('输入有误,仅支持输入数字'));
+      } else {
+        callback();
+      }
+    }
+  }
+}

+ 9 - 0
src/utils/data.js

@@ -0,0 +1,9 @@
+
+const get = name => {
+    let json = require(`@/assets/dataService/${name}.json`);
+    return json;
+}
+
+export default {
+    get
+}

文件差异内容过多而无法显示
+ 15241 - 0
src/utils/fault.json


+ 26 - 0
src/utils/partten.js

@@ -0,0 +1,26 @@
+// Color 常量
+const color = [
+    { key: "green", value: "#05BB4C" },
+    { key: "yellow", value: "#F8DE5B" },
+    { key: "gray", value: "#606769" },
+    { key: "grayl", value: "#B3BDC0" },
+    { key: "purple", value: "#4B55AE" },
+    { key: "orange", value: "#e17e23" },
+    { key: "blue", value: "#1a93cf" },
+    { key: "red", value: "#BA3237" },
+    { key: "pink", value: "#c531c7" },
+	{ key: "cyan", value: "#1cbbb4" },
+	{ key: "brown", value: "#a5673f" },
+	{ key: "mauve", value: "#9c26b0" },
+	{ key: "deepblue", value: "#36348e" },
+];
+
+function getColor(key) {
+	if(!color.some(ele=>{ return ele.key === key })) key = "green";
+    return color.find((t) => { return t.key == key }).value;
+}
+
+export default {
+    color,
+    getColor
+}

+ 16 - 5
src/utils/request.js

@@ -1,5 +1,6 @@
 import axios from "axios";
 import store from '../store/index'
+// import JSONbig from 'json-bigint'
 // import { getToken } from "@/utils/storage";
 const service = axios.create();
 service.defaults.timeout = 50000;
@@ -7,9 +8,18 @@ service.defaults.baseURL = `${process.env.VUE_APP_API}`
 service.interceptors.request.use(
 	config => {
 		config.headers = {
-            // 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
-            Authorization: store.state.token,
-        }
+			// 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
+			Authorization: store.state.token,
+		}
+		// config.transformResponse =  [
+		// 	function (data) {
+		// 		const json = JSONbig({
+		// 			storeAsString: true
+		// 		})
+		// 		const res = json.parse(data)
+		// 		return res
+		// 	}
+		// ]
 		return config;
 	},
 	error => {
@@ -31,19 +41,20 @@ service.interceptors.response.use(
 			// } else {
 			// 	return false;
 			// }
-			return response ;
+			return response;
 		} else {
 			// tips[data.code](data);
 			return false;
 		}
 	},
 	error => {
+		console.log(error);
 		// 处理错误并给出相应的错误处理
 		if (error.response) {
 			// const { status } = error.response;
 			// tips[status](error);
 			return error.response.data
-		}else{
+		} else {
 			return false;
 		}
 	}

+ 44 - 0
src/utils/util.js

@@ -0,0 +1,44 @@
+
+// 新建GUID
+const newGUID = () => {
+    let d = new Date().getTime();
+    let uid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
+        let r = (d + Math.random() * 16) % 16 | 0;
+        d = Math.floor(d / 16);
+        return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
+    });
+    return uid;
+}
+
+const copy = (obj) => {
+    return JSON.parse(JSON.stringify(obj));
+}
+
+const getGeoJson = (name, dataName) => {
+    const dataDefault = require('@/utils/data.js');
+    const dataService = dataDefault.default;
+    const region = dataService.get(dataName);
+    return {
+        type: "Feature",
+        geometry: {
+            type: "MultiPolygon",
+            coordinates: region
+        },
+        properties: {
+            name: name
+        }
+    }
+}
+
+
+// px to vh
+const vh = function (px) {
+    return window.innerHeight * px / 1080;
+}
+
+export default {
+    newGUID,
+    copy,
+    getGeoJson,
+    vh
+}

文件差异内容过多而无法显示
+ 35447 - 0
src/utils/yujing.json


+ 1 - 0
src/views/CenterPage.vue

@@ -94,5 +94,6 @@
 	.homePage {
 		height: 87%;
 		z-index: 2;
+		margin-left: 45px;
 	}
 </style>

+ 1 - 0
src/views/ManualPage.vue

@@ -82,5 +82,6 @@
 <style scoped>
     .homePage {
         height: 87%;
+        margin-left: 45px;
     }
 </style>

+ 234 - 0
src/views/Menu.vue

@@ -0,0 +1,234 @@
+<template>
+  <div class="menu">
+    <div
+      :class="item.id === 7 ? !lockMaskDisplay?'menu-item' :'menu-onItem': item.id === current?'menu-onItem': 'menu-item'"
+      v-for="(item, index) in menuList"
+      :key="index"
+      @click="handleChange(item.id)"
+      @mouseleave="leave(item.id)"
+      @mouseenter="hovers(item.id)"
+    >
+      <img
+        :class="item.id !== 7 ? 'muen-icon' : 'muen-lock'"
+        :src="item.src"
+        alt=""
+      />
+      <div v-if="item.id === 3" class="num">{{ temperatureNum }}</div>
+    </div>
+    <div
+      v-if="display"
+      class="menu-group"
+      @mouseleave="leave()"
+      @mouseenter="hovers(6)"
+    >
+      <div class="content" @click="handleSearch(6, 'fault')">报警/故障查询</div>
+      <div class="content" @click="handleSearch(6, 'warning')">预警查询</div>
+      <div class="content" @click="handleSearch(6, 'status')">状态时间查询</div>
+      <div class="content-end" @click="handleSearch(6, 'action')">动作查询</div>
+    </div>
+  </div>
+
+  <!-- <el-menu
+    default-active="1-4-1"
+    class="el-menu-vertical-demo"
+    @open="handleOpen"
+    @close="handleClose"
+    :collapse="isCollapse"
+  >
+    <el-menu-item v-for="(item, index) in menuList" :key="index" :index="item.id">
+      <img class="muen-icon" :src="item.src" alt="" />
+    </el-menu-item>
+  </el-menu> -->
+</template>
+<script>
+import homePage from "../assets/img/menu/homePage.png";
+import matrix from "../assets/img/menu/matrix.png";
+import booster from "../assets/img/menu/booster.png";
+import agc from "../assets/img/menu/agc.png";
+import search from "../assets/img/menu/search.png";
+import lock from "../assets/img/menu/lock.png";
+import voice from "../assets/img/menu/voice.png";
+import screenshot from "../assets/img/menu/screenshot.png";
+import set from "../assets/img/menu/set.png";
+
+export default {
+  props: {
+    temperatureNum: {
+      type: Number,
+      default: 0,
+    },
+    lockMaskDisplay: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  components: {
+    // AGCDetails,
+    // SYZDetails,
+    // AllMatrices,
+  },
+  data() {
+    return {
+      display: false,
+      current: 1,
+      menuList: [
+        {
+          id: 1,
+          src: homePage,
+        },
+        {
+          id: 2,
+          src: matrix,
+        },
+        {
+          id: 3,
+          src: matrix,
+        },
+        {
+          id: 4,
+          src: booster,
+        },
+        {
+          id: 5,
+          src: agc,
+        },
+        {
+          id: 6,
+          src: search,
+        },
+        {
+          id: 7,
+          src: lock,
+        },
+        {
+          id: 8,
+          src: voice,
+        },
+        {
+          id: 9,
+          src: screenshot,
+        },
+        {
+          id: 10,
+          src: set,
+        },
+      ],
+    };
+  },
+  methods: {
+    handleChange(val) {
+      if (!this.lockMaskDisplay || val === 7) {
+        if(val === 9){
+          this.$emit("handleChange", val);
+        }else if (val !== 6) {
+          this.current = val;
+          this.$emit("fhandleChange", val);
+        }
+      }
+    },
+    handleSearch(val, msg) {
+      this.current = val;
+      this.$emit("handleSearch", msg);
+    },
+    hovers(id) {
+      if (!this.lockMaskDisplay || id === 7) {
+        if (id === 6) {
+          this.display = true;
+        } else {
+          this.display = false;
+        }
+      }
+    },
+    leave() {
+      this.display = false;
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.menu {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-top: 20px;
+}
+.menu-item {
+  width: 33px;
+  height: 33px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-top: 10px;
+}
+.menu-onItem {
+  width: 33px;
+  height: 33px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: #000000;
+  margin-top: 10px;
+}
+.muen-icon {
+  width: 20px;
+  height: 20px;
+}
+.muen-lock {
+  width: 20px;
+  height: 20px;
+  z-index: 9999;
+}
+.num {
+  background-color: #e4503f;
+  width: 18px;
+  height: 18px;
+  border-radius: 50%;
+  font-size: 10px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: absolute;
+  color: #ffffff;
+  right: 0px;
+  margin-top: 17px;
+}
+.menu-group {
+  z-index: 9999;
+  width: 170px;
+  //   height: 100px;
+  background-color: #242424;
+  position: absolute;
+  top: 240px;
+  left: 37px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+.content {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: #242424;
+  color: #ffffff;
+  width: 100%;
+  height: 30px;
+  margin-top: 5px;
+}
+.content-end {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: #242424;
+  color: #ffffff;
+  width: 100%;
+  height: 30px;
+  margin-top: 5px;
+  margin-bottom: 10px;
+}
+.content:hover {
+  color: #2574db;
+}
+.content-end:hover {
+  color: #2574db;
+}
+</style>

+ 2 - 2
src/views/StatusBar.vue

@@ -6,9 +6,9 @@
         <div class="Bbox">
           <span style="color: white; margin-left: 20px">系统时间:</span>
           <span style="color: white">{{ currentTime }}</span>
-          <div class="bottom-right" @click="block">
+          <!-- <div class="bottom-right" @click="block">
             <span>新增报警数量</span>
-          </div>
+          </div> -->
         </div>
       </el-col>
 

+ 1 - 1
src/views/TitleBar.vue

@@ -36,7 +36,7 @@
           </el-dialog>
         </div>
       </el-col>
-      <el-col :span="19" style="margin-left: 60px;">
+      <el-col :span="19" style="margin-left: 23px;">
         <div class="titleinfoall">
           <div class="titleinfo" @dblclick="dbClicks(titleInfo.dailyPowerGeneration,'日发电量')">
             <ul>