浏览代码

初始化项目

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 2 月之前
当前提交
41107da943
共有 100 个文件被更改,包括 94803 次插入0 次删除
  1. 0 0
      .env
  2. 8 0
      .env.development
  3. 4 0
      .env.eapi
  4. 10 0
      .env.production
  5. 31 0
      .gitignore
  6. 19 0
      README.md
  7. 5 0
      babel.config.js
  8. 16356 0
      package-lock.json
  9. 48 0
      package.json
  10. 二进制
      public/favicon.ico
  11. 二进制
      public/img/icons/android-chrome-192x192.png
  12. 二进制
      public/img/icons/android-chrome-512x512.png
  13. 二进制
      public/img/icons/android-chrome-maskable-192x192.png
  14. 二进制
      public/img/icons/android-chrome-maskable-512x512.png
  15. 二进制
      public/img/icons/apple-touch-icon-120x120.png
  16. 二进制
      public/img/icons/apple-touch-icon-152x152.png
  17. 二进制
      public/img/icons/apple-touch-icon-180x180.png
  18. 二进制
      public/img/icons/apple-touch-icon-60x60.png
  19. 二进制
      public/img/icons/apple-touch-icon-76x76.png
  20. 二进制
      public/img/icons/apple-touch-icon.png
  21. 二进制
      public/img/icons/favicon-16x16.png
  22. 二进制
      public/img/icons/favicon-32x32.png
  23. 二进制
      public/img/icons/msapplication-icon-144x144.png
  24. 二进制
      public/img/icons/mstile-150x150.png
  25. 3 0
      public/img/icons/safari-pinned-tab.svg
  26. 17 0
      public/index.html
  27. 2 0
      public/robots.txt
  28. 二进制
      public/static/sound/syz.mp3
  29. 二进制
      public/static/sound/track.mp3
  30. 二进制
      public/static/sound/wd.mp3
  31. 3 0
      public/static/sound/音频说明.txt
  32. 186 0
      src/App.vue
  33. 206 0
      src/api/index.js
  34. 二进制
      src/assets/img/LabelArea/flag.png
  35. 二进制
      src/assets/img/RecommendedArea/background.png
  36. 二进制
      src/assets/img/RecommendedArea/guznzhu_bg_01.png
  37. 二进制
      src/assets/img/WindturbineDetailPages/green.png
  38. 二进制
      src/assets/img/WindturbineDetailPages/pic_01.png
  39. 二进制
      src/assets/img/WindturbineDetailPages/red.png
  40. 二进制
      src/assets/img/WindturbineDetailPages/偏航.png
  41. 二进制
      src/assets/img/WindturbineDetailPages/发电机.png
  42. 二进制
      src/assets/img/WindturbineDetailPages/变桨.png
  43. 二进制
      src/assets/img/WindturbineDetailPages/机舱.png
  44. 二进制
      src/assets/img/WindturbineDetailPages/液压.png
  45. 二进制
      src/assets/img/WindturbineDetailPages/齿轮箱.png
  46. 二进制
      src/assets/img/controlcenter/background_ACB.png
  47. 二进制
      src/assets/img/controlcenter/background_ACR.png
  48. 二进制
      src/assets/img/controlcenter/center_ACB.png
  49. 二进制
      src/assets/img/controlcenter/center_ACR.png
  50. 二进制
      src/assets/img/controlcenter/daraTrue.png
  51. 二进制
      src/assets/img/controlcenter/dataFalse.png
  52. 二进制
      src/assets/img/controlcenter/decoration01.png
  53. 二进制
      src/assets/img/controlcenter/decoration02.png
  54. 二进制
      src/assets/img/logo.ico
  55. 二进制
      src/assets/img/logo.png
  56. 二进制
      src/assets/img/logo2.ico
  57. 二进制
      src/assets/img/main_window/logo.png
  58. 二进制
      src/assets/img/statusbar/accident.png
  59. 二进制
      src/assets/img/statusbar/background.png
  60. 二进制
      src/assets/img/statusbar/background_alarm.png
  61. 二进制
      src/assets/img/statusbar/defect.png
  62. 二进制
      src/assets/img/statusbar/hidden_danger.png
  63. 二进制
      src/assets/img/statusbar/malfunction.png
  64. 二进制
      src/assets/img/type/down.png
  65. 二进制
      src/assets/img/type/electricityRestrictions.png
  66. 二进制
      src/assets/img/type/lock.png
  67. 二进制
      src/assets/img/type/none.png
  68. 二进制
      src/assets/img/type/up.png
  69. 二进制
      src/assets/sound/Track52.mp3
  70. 116 0
      src/assets/styles/main.css
  71. 86 0
      src/background.js
  72. 1253 0
      src/components/BasicInformationDetail.vue
  73. 5930 0
      src/components/BoosterStation/dwk.vue
  74. 4944 0
      src/components/BoosterStation/hzj.vue
  75. 2844 0
      src/components/BoosterStation/mch.vue
  76. 9139 0
      src/components/BoosterStation/mhs.vue
  77. 5432 0
      src/components/BoosterStation/nss.vue
  78. 5304 0
      src/components/BoosterStation/pl1.vue
  79. 3617 0
      src/components/BoosterStation/pl2.vue
  80. 722 0
      src/components/BoosterStation/previewPicture.vue
  81. 4050 0
      src/components/BoosterStation/qs.vue
  82. 2502 0
      src/components/BoosterStation/sbdl.vue
  83. 4403 0
      src/components/BoosterStation/sbq.vue
  84. 12163 0
      src/components/BoosterStation/xh.vue
  85. 10411 0
      src/components/BoosterStation/xs.vue
  86. 431 0
      src/components/StandAloneImg.vue
  87. 40 0
      src/components/TitleBarCard.vue
  88. 252 0
      src/components/WindturbineDetailPages.vue
  89. 730 0
      src/components/areaCard.vue
  90. 438 0
      src/components/basicDataDetails.vue
  91. 180 0
      src/components/boxSelect.vue
  92. 186 0
      src/components/check/areaCard.vue
  93. 33 0
      src/components/check/checkArea.vue
  94. 393 0
      src/components/check/operationRecords.vue
  95. 972 0
      src/components/control/areaCard.vue
  96. 877 0
      src/components/control/controlAllArea.vue
  97. 48 0
      src/components/control/controlArea.vue
  98. 145 0
      src/components/dataDetails.vue
  99. 264 0
      src/components/focus/PhotoelectricDetailPages.vue
  100. 0 0
      src/components/focus/agcDetails.vue

+ 0 - 0
.env


+ 8 - 0
.env.development

@@ -0,0 +1,8 @@
+VUE_APP_API=http://192.168.10.18:8099
+VUE_APP_WARNING=http://192.168.10.18:8070
+VUE_APP_SHARDINGURL=http://192.168.10.18:8075
+VUE_APP_ADAPTERURL=http://192.168.10.18:8011
+VUE_APP_APIS=192.168.10.18:8099
+VUE_APP_SHARDINGURLS=192.168.10.18:8075
+VUE_APP_ADAPTERURLS=192.168.10.18:8011
+VUE_APP_WARNINGS=92.168.10.18:8070

+ 4 - 0
.env.eapi

@@ -0,0 +1,4 @@
+NODE_ENV=eapi
+VUE_APP_API=https://eapi.nxgqt.org
+VUE_APP_IMAGE=https://eapi.nxgqt.org
+VUE_APP_MAP_KEY=df6LUP4BcbGgSGjZLf8sOBSB6a0fktrb

+ 10 - 0
.env.production

@@ -0,0 +1,10 @@
+# VUE_APP_API=http://18.6.30.53:8075
+# VUE_APP_IMAGE=http://18.6.30.53:8075
+VUE_APP_API=http://18.6.30.63:8099
+VUE_APP_WARNING=http://18.6.30.63:8070
+VUE_APP_SHARDINGURL=http://18.6.30.53:8075
+VUE_APP_ADAPTERURL=http://18.6.30.63:8011
+VUE_APP_APIS=18.6.30.63:8099
+VUE_APP_SHARDINGURLS=18.6.30.53:8075
+VUE_APP_ADAPTERURLS=18.6.30.63:8011
+VUE_APP_WARNINGS=18.6.30.63:8070

+ 31 - 0
.gitignore

@@ -0,0 +1,31 @@
+.DS_Store
+node_modules
+/dist
+
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+#Electron-builder output
+/dist_electron
+
+#压缩包
+*.zip
+*.rar
+*.7z

+ 19 - 0
README.md

@@ -0,0 +1,19 @@
+# newneic
+
+## Project setup
+```
+npm install
+```
+
+### Compiles and hot-reloads for development
+```
+npm run serve
+```
+
+### Compiles and minifies for production
+```
+npm run build
+```
+
+### Customize configuration
+See [Configuration Reference](https://cli.vuejs.org/config/).

+ 5 - 0
babel.config.js

@@ -0,0 +1,5 @@
+module.exports = {
+  presets: [
+    '@vue/cli-plugin-babel/preset'
+  ]
+}

文件差异内容过多而无法显示
+ 16356 - 0
package-lock.json


+ 48 - 0
package.json

@@ -0,0 +1,48 @@
+{
+  "name": "newneic",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "eb": "vue-cli-service electron:build",
+    "es": "vue-cli-service electron:serve",
+    "postinstall": "electron-builder install-app-deps",
+    "postuninstall": "electron-builder install-app-deps"
+  },
+  "main": "background.js",
+  "dependencies": {
+    "axios": "^0.21.1",
+    "core-js": "^3.6.5",
+    "dayjs": "^1.10.6",
+    "echarts": "^5.1.2",
+    "element-plus": "^1.0.2-beta.55",
+    "element-ui": "^2.15.3",
+    "register-service-worker": "^1.7.1",
+    "stompjs": "^2.3.3",
+    "vue": "^3.0.0",
+    "vue-router": "^4.0.0-0",
+    "vuex": "^4.0.0-0",
+    "xlsx": "^0.17.1"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "~4.5.0",
+    "@vue/cli-plugin-pwa": "~4.5.0",
+    "@vue/cli-plugin-router": "~4.5.0",
+    "@vue/cli-plugin-vuex": "~4.5.0",
+    "@vue/cli-service": "~4.5.0",
+    "@vue/compiler-sfc": "^3.0.0",
+    "electron": "^13.0.0",
+    "electron-devtools-installer": "^3.1.0",
+    "less": "^3.0.4",
+    "less-loader": "^5.0.0",
+    "node-sass": "^4.12.0",
+    "sass-loader": "^8.0.2",
+    "vue-cli-plugin-electron-builder": "~2.1.1"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not dead"
+  ]
+}

二进制
public/favicon.ico


二进制
public/img/icons/android-chrome-192x192.png


二进制
public/img/icons/android-chrome-512x512.png


二进制
public/img/icons/android-chrome-maskable-192x192.png


二进制
public/img/icons/android-chrome-maskable-512x512.png


二进制
public/img/icons/apple-touch-icon-120x120.png


二进制
public/img/icons/apple-touch-icon-152x152.png


二进制
public/img/icons/apple-touch-icon-180x180.png


二进制
public/img/icons/apple-touch-icon-60x60.png


二进制
public/img/icons/apple-touch-icon-76x76.png


二进制
public/img/icons/apple-touch-icon.png


二进制
public/img/icons/favicon-16x16.png


二进制
public/img/icons/favicon-32x32.png


二进制
public/img/icons/msapplication-icon-144x144.png


二进制
public/img/icons/mstile-150x150.png


+ 3 - 0
public/img/icons/safari-pinned-tab.svg

@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M8.00251 14.9297L0 1.07422H6.14651L8.00251 4.27503L9.84583 1.07422H16L8.00251 14.9297Z" fill="black"/>
+</svg>

+ 17 - 0
public/index.html

@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <title><%= htmlWebpackPlugin.options.title %></title>
+  </head>
+  <body>
+    <noscript>
+      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+    </noscript>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

+ 2 - 0
public/robots.txt

@@ -0,0 +1,2 @@
+User-agent: *
+Disallow:

二进制
public/static/sound/syz.mp3


二进制
public/static/sound/track.mp3


二进制
public/static/sound/wd.mp3


+ 3 - 0
public/static/sound/音频说明.txt

@@ -0,0 +1,3 @@
+track.mp3 - 测试用音频
+syz.mp3 - 升压站报警音频
+wd.mp3 - 温度报警音频

+ 186 - 0
src/App.vue

@@ -0,0 +1,186 @@
+<template class="app">
+  <div :class="$store.state.showWarningMask ? 'warningMask' : ''"></div>
+  <TitleBar class="titleBar" />
+  <div class="right">
+    <el-col>
+      <el-row>
+        <el-col>
+          <ModeControl
+            ref="modeControl"
+            :current="current"
+            @clicks="handleClick"
+          ></ModeControl>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col>
+          <FocusArea />
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col>
+          <WarningArea></WarningArea>
+        </el-col>
+      </el-row>
+    </el-col>
+  </div>
+  <StatusBar class="statusBar" />
+  <router-view />
+</template>
+<script>
+import TitleBar from "views/TitleBar.vue";
+import StatusBar from "views/StatusBar.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";
+
+export default {
+  components: {
+    TitleBar,
+    StatusBar,
+    ModeControl,
+    FocusArea,
+    WarningArea,
+  },
+  created() {
+    this.initData();
+    this.subscribe();
+  },
+  methods: {
+    initData() {
+      let mb = MessageBridge.getInstance();
+      let windturbine = [
+        { key: "/topic/windturbine", action: this.windturbineMessage },
+      ];
+      let popup = [{ key: "/topic/fault-popup", action: this.faultMessage }];
+      let title = [{ key: "/topic/title-info", action: this.titleInfos }];
+      // var heartbeat = [{ key: "/topic/heartbeat-data", action: this.heartbeat }];
+      // mb.register(heartbeat);
+      mb.register(title);
+      mb.register(windturbine);
+      mb.register(popup);
+    },
+    windturbineMessage(msg) {
+      let json = JSON.parse(msg);
+      this.$store.commit("windturbinelist", json);
+    },
+    faultMessage(msg) {
+      let json = JSON.parse(msg);
+      this.$store.commit("warning", json);
+    },
+    // heartbeat(msg){
+    //   console.log(msg);
+    // },
+    subscribe() {
+      setTimeout(() => {
+        this.subscribe();
+      }, 20000);
+      if (!this.$store.state.observers) {
+        let mb = MessageBridge.getInstance();
+        let windturbine = [
+          { key: "/topic/windturbine", action: this.windturbineMessage },
+        ];
+        let popup = [{ key: "/topic/fault-popup", action: this.faultMessage }];
+        let title = [{ key: "/topic/title-info", action: this.titleInfos }];
+        let suggestion = [
+          { key: "/topic/suggestion", action: this.suggestion },
+        ];
+        mb.register(suggestion);
+        mb.register(title);
+        mb.register(windturbine);
+        mb.register(popup);
+        this.$store.commit("observers", true);
+      }
+    },
+  },
+};
+</script>
+<style>
+@import "../src/assets/styles/main.css";
+body {
+  /* 设置内容不可选中 */
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+}
+
+/* .app{
+    background-color: #000000;
+  } */
+.right {
+  width: 32%;
+  position: absolute;
+  right: 20px;
+  z-index: 99;
+}
+
+.statusBar {
+  width: 100%;
+  position: absolute;
+  bottom: 0;
+  left: 0;
+}
+
+.titleBar {
+  width: 100%;
+  position: relative;
+  top: 0;
+  left: 0;
+}
+.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 {
+  .currentScroll::-webkit-scrollbar {
+    width: 8px;
+    height: 0px;
+    background-color: black;
+  }
+
+  .currentScroll::-webkit-scrollbar-thumb {
+    background-color: #292929;
+    border-radius: 6px;
+  }
+}
+</style>

+ 206 - 0
src/api/index.js

@@ -0,0 +1,206 @@
+import request from "../utils/request";
+//登陆
+const login = (data) => {
+    return request({
+        baseURL:process.env.VUE_APP_API,
+        url: `/user/login`,
+        method: "post",
+        data:data,
+    });
+};
+//刷新报警信息
+const getSnap = (data) => {
+    return request({
+        baseURL:process.env.VUE_APP_SHARDINGURL,
+        url: `/alarm/snap/page?pagenum=${data.pagenum}&pagesize=${data.pagesize}&category1=${data.category1}&isopened=${data.isopened}&starttime=${data.starttime}&endtime=${data.endtime}`,
+        method: "get",
+    });
+};
+//数据刷新
+const refreshData = (keys) => {
+    return request({
+        baseURL:process.env.VUE_APP_ADAPTERURL,
+        url: `/ts/latest?keys=${keys}`,
+        method: "get",
+    });
+};
+//风机控制
+const windturbControl = (pairs) => {
+    return request({
+        baseURL:process.env.VUE_APP_API,
+        url: `/api/control/`,
+        method: "post",
+        data:pairs
+    });
+};
+//风机控制
+const windturbControlLock = (pairs) => {
+    return request({
+        baseURL:process.env.VUE_APP_API,
+        url: `/api/control/lock`,
+        method: "post",
+        data:pairs
+    });
+};
+//获取风机详情页面数据
+const nitWinturbineBaseData = (data) => {
+    return request({
+        baseURL:process.env.VUE_APP_ADAPTERURL,
+        url: `/ts/latest?thingType=${data.thingType}&thingId=${data.thingId}&uniformCodes=${data.uniformCodes}`,
+        method: "get",
+    });
+};
+const getOverview = (data) => {
+    return request({
+        baseURL:process.env.VUE_APP_API,
+        url: `/api/windturbine/overview`,
+        method: "get",
+    });
+};
+const sendWarning = (data) => {
+    return request({
+        baseURL:process.env.VUE_APP_API,
+        url: `/alarm/confirm?snapID=${data.snapID}&faultID=${data.faultID}&userName=${data.userName}`,
+        method: "get",
+    });
+};
+const sendRecommend = (data) => {
+    return request({
+        baseURL:process.env.VUE_APP_API,
+        url: `api/voice-control/addvoicetask`,
+        method: "post",
+        data:data
+    });
+};
+const getPower = (data) => {
+    return request({
+        baseURL:process.env.VUE_APP_ADAPTERURL,
+        url: `/ts/history/snap?tagName=${data.tagName}&startTs=${data.startTs}&endTs=${data.endTs}&interval=${data.interval}`,
+        method: "get",
+    });
+};
+const getOriginalPower = (data) => {
+    return request({
+        baseURL:process.env.VUE_APP_ADAPTERURL,
+        url: `/ts/history/raw?tagName=${data.tagName}&startTs=${data.startTs}&endTs=${data.endTs}`,
+        method: "get",
+    });
+};
+const getWindturbinePower = (data) => {
+    return request({
+        baseURL:process.env.VUE_APP_ADAPTERURL,
+        url: `/ts/history/snap?thingId=${data.thingId}&uniformCode=${data.uniformCode}&startTs=${data.startTs}&endTs=${data.endTs}&thingType=${data.thingType}&interval=${data.interval}`,
+        method: "get",
+    });
+};
+const getOriginalWindturbinePower = (data) => {
+    return request({
+        baseURL:process.env.VUE_APP_ADAPTERURL,
+        url: `/ts/history/raw?thingId=${data.thingId}&uniformCode=${data.uniformCode}&startTs=${data.startTs}&endTs=${data.endTs}&thingType=${data.thingType}`,
+        method: "get",
+    });
+};
+const getWindWarning = (data,pageIndex,pageSize) => {
+    return request({
+        baseURL:process.env.VUE_APP_API,
+        url: `/alarm/real-time-alarm?objectId=${data}&pageIndex=${pageIndex}&pageSize=${pageSize}`,
+        method: "get"
+    });
+};
+const getHealthDate=(stid,wtid)=>{
+    return request({
+        baseURL:process.env.VUE_APP_WARNING,
+        url:`/alarm/statistic?stId=${stid}&wtId=${wtid}`,
+        method:"get"
+    })
+}
+const getDetial=(data)=>{
+    return request({
+        baseURL:process.env.VUE_APP_API,
+        url:`/api/windturbine/${data}`,
+        method:"get"
+    })
+}
+const getWarning=(data,wtid,pt)=>{
+    return request({
+        baseURL:process.env.VUE_APP_WARNING,
+        url:`/alarm/list?stId=${data}&wtId=${wtid}&widget=${pt}`,
+        method:"get"
+    })
+}
+const getCustomerLock=()=>{
+    return request({
+        baseURL: process.env.VUE_APP_API,
+        url:`/api/windturbine/customer-lock`,
+        method:"get"
+    })
+}
+const controlRecord = (data) => {
+    return request({
+        baseURL:process.env.VUE_APP_API,
+        url: `/control-record/search?stationId=${data.stationId}&userName=${data.userName}&windturbineId=${data.windturbineId}&startTime=${data.startTime}&endTime=${data.endTime}&pageSize=${data.pageSize}&pageIndex=${data.pageIndex}`,
+        method: "get",
+    });
+};
+const getLatest = (data) => {
+    return request({
+        baseURL:process.env.VUE_APP_ADAPTERURL,
+        url: `/ts/latest?keys=${data}`,
+        method: "get",
+    });
+};
+//获取智能模式下场站
+const getControlType = () => {
+    return request({
+        baseURL:process.env.VUE_APP_API,
+        url: `/api/station/status`,
+        method: "get",
+    });
+};
+const uodateControlType = (data) => {
+    return request({
+        baseURL:process.env.VUE_APP_API,
+        url: `/api/station/status/update?stationid=${data.stationid}&type=${data.type}&userName=${data.userName}`,
+        method: "get",
+    });
+};
+
+const getWindturbineFdc = () => {
+    return request({
+        baseURL:process.env.VUE_APP_API,
+        url: `/api/windturbine/fdc`,
+        method: "get",
+    });
+};
+export default {
+    login,
+    getSnap,
+    refreshData,
+    windturbControl,
+    windturbControlLock,
+    nitWinturbineBaseData,
+    getOverview,
+    sendWarning,
+    sendRecommend,
+    getPower,
+    getOriginalPower,
+    getWindWarning,
+    getHealthDate,
+    getDetial,
+    getWarning,
+    getCustomerLock,
+    getWindturbinePower,
+    getOriginalWindturbinePower,
+    controlRecord,
+    getLatest,
+    getControlType,
+    uodateControlType,
+    getWindturbineFdc,
+    getStation(){
+        return request({
+            baseURL:process.env.VUE_APP_API,
+            url: `/api/station/agc`,
+            method: "get",
+        });
+    }
+};

二进制
src/assets/img/LabelArea/flag.png


二进制
src/assets/img/RecommendedArea/background.png


二进制
src/assets/img/RecommendedArea/guznzhu_bg_01.png


二进制
src/assets/img/WindturbineDetailPages/green.png


二进制
src/assets/img/WindturbineDetailPages/pic_01.png


二进制
src/assets/img/WindturbineDetailPages/red.png


二进制
src/assets/img/WindturbineDetailPages/偏航.png


二进制
src/assets/img/WindturbineDetailPages/发电机.png


二进制
src/assets/img/WindturbineDetailPages/变桨.png


二进制
src/assets/img/WindturbineDetailPages/机舱.png


二进制
src/assets/img/WindturbineDetailPages/液压.png


二进制
src/assets/img/WindturbineDetailPages/齿轮箱.png


二进制
src/assets/img/controlcenter/background_ACB.png


二进制
src/assets/img/controlcenter/background_ACR.png


二进制
src/assets/img/controlcenter/center_ACB.png


二进制
src/assets/img/controlcenter/center_ACR.png


二进制
src/assets/img/controlcenter/daraTrue.png


二进制
src/assets/img/controlcenter/dataFalse.png


二进制
src/assets/img/controlcenter/decoration01.png


二进制
src/assets/img/controlcenter/decoration02.png


二进制
src/assets/img/logo.ico


二进制
src/assets/img/logo.png


二进制
src/assets/img/logo2.ico


二进制
src/assets/img/main_window/logo.png


二进制
src/assets/img/statusbar/accident.png


二进制
src/assets/img/statusbar/background.png


二进制
src/assets/img/statusbar/background_alarm.png


二进制
src/assets/img/statusbar/defect.png


二进制
src/assets/img/statusbar/hidden_danger.png


二进制
src/assets/img/statusbar/malfunction.png


二进制
src/assets/img/type/down.png


二进制
src/assets/img/type/electricityRestrictions.png


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


二进制
src/assets/img/type/none.png


二进制
src/assets/img/type/up.png


二进制
src/assets/sound/Track52.mp3


+ 116 - 0
src/assets/styles/main.css

@@ -0,0 +1,116 @@
+* {
+    margin: 0;
+    padding: 0;
+}
+
+html,
+body,
+#app,
+.wrapper {
+    width: 100%;
+    height: 100%;
+    background-color: #000000;
+    overflow: hidden;
+    font-family: "Microsoft YaHei";
+}
+.el-popover{
+    background-color: rgb(36,36,36) !important;
+    border-color: rgb(36,36,36) !important;
+  }
+/*   .el-table{
+    border-color: rgb(36,36,36) !important;
+  }
+  .el-table__border td{
+    border: 1px solid red !important;
+  }
+  .el-table__row>td{
+	border-color: rgb(36,36,36) !important;
+}
+.el-table::before {
+	height: 0px !important;
+}
+.el-table::after {
+	height: 0px !important;
+} */
+.el-dialog{
+  background-color: rgb(36,36,36) !important;
+}
+.el-form-item__label{
+  color: rgb(220, 220, 220) !important;
+}
+.el-dialog__title{
+  color: rgb(220, 220, 220) !important;
+}
+.inputs .el-input__inner{
+  background-color: #000000 !important;
+  color: rgb(220, 220, 220) !important;
+}
+.el-input__inner{
+  /* background-color: rgb(100,100,100) !important; */
+  color: rgb(220, 220, 220) !important;
+  border: 1px solid rgba(77, 77, 77, 1) !important;
+}
+.el-tabs{
+  background-color: black !important;
+  border: none !important;
+  color: rgb(220,220,220) !important;
+}
+.el-table__empty-block{
+  background-color: #141414;
+  border: none;
+}
+.el-tabs__item{
+  background-color: #363636 !important;
+  color: rgb(220,220,220) !important;
+  border-color: black !important;
+} 
+.el-tabs__item:hover{
+  background-color: rgb(36,36,36) !important;
+  border-color: black !important;
+}
+.el-tabs__item.is-active{
+  background-color: rgb(29,106,235) !important;
+}
+
+
+.el-table--border:after,.el-table--group:after,.el-table:before {
+  background-color: black;
+  
+  }
+  
+  .el-table--border,.el-table--group {
+    border-color:black;
+  
+  }
+  
+/*   .el-table td,.el-table th {
+    border-bottom:2px solid rgb(36,36,36);
+  } 
+  
+  .el-table--border th,.el-table--border th.gutter:last-of-type {
+    border-bottom:1px solid yellow;
+  
+  }*/
+  
+  .el-table--border td,.el-table--border th {
+    border-right:1px solid rgb(36,36,36);
+  
+  }
+  
+  .el-table__empty-text{
+    color: black;
+  }
+
+  .el-tree-node:focus>.el-tree-node__content {
+    background-color: #000000 !important;
+  }
+
+  .el-tree-node__content:hover {
+    background-color: #000000 !important;
+  }
+  .el-notification .el-icon-success{
+    color: #67C23A !important;
+  }
+  .el-notification .el-icon-warning {
+    color: #E6A23C !important;
+  }

+ 86 - 0
src/background.js

@@ -0,0 +1,86 @@
+'use strict'
+
+import { app, protocol, BrowserWindow } from 'electron'
+import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
+import installExtension, { VUEJS3_DEVTOOLS } from 'electron-devtools-installer'
+const isDevelopment = process.env.NODE_ENV !== 'production'
+
+// Scheme must be registered before the app is ready
+protocol.registerSchemesAsPrivileged([
+  { scheme: 'app', privileges: { secure: true, standard: true } }
+])
+
+async function createWindow() {
+  // Create the browser window.
+  const win = new BrowserWindow({
+    width: 800,
+    height: 600,
+    frame:false,
+    fullscreen:true,
+    webPreferences: {
+      
+      // Use pluginOptions.nodeIntegration, leave this alone
+      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
+      nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
+      contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
+      nodeIntegration: true,
+      contextIsolation: false,
+      enableRemoteModule: true,   // 打开remote模块
+    }
+  })
+
+  if (process.env.WEBPACK_DEV_SERVER_URL) {
+    // Load the url of the dev server if in development mode
+    await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
+    if (!process.env.IS_TEST) win.webContents.openDevTools()
+  } else {
+    createProtocol('app')
+    // Load the index.html when not in development
+    win.loadURL('app://./index.html')
+  }
+}
+
+// Quit when all windows are closed.
+app.on('window-all-closed', () => {
+  // On macOS it is common for applications and their menu bar
+  // to stay active until the user quits explicitly with Cmd + Q
+  if (process.platform !== 'darwin') {
+    app.quit()
+  }
+})
+
+app.on('activate', () => {
+  // On macOS it's common to re-create a window in the app when the
+  // dock icon is clicked and there are no other windows open.
+  if (BrowserWindow.getAllWindows().length === 0) createWindow()
+})
+
+// This method will be called when Electron has finished
+// initialization and is ready to create browser windows.
+// Some APIs can only be used after this event occurs.
+app.on('ready', async () => {
+  if (isDevelopment && !process.env.IS_TEST) {
+    // Install Vue Devtools
+    try {
+      await installExtension(VUEJS3_DEVTOOLS)
+    } catch (e) {
+      console.error('Vue Devtools failed to install:', e.toString())
+    }
+  }
+  createWindow()
+})
+
+// Exit cleanly on request from parent process in development mode.
+if (isDevelopment) {
+  if (process.platform === 'win32') {
+    process.on('message', (data) => {
+      if (data === 'graceful-exit') {
+        app.quit()
+      }
+    })
+  } else {
+    process.on('SIGTERM', () => {
+      app.quit()
+    })
+  }
+}

文件差异内容过多而无法显示
+ 1253 - 0
src/components/BasicInformationDetail.vue


文件差异内容过多而无法显示
+ 5930 - 0
src/components/BoosterStation/dwk.vue


文件差异内容过多而无法显示
+ 4944 - 0
src/components/BoosterStation/hzj.vue


文件差异内容过多而无法显示
+ 2844 - 0
src/components/BoosterStation/mch.vue


文件差异内容过多而无法显示
+ 9139 - 0
src/components/BoosterStation/mhs.vue


文件差异内容过多而无法显示
+ 5432 - 0
src/components/BoosterStation/nss.vue


文件差异内容过多而无法显示
+ 5304 - 0
src/components/BoosterStation/pl1.vue


文件差异内容过多而无法显示
+ 3617 - 0
src/components/BoosterStation/pl2.vue


+ 722 - 0
src/components/BoosterStation/previewPicture.vue

@@ -0,0 +1,722 @@
+<template>
+  <div class="pop-up-main">
+    <div class="paln-box">
+      <div
+        class="movableItem"
+        :style="{ width: width, height: height }"
+        @mousewheel="rollImg($event)"
+        @mousedown="drag($event, 1)"
+        ref="bigImage"
+      >
+        <!-- 图片不可选中 或不可拖拽到新标签打开-->
+        <slot
+          name="svg"
+          oncontextmenu="return false;"
+          onselectstart="return false;"
+          draggable="false"
+        ></slot>
+        <template v-if="isEdit && iconWidth">
+          <img
+            ref="signImage"
+            :src="iconImgUrl"
+            @mousedown="dragSign($event, key)"
+            v-for="(item, key) in equipment"
+            :key="key"
+            :style="{
+              top: equipment[key].top + '%',
+              left: equipment[key].left + '%',
+              width: iconWidth,
+              height: iconHeight,
+            }"
+            class="equipment"
+          />
+        </template>
+        <el-popover
+          width="200"
+          placement="bottom-start"
+          trigger="hover"
+          :close-delay="100"
+          content="暂无描述"
+          v-else-if="!isEdit && iconWidth && arrIcon.length == equipment.length"
+          v-for="(item, key) in equipment"
+          :key="key"
+          popper-class="preview-popover"
+        >
+          <!-- &&arrIcon.length==equipment.length -->
+          <template>
+            <div v-if="equipment[key].describe" class="describe">
+              <p class="describe-top">
+                {{ equipment[key].describe.deviceName }}
+              </p>
+              <p class="describe-center">
+                {{ equipment[key].describe.remark }}
+              </p>
+              <p class="describe-bottom">
+                {{ equipment[key].describe.location }}
+              </p>
+            </div>
+          </template>
+          <!-- <img oncontextmenu="return false;" onselectstart="return false;" draggable="false" slot="reference"
+						ref="signImage" :src="$baseUrl + equipment[key].iconImgUrl"
+						:style="{top:equipment[key].top+'%',left:equipment[key].left+'%',width:arrIcon[key].iconWidth,height:arrIcon[key].iconHeight}"
+						class="equipment" /> -->
+        </el-popover>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    equipment: {
+      type: Array,
+      default: () => {
+        return [
+          {
+            iconImgUrl: "",
+            top: 0,
+            left: 0,
+          },
+        ];
+      },
+    },
+    isEdit: {
+      default: false,
+    },
+    imgUrl: {},
+  },
+
+  data() {
+    return {
+      // 定时器
+      timer: "",
+      // 图片加载失败
+      imgOnerror: false,
+      imgIndex: 0,
+      isChange: true,
+      // 图片显示默认大小
+      width: "1200px",
+      height: "800px",
+      // 可缩小倍数,为空则可无限缩小
+      minification: 3,
+      // 可放大倍数 为空则可无限放大
+      magnification: "",
+      bigMaxWidth: 1100,
+      bigMaxHeight: 800,
+
+      // 小图标信息
+      iconImgUrl: "",
+      iconWidth: "",
+      // 存储每个小图标处理好的宽高
+      iconHeight: "",
+      arrIcon: [],
+      iconMaxWidth: 32,
+      iconMaxHeight: 32,
+      tog: 1,
+    };
+  },
+  methods: {
+    // 获取图片大小
+    getImgInfo(
+      imgUrl,
+      MaxWidth,
+      MaxHeight,
+      StrWidth,
+      StrHeight,
+      Array = false,
+      arr,
+      num = 0
+    ) {
+      let img = new Image();
+
+      // img.src = imgUrl;
+      img = document.getElementsByClassName("svg");
+      let _this = this;
+      img.onerror = () => {
+        // console.log("加载失败!!", _this.arrIcon.length);
+        // console.log(imgUrl, MaxWidth, MaxHeight, StrWidth, StrHeight);
+        _this.imgOnerror = true;
+        _this.imgIndex =
+          _this.arrIcon.length - 1 < 0 ? 0 : _this.arrIcon.length - 1;
+        this.timer = setTimeout(() => {
+          if (num <= 5) {
+            _this.getImgInfo(
+              imgUrl,
+              MaxWidth,
+              MaxHeight,
+              StrWidth,
+              StrHeight,
+              Array,
+              arr,
+              num + 1
+            );
+          }
+          clearInterval(this.timer);
+        }, 2000);
+      };
+      img.onload = function (e) {
+        //  显示时 初始 最大宽度
+        let maxWidth = MaxWidth;
+        //  显示时 初始 最大高度
+        let maxHeight = MaxHeight;
+        if (
+          e.path[0].naturalWidth <= maxWidth &&
+          e.path[0].naturalHeight <= maxHeight
+        ) {
+          _this[StrWidth] = e.path[0].naturalWidth + "px";
+          _this[StrHeight] = e.path[0].naturalHeight + "px";
+        } else {
+          _this[StrWidth] = e.path[0].naturalWidth + "px";
+          _this[StrHeight] = e.path[0].naturalHeight + "px";
+          if (
+            e.path[0].naturalWidth > maxWidth &&
+            e.path[0].naturalHeight <= maxHeight
+          ) {
+            let ratio = e.path[0].naturalWidth / e.path[0].naturalHeight;
+            _this[StrWidth] = "1600px";
+            _this[StrHeight] = maxWidth / ratio + "px";
+          } else if (
+            e.path[0].naturalWidth <= maxWidth &&
+            e.path[0].naturalHeight > maxHeight
+          ) {
+            let ratio = e.path[0].naturalWidth / e.path[0].naturalHeight;
+            _this[StrWidth] = maxHeight * ratio + "px";
+            _this[StrHeight] = "800px";
+          } else if (
+            e.path[0].naturalWidth > maxWidth &&
+            e.path[0].naturalHeight > maxHeight
+          ) {
+            let ratio = e.path[0].naturalWidth / e.path[0].naturalHeight;
+            let w = maxWidth;
+            let h = w / ratio;
+            if (h > maxHeight) {
+              let ratio2 = w / h;
+              h = maxHeight;
+              w = h * ratio2;
+            }
+            _this[StrWidth] = w + "px";
+            _this[StrHeight] = h + "px";
+          }
+        }
+        if (Array) {
+          _this[arr].push({
+            iconWidth: _this[StrWidth],
+            iconHeight: _this[StrHeight],
+          });
+          // console.log(
+          // 	"tow#################################arrIcon",
+          // 	_this[arr].length
+          // );
+        }
+        // _this[StrWidth] = `${e.path[0].naturalWidth}px`;
+        // _this[StrHeight] = `${e.path[0].naturalHeight}px`;
+        // vm.$set(vm.imgInfo, "width", img.width);
+        // vm.$set(vm.imgInfo, "height", img.height);
+        // console.log("打印图片信息", imgUrl, _this[StrWidth], _this[StrHeight]); // 打印图片信息
+
+        // console.log("打印图片信息", e.path[0].naturalHeight); // 打印图片信息
+        // console.log("打印图片信息", e); // 打印图片信息
+        // console.log("打印图片信息this.width", _this[StrWidth]); // 打印图片信息
+        // console.log("打印图片信息this.height", _this[StrHeight]); // 打印图片信息
+      };
+    },
+    // 缩放
+    rollImg() {
+      let that = this;
+      // let oImg = document.getElementsByClassName("movableItem")[0];
+      let oImg = this.$refs.bigImage;
+      // console.log(
+      // 	"length",
+      // 	document.getElementsByClassName("movableItem").length
+      // );
+      // console.log("oImg", oImg);
+      let _this = this;
+
+      function fnWheel(obj, fncc) {
+        obj.onmousewheel = fn;
+        if (obj.addEventListener) {
+          obj.addEventListener("DOMMouseScroll", fn, false);
+        }
+
+        function fn(ev) {
+          let oEvent = ev || window.event;
+          let down = true;
+          if (oEvent.detail) {
+            down = oEvent.detail > 0;
+          } else {
+            down = oEvent.wheelDelta < 0;
+          }
+          if (fncc) {
+            fncc.call(this, down, oEvent);
+          }
+          if (oEvent.preventDefault) {
+            oEvent.preventDefault();
+          }
+          return false;
+        }
+      }
+      fnWheel(oImg, function (down, oEvent) {
+        let oldWidth = this.offsetWidth;
+        let oldHeight = this.offsetHeight;
+        let oldLeft = this.offsetLeft;
+        let oldTop = this.offsetTop;
+        let parent = oEvent.path[2];
+        // 获取父元素距离页面可视区域的位置
+        let parentLeft = parent.getBoundingClientRect().left;
+        let parentTop = parent.getBoundingClientRect().top;
+        // 比例 = (点击位置距离可视窗口位置 - 父元素距离可视窗口位置 - 相对定位的left)/ 本身宽度
+        let scaleX = (oEvent.clientX - parentLeft - oldLeft) / oldWidth; //比例
+        let scaleY = (oEvent.clientY - parentTop - oldTop) / oldHeight;
+
+        let nowWidth = this.style.width.split("p")[0];
+        let initWidth = _this.width.split("p")[0];
+        let initHeight = _this.height.split("p")[0];
+
+        let miniFlag = true;
+        let magniFlag = true;
+        if (_this.minification) {
+          // 限制缩小范围
+          if (nowWidth <= parseInt(initWidth / _this.minification)) {
+            miniFlag = false;
+            // console.log("限制缩小范围");
+            // console.log(
+            // 	"限制缩小范围",
+            // 	nowWidth,
+            // 	parseInt(initWidth / _this.minification)
+            // );
+            this.style.width = parseInt(initWidth / _this.minification) + "px";
+            this.style.height =
+              parseInt(initHeight / _this.minification) + "px";
+          }
+          if (_this.magnification) {
+            // 限制放大范围
+            if (nowWidth >= parseInt(initWidth * _this.magnification)) {
+              magniFlag = false;
+              // console.log("限制放大范围");
+              this.style.width =
+                parseInt(initWidth * _this.magnification) + "px";
+              this.style.height =
+                parseInt(initHeight * _this.magnification) + "px";
+            }
+          }
+        }
+
+        if (down && miniFlag) {
+          this.style.width = parseInt(this.offsetWidth * 0.9) + "px";
+          this.style.height = parseInt(this.offsetHeight * 0.9) + "px";
+
+          that.width = parseInt(this.offsetWidth * 0.9) + "px";
+          that.height = parseInt(this.offsetHeight * 0.9) + "px";
+        } else if (!down && magniFlag) {
+          // console.log("放大");
+          this.style.width = parseInt(this.offsetWidth * 1.1) + "px";
+          this.style.height = parseInt(this.offsetHeight * 1.1) + "px";
+          that.width = parseInt(this.offsetWidth * 1.1) + "px";
+          that.height = parseInt(this.offsetHeight * 1.1) + "px";
+        }
+        let newWidth = this.offsetWidth;
+        let newHeight = this.offsetHeight;
+
+        // 新的相对位置left = 原先的相对位置left - 比例 *(本身新的宽度-旧的宽度)
+        this.style.left =
+          Math.round(this.offsetLeft - scaleX * (newWidth - oldWidth)) + "px";
+        this.style.top =
+          Math.round(this.offsetTop - scaleY * (newHeight - oldHeight)) + "px";
+      });
+      // console.log(that.width)
+    },
+    // },
+    //拖拽
+    drag(ev) {
+      // let ie = document.all;
+      let nn6 = document.getElementById && !document.all;
+      let isdrag = false;
+      let y, x;
+      let nTY, nTX;
+      let oDragObj;
+
+      function moveMouse(e) {
+        if (isdrag) {
+          oDragObj.style.top =
+            (nn6 ? nTY + e.clientY - y : nTY + event.clientY - y) + "px";
+          oDragObj.style.left =
+            (nn6 ? nTX + e.clientX - x : nTX + event.clientX - x) + "px";
+          return false;
+        }
+      }
+
+      function initDrag(e) {
+        // console.log("点击图片initDrag");
+        let oDragHandle = nn6 ? e.target : event.srcElement;
+        let topElement = "HTML";
+        while (
+          oDragHandle.tagName != topElement &&
+          oDragHandle.className != "movableItem"
+        ) {
+          oDragHandle = nn6
+            ? oDragHandle.parentNode
+            : oDragHandle.parentElement;
+        }
+        if (oDragHandle.className == "movableItem") {
+          isdrag = true;
+          oDragObj = oDragHandle;
+          // 父元素宽高
+          let width = e.path[2].offsetWidth;
+          let height = e.path[2].offsetHeight;
+          // 这里判断第一次获取不到style 样式 默认为 居中50%
+          if (oDragObj.style.top == "") {
+            nTY = 0;
+            nTX = parseInt((50 * width) / 100 + 0);
+          } else {
+            nTY = parseInt(oDragObj.style.top + 0);
+            nTX = parseInt(oDragObj.style.left + 0);
+          }
+          y = nn6 ? e.clientY : event.clientY;
+          x = nn6 ? e.clientX : event.clientX;
+          oDragObj.style.cursor = "move";
+          document.onmousemove = moveMouse;
+          return false;
+        }
+      }
+      document.onmousemove = initDrag;
+      // document.onmouseup = new Function("isdrag=false");
+      document.onmouseup = function (e) {
+        isdrag = false;
+        document.onmousemove = null;
+        document.onmouseup = null;
+        let oDragHandle = nn6 ? e.target : event.srcElement;
+        let topElement = "HTML";
+        while (
+          oDragHandle.tagName != topElement &&
+          oDragHandle.className != "movableItem"
+        ) {
+          oDragHandle = nn6
+            ? oDragHandle.parentNode
+            : oDragHandle.parentElement;
+        }
+        if (oDragHandle.className == "movableItem") {
+          oDragObj = oDragHandle;
+          oDragObj.style.cursor = "Default";
+        }
+      };
+      ev = event || window.event;
+
+      // 取消事件冒泡行为
+      // window.event ? (window.event.cancelBubble = true) : ev.stopPropagation();
+    },
+    // 拖拽标记
+    // eslint-disable-next-line no-unused-lets
+    dragSign(ev, key) {
+      let nn6 = document.getElementById && !document.all;
+      let isdrag = false;
+      let y, x;
+      let nTY, nTX;
+      let oDragObj;
+      let _this = this;
+
+      function moveMouse(e) {
+        if (isdrag) {
+          this.equipmentKey = key;
+          // console.log("thisequipmentKey", this.equipmentKey);
+
+          let widthItem = e.path[1].style.width.split("p");
+          let heightItem = e.path[1].style.height.split("p");
+          let width = widthItem[0];
+          // eslint-disable-next-line no-unused-lets
+          let height = heightItem[0];
+          let top =
+            ((nn6
+              ? (nTY / 100) * height + e.clientY - y
+              : (nTY / 100) * height + event.clientY - y) /
+              height) *
+            100;
+          let left =
+            ((nn6
+              ? (nTX / 100) * width + e.clientX - x
+              : (nTX / 100) * width + event.clientX - x) /
+              width) *
+            100;
+
+          if (top >= 0 && top <= 100) {
+            _this.equipment[key].top = top;
+          }
+          if (left >= 0 && left <= 100) {
+            _this.equipment[key].left = left;
+          }
+
+          return false;
+        }
+      }
+      // eslint-disable-next-line no-unused-vars
+      function initDrag(e) {
+        // console.log("_this", _this);
+        let oDragHandle = nn6 ? e.target : event.srcElement;
+        let topElement = "HTML";
+        while (
+          oDragHandle.tagName != topElement &&
+          oDragHandle.className.indexOf("equipment") == -1
+        ) {
+          oDragHandle = nn6
+            ? oDragHandle.parentNode
+            : oDragHandle.parentElement;
+        }
+        if (oDragHandle.className.indexOf("equipment") != -1) {
+          isdrag = true;
+          oDragObj = oDragHandle;
+          // 父元素宽高
+          let width = e.path[1].offsetWidth;
+          // let height = e.path[1].offsetHeight;
+          // console.log(width, height);
+          // console.log("oDragObj.style", oDragObj.style);
+          // 这里判断第一次获取不到style 样式 默认为 居中50%
+          if (oDragObj.style.top == "") {
+            // nTY = parseInt((50 * height) / 100 + 0);
+            nTY = 0;
+            nTX = parseInt((50 * width) / 100 + 0);
+          } else if (oDragObj.style.top.indexOf("%") != -1) {
+            nTY = oDragObj.style.top.split("%")[0];
+            nTX = oDragObj.style.left.split("%")[0];
+          } else {
+            nTY = parseInt(oDragObj.style.top + 0);
+            nTX = parseInt(oDragObj.style.left + 0);
+          }
+          y = nn6 ? e.clientY : event.clientY;
+          x = nn6 ? e.clientX : event.clientX;
+
+          oDragObj.style.cursor = "move";
+          document.onmousemove = moveMouse;
+          return false;
+        }
+      }
+
+      // document.onmousedown = initDrag;
+      document.onmousemove = initDrag;
+
+      document.onmouseup = function (e) {
+        isdrag = false;
+        document.onmousemove = null;
+        document.onmouseup = null;
+        let oDragHandle = nn6 ? e.target : event.srcElement;
+        let topElement = "HTML";
+        while (
+          oDragHandle.tagName != topElement &&
+          oDragHandle.className != "equipment"
+        ) {
+          oDragHandle = nn6
+            ? oDragHandle.parentNode
+            : oDragHandle.parentElement;
+        }
+        if (oDragHandle.className == "equipment") {
+          oDragObj = oDragHandle;
+          oDragObj.style.cursor = "Default";
+        }
+      };
+
+      // _this.equipmentKey = key;
+      // _this.equipment[_this.equipmentKey].left = l;
+      // _this.equipment[_this.equipmentKey].top = t;
+      ev = event || window.event;
+
+      // 取消事件冒泡行为
+      window.event ? (window.event.cancelBubble = true) : ev.stopPropagation();
+    },
+  },
+
+  watch: {
+    equipment() {
+      if (this.equipment.length != 0) {
+        this.arrIcon = [];
+        let finish = true;
+        this.equipment.filter((item) => {
+          if (!item.iconImgUrl) {
+            finish = false;
+          }
+          return true;
+        });
+        // console.log("finish", finish);
+        if (finish) {
+          this.equipment.filter((item, index) => {
+            if (index >= this.imgIndex) {
+              console.log("iconImgUrl", this.equipment[index].iconImgUrl);
+              this.getImgInfo(
+                this.$baseUrl + item.iconImgUrl,
+                this.iconMaxWidth,
+                this.iconMaxHeight,
+                "iconWidth",
+                "iconHeight",
+                true,
+                "arrIcon"
+              );
+            }
+            console.log("22filter", index);
+            return true;
+          });
+        }
+      }
+    },
+  },
+  created() {
+    this.getImgInfo(
+      this.imgUrl,
+      this.bigMaxWidth,
+      this.bigMaxHeight,
+      "width",
+      "height"
+    );
+    if (this.equipment.length != 0) {
+      this.arrIcon = [];
+      let finish = true;
+      this.equipment.filter((item) => {
+        if (!item.iconImgUrl) {
+          finish = false;
+        }
+        return true;
+      });
+      // console.log("finish", finish);
+      if (finish) {
+        this.equipment.filter((item, index) => {
+          if (index >= this.imgIndex) {
+            // console.log("iconImgUrl", this.equipment[index].iconImgUrl);
+            this.getImgInfo(
+              this.$baseUrl + item.iconImgUrl,
+              this.iconMaxWidth,
+              this.iconMaxHeight,
+              "iconWidth",
+              "iconHeight",
+              true,
+              "arrIcon"
+            );
+          }
+          // console.log("22filter", index);
+          return true;
+        });
+      }
+    }
+
+    this.iconImgUrl = JSON.parse(
+      JSON.stringify(this.$baseUrl + this.equipment[0].iconImgUrl)
+    );
+    // console.log("imgUrl", this.imgUrl);
+    // console.log("equipment", this.equipment);
+    // //禁止鼠标右键
+    // document.oncontextmenu = function() {
+    //   return false;
+    // };
+  },
+};
+</script>
+<style lang="less">
+.preview-popover {
+  background-color: #d3edf7dd;
+  padding: 12px;
+
+  .popper__arrow::after {
+    border-bottom-color: #d3edf7dd !important;
+  }
+
+  .describe {
+    p {
+      padding-bottom: 5px;
+
+      &:last-child {
+        padding-bottom: 0px;
+      }
+    }
+
+    .describe-top {
+      // color: sandybrown;
+      // color: red;
+      color: rgb(21, 110, 110);
+    }
+
+    .describe-center {
+      color: rgb(79, 21, 206);
+    }
+
+    .describe-bottom {
+      color: rgb(30, 31, 29);
+    }
+  }
+}
+</style>
+<style lang="less" scoped>
+.pop-up-main {
+		width: 100%;
+		height: calc(100vh - 32vh);
+		overflow-y:hidden ;
+
+		.paln-box {
+			width: 100%;
+			height: 100%;
+			position: relative;
+
+			.movableItem {
+				position: absolute;
+				// top: 75%;
+				left: 50%;
+				transform: translate(-50%, -15%);
+
+				img,
+				.svg {
+					z-index: 1;
+					width: 100%;
+					height: 100%;
+				}
+
+				.equipment {
+					position: absolute;
+					top: 0;
+					left: 0;
+					transform: translate(-50%, -50%);
+					z-index: 2;
+					font-size: 40px;
+					// color: red;
+					// background: blue;
+					zoom: 1;
+				}
+			}
+
+			.shuaxin {
+				position: absolute;
+				z-index: 2;
+				font-size: 40px;
+				top: 20px;
+				left: 20px;
+				cursor: pointer;
+
+				&:hover {
+					color: yellowgreen;
+				}
+			}
+
+			.equipment {
+				color: white;
+			}
+
+			&/deep/.el-button {
+				z-index: 2;
+				position: absolute;
+				bottom: 60px;
+				right: 20px;
+				width: 60px;
+				height: 35px;
+
+				span {
+					display: inline-block;
+					position: absolute;
+					top: 50%;
+					left: 50%;
+					transform: translate(-50%, -50%);
+				}
+
+				i {
+					display: inline-block;
+					position: absolute;
+					top: 50%;
+					left: 25%;
+					transform: translate(-50%, -50%);
+				}
+			}
+		}
+	}
+</style>

文件差异内容过多而无法显示
+ 4050 - 0
src/components/BoosterStation/qs.vue


文件差异内容过多而无法显示
+ 2502 - 0
src/components/BoosterStation/sbdl.vue


文件差异内容过多而无法显示
+ 4403 - 0
src/components/BoosterStation/sbq.vue


文件差异内容过多而无法显示
+ 12163 - 0
src/components/BoosterStation/xh.vue


文件差异内容过多而无法显示
+ 10411 - 0
src/components/BoosterStation/xs.vue


文件差异内容过多而无法显示
+ 431 - 0
src/components/StandAloneImg.vue


+ 40 - 0
src/components/TitleBarCard.vue

@@ -0,0 +1,40 @@
+<template>
+    <div>
+        <span class="title">{{title}}</span>
+        <span class="value">{{value}}</span>
+        <span class="title">{{unit}}</span>
+    </div>
+</template>
+
+<script>
+export default {
+  name: 'TitleBarCard',
+  props: {
+    title: String,
+    value: Number,
+    unit: String,
+  },
+  data() {
+    return {
+      
+    };
+  },
+  methods: {
+    handleClose() {},
+  }
+}
+</script>
+
+<style scoped>
+
+span{
+  font-size: 15px;
+  margin-left: 9px;
+}
+.title{
+    color:#FFFFFF;
+}
+.value{
+  color:#50AE56;
+}
+</style>

+ 252 - 0
src/components/WindturbineDetailPages.vue

@@ -0,0 +1,252 @@
+<template>
+	<el-dialog width="75%" @opened="opened()" @closed="closed()" :show-close="false" class="my-info-dialog">
+		<template #title>
+			<div style="margin-top:-10px;color: #FFFFFF;">风机详情</div>
+		</template>
+		<div class="body">
+			<div class="titleList">
+				<div class="chunkdiv">
+					<div class="title">风机号:&emsp;</div>
+					<div>{{ windturbine.windturbineId }}</div>
+				</div>
+				<div class="chunkdiv" @dblclick="dbClicks(baseDate.windSpeed)">
+					<div class="title">{{baseDate.windSpeed.name}}:&emsp;</div>
+					<div>{{baseDate.windSpeed.value}}{{baseDate.windSpeed.unit}}</div>
+				</div>
+				<div class="chunkdiv" @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="title">理论功率:&emsp;</div>
+					<div>{{healthInfo?.theoreticalPower?.toFixed(2)}}Kw</div>
+				</div>
+				<div class="chunkdiv" @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="title">{{baseDate.generatorSpeed.name}}:&emsp;</div>
+					<div>{{baseDate.generatorSpeed.value}}{{baseDate.generatorSpeed.unit}}</div>
+				</div>
+			</div>
+			<BasicInformationDetail ref="BasicInfo" :types="types" @health-click="handleHealth" :windturbine="windturbine"></BasicInformationDetail>
+		</div>
+	</el-dialog>
+</template>
+
+<script>
+	// import YawDetail from "./YawDetail.vue";
+	import api from "api/index";
+	import BasicInformationDetail from "./BasicInformationDetail.vue";
+	import UniformCodes from "utils/UniformCodes";
+	import BackgroundData from 'utils/BackgroundData'
+	// import Worning from "./warning.vue"
+	export default {
+		components: {
+			BasicInformationDetail,
+		},
+		props: {
+			windturbine: Object,
+		},
+		data() {
+			return {
+				BasicInfo: {},
+				healthInfo: {},
+				line: "",
+				alarmTime: "",
+				alarmContent: "",
+				alarms: [],
+				count: false,
+				theoreticalPower:{
+					code: "LLGL",
+					name: "理论功率"
+				},
+				typeList: [{
+					type: 0,
+					name: '已经停机',
+				},
+				{
+					type: 1,
+					name: '上电',
+				},
+				{
+					type: 2,
+					name: '待机',
+				},
+				{
+					type: 3,
+					name: '启动',
+				},
+				{
+					type: 4,
+					name: '并网',
+				},
+				{
+					type: 5,
+					name: '故障',
+				},
+				{
+					type: 6,
+					name: '维护',
+				},
+				{
+					type: 7,
+					name: '离线',
+				},
+				],
+				baseDate: {
+					windSpeed: {
+						name: '',
+						num: '',
+						unit: ''
+					},
+					power: {
+						name: '',
+						num: '',
+						unit: ''
+					},
+					generatorSpeed: {
+						name: '',
+						num: '',
+						unit: ''
+					},
+				},
+				types: null,
+			};
+		},
+		created() {
+			this.UniformCodes = new UniformCodes();
+		},
+
+		methods: {
+			opened() {
+				this.line = "";
+					this.alarmTime = "";
+					this.alarmContent = "";
+					this.BasicInfo = this.UniformCodes.getStationInfos(this.windturbine);
+					this.BasicInfo.windturbineId = this.windturbine.windturbineId;
+					// this.dateDeal(this.BasicInfo)
+					this.$refs.BasicInfo.start(this.BasicInfo);
+					this.initData();
+					this.refreshData();
+					this.refreshTimer = setInterval(this.refreshData, 100)
+			},
+			closed() {
+				// todo 切换页面的时候应该让上一个页面停止刷新数据(调用end方法)
+				// this.$refs.svgRef.closed();
+				// this.$refs.BasicInfo.end();
+				// this.$refs.BasicInfo.labelChange();
+				this.$emit('close');
+				//clearInterval(this.refreshTimer);
+			},
+			dateDeal(BasicInfo) {
+				let showInf = {}
+				showInf = BasicInfo.BasicInfo.filter(item => item.tag === "基本信息")[0]
+				this.baseDate.windSpeed = showInf.param.filter(item => item.name === "风速")[0]
+				this.baseDate.power = showInf.param.filter(item => item.name === "有功功率")[0]
+				this.baseDate.generatorSpeed = showInf.param.filter(item => item.name === "发电机转速")[0]
+				this.baseDate.type = showInf.param.filter(item => item.name === "状态")[0].value ? this.typeList.filter(
+					status => status.type === Number(showInf.param.filter(item => item.name === "状态")[0].value))[0]
+					.name : ''
+				console.log(this.baseDate.generatorSpeed.name);
+				this.types = Number(showInf.param.filter(item => item.name === "状态")[0].value)
+				console.log(this.types)
+			},
+			refreshData() {
+				let bg = BackgroundData.getInstance();
+				bg.initWinturbineBaseData(this.BasicInfo, this.onMessage);
+				this.dateDeal(this.BasicInfo)
+				clearInterval(this.refreshTimer);
+				this.refreshTimer = setInterval(this.refreshData, 5000)
+			},
+			initData() {
+				// axiios.get(`http://${config.calcUrl}/windturbine/line/${this.windturbine.windturbineId}`)
+				//   .then(msg => this.line = msg.data);
+				api.getWindWarning(this.windturbine.windturbineId, '1', '50').then(msg => {
+					let vs = msg.data;
+					if (vs.length <= 0) return;
+					this.alarmTime = BackgroundData.getInstance().formatDate(vs[0].lastUpdateTime);
+					this.alarmContent = vs[0].alertText;
+					this.alarms = msg.data;
+					this.$refs.BasicInfo.alarmd(this.alarms);
+					console.log(this.alarms)
+				})
+					.catch(err => {
+						console.log(err);
+					});
+			},
+			dbClicks(value) {
+				this.$refs.BasicInfo.dbClicks(value, this.windturbine.windturbineId)
+			},
+			handleHealth(value){
+				this.healthInfo = value
+			}
+		},
+		watch: {
+			'windturbine': {
+				handler: function (json) {
+					if (json) {
+						this.initData()
+					}
+				}
+			}
+		}
+	};
+</script>
+<style scoped>
+	.my-info-dialog {
+		box-shadow: 0px 0px 10px #05bb4c;
+	}
+
+	.body {
+		background-color: black;
+		margin-top: -30px;
+		margin-left: -10px;
+		margin-right: -10px;
+		margin-bottom: -30px;
+		border-bottom: 20px solid rgb(36, 36, 36);
+	}
+
+	.chunkdiv {
+		display: flex;
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		width: 17%;
+		background-color: #363636;
+		margin: 1px;
+		padding: 4px 0px;
+		font-size: 12px;
+		color: #FFFFFF;
+		overflow: hidden;
+		white-space: nowrap;
+	}
+
+	.title {
+		font-size: 12px;
+		color: #B3B3B3;
+	}
+
+	table {
+		margin-left: 2px;
+		margin-right: 2px;
+	}
+
+	/* td {
+		width: 20%;
+	} */
+
+	el-tabs {
+		background-color: black;
+	}
+
+	.svg {
+		height: 67vh;
+	}
+	.titleList{
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+	}
+</style>

+ 730 - 0
src/components/areaCard.vue

@@ -0,0 +1,730 @@
+/* 自定义tabs */
+<template>
+    <!-- <transition>
+        <div :class='areaClass' @mouseover="hover = false" @mouseleave="hover = false" onselectstart="return false">
+            <div :class="headerClass">
+                <div :class='circleClass'></div>
+                <span class="gy-card-title">{{ title }}</span>
+                <img class="gy-card-decoration01" src="../../assets/img/controlcenter/decoration01.png">
+                <img class="gy-card-decoration02" src="../../assets/img/controlcenter/decoration02.png">
+            </div>
+            <div :class='contentClass'>
+                <el-scrollbar style="height: 100%">
+                    <slot></slot>
+                </el-scrollbar>
+            </div>
+        </div>
+    </transition> -->
+    <div class="body" :style="style">
+        <img class="logo" src="../assets/img/logo.png" alt="">
+        <div class="title">{{ title }}</div>
+        <div style="margin-top: 50px; height: 91%;">
+            <el-scrollbar>
+                <div class="scoll">
+                    <div class="matrix" v-if="faultList.length>0">
+                        <div class="problemTitle">故障</div>
+                        <MatrixBlock @on-click="handleClick" :dataList="faultList"></MatrixBlock>
+                    </div>
+                    <div class="matrix" v-if="maintainList.length>0">
+                        <div class="problemTitle">维护</div>
+                        <MatrixBlock @on-click="handleClick" :dataList="maintainList"></MatrixBlock>
+                    </div>
+                    <div class="matrix" v-if="offlineList.length>0">
+                        <div class="problemTitle">离线</div>
+                        <MatrixBlock @on-click="handleClick" :dataList="offlineList"></MatrixBlock>
+                    </div>
+                    <div class="matrix" v-if="listedList.length>0">
+                        <div class="problemTitle">挂牌</div>
+                        <MatrixBlock @on-click="handleClick" :dataList="listedList"></MatrixBlock>
+                    </div>
+                    <div class="matrix" v-if="listedList.length>0">
+                        <div class="problemTitle">挂牌</div>
+                        <MatrixBlock @on-click="handleClick" :dataList="listedList"></MatrixBlock>
+                    </div>
+                </div>
+            </el-scrollbar>
+        </div>
+    </div>
+</template>
+
+<script>
+    import BackgroundData from 'utils/BackgroundData'
+    // import ProblemMatrixCard from "./problem/ProblemMatrixCard.vue";
+    import MatrixBlock from "./matrixBlock.vue";
+    export default {
+        name: 'gy-card',
+        components: {
+            // ProblemMatrixCard,
+            MatrixBlock
+        },
+        emits: ["parentRun"],
+        props: {
+            title: {
+                type: String,
+                default: '校验区',
+                required: true
+            },
+            height: {
+                type: Number,
+                default: 200,
+            },
+            areaStyle: {
+                type: String,
+                default: 'check',
+                required: true
+            },
+            circleStyle: {
+                type: String,
+                default: 'green',
+                required: true
+            },
+            contentStyle: {
+                type: String,
+                default: '44',
+                required: true
+            },
+            showFlag: {
+                type: Boolean,
+                default: false,
+            }
+        },
+        data() {
+            return {
+                dialogVisible: false,
+                currentWindturbine: {},
+                values: [],
+                hover: false,
+                big: false,
+                current: 0,
+                faultList: [],
+                maintainList: [],
+                offlineList: [],
+                listedList: [],
+                chooseList: [],
+                titleList: [
+                    {
+                        id: 0,
+                        title: '麻黄山',
+                    },
+                    {
+                        id: 1,
+                        title: '牛首山',
+                    },
+                    {
+                        id: 2,
+                        title: '青山',
+                    },
+                    {
+                        id: 3,
+                        title: '石板泉',
+                    },
+                    {
+                        id: 4,
+                        title: '香山',
+                    },
+                ],
+            }
+        },
+        computed: {
+            style() {
+                return `width: 100%; height: 82%;`
+            },
+            areaClass() {
+                if (this.big) {
+                    return `gy-card-area-big`;
+                } else {
+                    return `gy-card-area-${this.areaStyle}`;
+                }
+            },
+            circleClass() {
+                return `gy-card-circle gy-card-circle-${this.circleStyle}`;
+            },
+            contentClass() {
+                if (this.big) {
+                    return `gy-card-content-big`;
+                } else {
+                    return `gy-card-content-${this.contentStyle}`;
+                }
+            },
+            headerClass() {
+                if (this.hover) {
+                    return `gy-card-header-hover`;
+                } else {
+                    return `gy-card-header`;
+                }
+            }
+        },
+        methods: {
+            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)
+                }
+            },
+            /* 右键菜单 */
+            contextmenu() {
+                const { remote } = require("electron");
+                let that = this;
+                const menuTemplate = [
+                    {
+                        label: "启动",
+                        click() {
+                            that.menuClicked({ type: "send", controlType: '1' });
+                        },
+                    },
+                    {
+                        label: "停机",
+                        click() {
+                            that.menuClicked({ type: "send", controlType: '2' });
+                        },
+                    },
+                    {
+                        label: "复位",
+                        click() {
+                            that.menuClicked({ type: "send", controlType: '5' });
+                        },
+                    },
+                    {
+                        label: "维护",
+                        click() {
+                            that.menuClicked({ type: "send", controlType: '6' });
+                        },
+                    },
+                    {
+                        label: "取消维护",
+                        click() {
+                            that.menuClicked({ type: "send", controlType: '8' });
+                        },
+                    },
+                    {
+                        label: "挂牌",
+                        submenu: [
+                            {
+                                label: "检修",
+                                click() {
+                                    that.menuClicked({ type: "lock", value: "CheckLock" });
+                                },
+                            },
+                            {
+                                label: "故障维修",
+                                click() {
+                                    that.menuClicked({ type: "lock", value: "FaultLock" });
+                                },
+                            },
+                            {
+                                label: "场内受累检修",
+                                click() {
+                                    that.menuClicked({ type: "lock", value: "StationCheckLock" });
+                                },
+                            },
+                            {
+                                label: "场内受累故障",
+                                click() {
+                                    that.menuClicked({ type: "lock", value: "StationFaulLock" });
+                                },
+                            },
+                            {
+                                label: "场外受累电网",
+                                click() {
+                                    that.menuClicked({
+                                        type: "lock",
+                                        value: "StationPowerLineLock",
+                                    });
+                                },
+                            },
+                            {
+                                label: "场外受累天气",
+                                click() {
+                                    that.menuClicked({ type: "lock", value: "StationWeatherLock" });
+                                },
+                            },
+                        ],
+                    },
+                    {
+                        label: "取消挂牌",
+                        click() {
+                            that.menuClicked({ type: 'lock', value: 'UnLock' });
+                        },
+                    },
+                    // {
+                    //     label: "标注",
+                    //     click() {
+                    //         that.menuClicked({ type: "marking" });
+                    //     },
+                    // },
+                ];
+                const menu = remote.Menu.buildFromTemplate(menuTemplate);
+
+                menu.popup(remote.getCurrentWindow());
+            },
+            menuClicked(msg) {
+                let bd = BackgroundData.getInstance();
+                
+                if (msg.type == "lock") {
+                    // 挂牌
+                    let los = this.getSelectedItems();
+                    for (let id in los) {
+                        los[id].lockType = msg.value;
+                    }
+                    bd.windturbineControl(
+                        los,
+                        true,
+                        '',
+                        this.controlSuccess,
+                        this.controlError
+                    );
+                } else if (msg.type == "send") {
+                    // 发送
+                    let vs = this.getSelectedItems(true);
+                    for (let item in los) {
+                        los[item].controlType = Number(msg.controlType)
+                    }
+                    bd.windturbineControl(
+                        vs,
+                        false,
+                        '',
+                        '',
+                        this.controlSuccess,
+                        this.controlError
+                    );
+                } else if (msg.type == "marking") {
+                    // 标注
+                    let vvs = this.getSelectedItems();
+                    bd.marking(vvs);
+                }
+                this.clearSelected();
+            },
+            /* 获取选中的项目,isControl:是否是控制 */
+            getSelectedItems() {
+                // isControl
+                let ls = new Array();
+                this.$refs.malfunction.outputSelectedItems(ls);
+                return ls;
+            },
+            /* 清除所有选择 */
+            clearSelected() {
+                this.$refs.malfunction.clearSelected();
+            },
+            filter(value, windturbineId) {
+                let array = [];
+                let flag = false;
+                for (let i = 0; i < value.length; i++) {
+                    if (value[i].windturbineId == windturbineId) {
+                        flag = true;
+                        array.push(flag); // 风机是否已经存在
+                        array.push(i); // 风机在values数组的位置
+                        array.push(value[i].active); // 当前风机是否被选中
+                        break;
+                    }
+                }
+                return array;
+            },
+            changeTitle(id) {
+                this.current = id
+                this.$refs.malfunction.dateClick(id)
+            },
+            addCard(val) {
+                let active = false;
+                let array = this.filter(this.values, val.windturbineId);
+                if (!array[0]) {
+                    // 维护
+                    val.active = active;
+                    if (val.modelId.indexOf("105") >= 0) {
+                        val.rollSpeed *= 9.55;
+                    }
+                    this.values.push(val);
+                } else {
+                    val.active = array[2];
+                    this.values.splice(array[1], 1, val);
+                }
+            },
+            showWindows(item) {
+                this.dialogVisible = true;
+                this.currentWindturbine = item;
+            }
+        },
+        watch: {
+            "$store.getters.windturbinelist": {
+                deep: true,
+                handler: function (json) {
+                    let vs = {};
+                    this.faultList = []
+                    this.maintainList = []
+                    this.offlineList = []
+                    this.listedList = []
+                    let arr = Object.keys(json).sort()
+                    for (let id of arr) {
+                        let val = json[id];
+                        this.chooseList.forEach(item => {
+                            if (item.windturbineId === val.windturbineId) {
+                                val.active = true
+                            }
+                        })
+                        switch (val.status) {
+                            case 5:
+                                this.faultList.push(val)
+                                break;
+                            case 6:
+                                this.maintainList.push(val)
+                                break;
+                            case 7:
+                                this.offlineList.push(val)
+                                break;
+                        }
+                        if (val.lockValue > 0) {
+                            this.listedList.push(val)
+                        }
+                    }
+                },
+            },
+        },
+    }
+</script>
+
+<style scoped="scoped">
+    .body {
+        border: 1px solid #373737;
+        width: 100%;
+        margin-left: 15px;
+        margin-top: 10px;
+    }
+
+    .body .scoll {
+        height: 91%;
+    }
+
+    .title {
+        color: #ffffff;
+        font-size: 14px;
+        margin-left: 32px;
+        /* margin-top: 12px; */
+        margin-bottom: 10px;
+        width: 570px;
+        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: #54B75A;
+        border-radius: 50%;
+    }
+
+    .logo {
+        position: absolute;
+        top: 2px;
+        left: 18px;
+    }
+
+    .matrix {
+        margin-left: 20px;
+        margin-right: 10px;
+        padding-bottom: 20px;
+        border-bottom: 1px solid rgba(31, 31, 31, 1);
+    }
+
+    .problemTitle {
+        font-size: 12px;
+        color: #BFBFBF;
+        margin-top: 20px;
+        margin-bottom: 20px;
+        margin-left: 12px;
+    }
+
+    .gy-card-header {
+        position: relative;
+        height: 40px;
+        background-color: #292929;
+        color: white;
+        box-sizing: border-box;
+    }
+
+    .gy-card-content-89 {
+        position: relative;
+        height: calc(89vh - 50px);
+        background-color: #000000;
+        color: white;
+        box-sizing: border-box;
+        border-radius: 7px;
+    }
+
+    .gy-card-content-44 {
+        position: relative;
+        height: calc(44vh - 50px);
+        background-color: #000000;
+        color: white;
+        box-sizing: border-box;
+        border-radius: 7px;
+    }
+
+    .gy-card-content-37 {
+        position: relative;
+        height: calc(37vh - 50px);
+        background-color: #000000;
+        color: white;
+        box-sizing: border-box;
+        border-radius: 7px;
+    }
+
+    .gy-card-content-25 {
+        position: relative;
+        height: calc(25vh - 50px);
+        background-color: #000000;
+        color: white;
+        box-sizing: border-box;
+        border-radius: 7px;
+    }
+
+    .gy-card-circle {
+        position: relative;
+        top: 7px;
+        display: inline-block;
+        width: 7px;
+        height: 7px;
+        -moz-border-radius: 50%;
+        -webkit-border-radius: 50%;
+        border-radius: 50%;
+    }
+
+    .gy-card-circle-green {
+        background-color: #008000;
+    }
+
+    .gy-card-circle-yellow {
+        background-color: #ffff00;
+    }
+
+    .gy-card-title {
+        position: relative;
+        top: 10px;
+        left: 10px;
+    }
+
+    .gy-card-decoration01 {
+        position: absolute;
+        right: 80px;
+    }
+
+    .gy-card-decoration02 {
+        position: absolute;
+        top: 20px;
+        right: 20px;
+    }
+
+    .gy-card-area-problem {
+        position: relative;
+        height: 89vh;
+        background-color: #292929;
+        border-radius: 7px;
+        margin: 0px;
+        padding-top: 0;
+        padding-left: 10px;
+        padding-right: 10px;
+        padding-bottom: 10px;
+        box-sizing: border-box;
+    }
+
+    .gy-card-area-alarm {
+        position: relative;
+        height: 25vh;
+        margin-top: 10px;
+        background-color: #292929;
+        border-radius: 7px;
+        padding-left: 10px;
+        padding-right: 10px;
+        padding-bottom: 10px;
+        box-sizing: border-box;
+    }
+
+    .gy-card-area-check {
+        position: relative;
+        height: 44vh;
+        background-color: #292929;
+        border-radius: 7px;
+        margin-top: 10px;
+        padding-top: 0;
+        padding-left: 10px;
+        padding-right: 10px;
+        padding-bottom: 10px;
+        box-sizing: border-box;
+    }
+
+    .gy-card-area-control {
+        position: relative;
+        width: 100%;
+        height: 44vh;
+        background-color: #292929;
+        border-radius: 7px;
+        margin: 0px;
+        padding-top: 0;
+        padding-left: 10px;
+        padding-right: 10px;
+        padding-bottom: 10px;
+        box-sizing: border-box;
+    }
+
+    .gy-card-area-label {
+        position: relative;
+        height: 25vh;
+        margin-top: 10px;
+        background-color: #292929;
+        border-radius: 7px;
+        padding-left: 10px;
+        padding-right: 10px;
+        padding-bottom: 10px;
+        box-sizing: border-box;
+    }
+
+    .gy-card-area-recommended {
+        position: relative;
+        height: 37vh;
+        background-color: #292929;
+        border-radius: 7px;
+        padding-left: 10px;
+        padding-right: 10px;
+        padding-bottom: 10px;
+        box-sizing: border-box;
+    }
+
+    .gy-card-header-hover {
+        position: relative;
+        height: 40px;
+        background-color: #292929;
+        color: white;
+        box-sizing: border-box;
+    }
+
+    .gy-card-area-problem:hover {
+        position: relative;
+        height: 89vh;
+        background-color: #292929;
+        border-radius: 7px;
+        margin: 0px;
+        padding-top: 0;
+        padding-left: 10px;
+        padding-right: 10px;
+        padding-bottom: 10px;
+        box-sizing: border-box;
+    }
+
+    .gy-card-area-alarm:hover {
+        position: relative;
+        height: 25vh;
+        margin-top: 10px;
+        background-color: #292929;
+        border-radius: 7px;
+        padding-left: 10px;
+        padding-right: 10px;
+        padding-bottom: 10px;
+        box-sizing: border-box;
+    }
+
+    .gy-card-area-label:hover {
+        position: relative;
+        height: 25vh;
+        margin-top: 10px;
+        background-color: #292929;
+        border-radius: 7px;
+        padding-left: 10px;
+        padding-right: 10px;
+        padding-bottom: 10px;
+        box-sizing: border-box;
+    }
+
+    .gy-card-area-recommended:hover {
+        position: relative;
+        height: 37vh;
+        background-color: #292929;
+        border-radius: 7px;
+        padding-left: 10px;
+        padding-right: 10px;
+        padding-bottom: 10px;
+        box-sizing: border-box;
+    }
+
+
+    .gy-card-area-big {
+        position: fixed;
+        top: 0px;
+        left: 0px;
+        width: 100vw;
+        height: 100vh;
+        background-color: #292929;
+        border-radius: 7px;
+        margin: 0px;
+        padding-top: 0;
+        padding-left: 10px;
+        padding-right: 10px;
+        padding-bottom: 10px;
+        box-sizing: border-box;
+        z-index: 900;
+    }
+
+    .gy-card-content-big {
+        position: relative;
+        height: calc(100vh - 50px);
+        background-color: #000000;
+        color: white;
+        box-sizing: border-box;
+        border-radius: 7px;
+    }
+
+    .el-scrollbar__wrap {
+        overflow: scroll;
+        width: 110%;
+        height: 120%;
+    }
+
+    ::-webkit-scrollbar {
+        width: 0;
+        height: 0;
+    }
+
+    .scroll {
+        color: #ffffff;
+        min-height: 300px;
+        height: 400px;
+    }
+
+
+    .content {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        width: 80px;
+        color: #ffffff;
+        height: 25px;
+        border: 1px solid blue;
+        margin-right: 10px;
+        margin-bottom: 10px;
+    }
+
+    .content_on {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        width: 80px;
+        color: #ffffff;
+        height: 25px;
+        border: 1px solid blue;
+        margin-right: 10px;
+        margin-bottom: 10px;
+        background-color: chartreuse;
+    }
+</style>

+ 438 - 0
src/components/basicDataDetails.vue

@@ -0,0 +1,438 @@
+<template>
+    <el-dialog width="50%" @closed="closed()" :show-close="false" class="my-info-dialog">
+        <template #title>
+            <div class="showTitles">
+                <div class="titles">{{partsName}}详情</div>
+                <div class="model">
+                    <div class="selects" v-show="!switchFlag">
+                        <!-- filterable allow-create default-first-option -->
+                        <el-select @change="search()" class="inputs" v-model="selectValue" placeholder="请选择">
+                            <el-option v-for="item in options" :key="item.value" :label="item.label"
+                                :value="item.value">
+                            </el-option>
+                        </el-select>
+                    </div>
+                    <div class="choose">
+                        <div :class="switchFlag?'interval':'interval_on'" @click="switchChange">等间隔</div>
+                        <div :class="switchFlag?'original_on':'original'" @click="switchChange">原始数据</div>
+                    </div>
+                </div>
+            </div>
+        </template>
+        <div class="bodys">
+            <div class="dataTitle">
+                <div class="operate">
+                    <el-date-picker class="picker" @change="changes" v-model="timeValue" type="datetimerange"
+                        range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期">
+                    </el-date-picker>
+                    <div class="buttons" @click="search()">查询</div>
+                </div>
+                <div class="buttons" @click="search('flag')">导出</div>
+            </div>
+            <div :id="echartsId" class="showEcharts"></div>
+        </div>
+    </el-dialog>
+</template>
+<script>
+    import * as echarts from "echarts";
+    import dayjs from 'dayjs'
+    import XLSX from 'xlsx'
+    export default {
+        props: {
+            datas: {
+                type: Array,
+                default: () => {
+                    return []
+                },
+            },
+            partsName: Object,
+            echartsId: Object,
+        },
+        updated() {
+            if (this.timeValue.length === 0) {
+                let date = new Date()
+                this.timeValue[0] = date.getTime() - 28800000
+                this.timeValue[1] = date.getTime()
+            }
+            this.chooseTime = this.timeValue
+            this.xdata = []
+            this.values = []
+            if ((this.timeValue[1] - this.timeValue[0]) <= 86400000) {
+                this.datas.map(item => {
+                    this.xdata.push(dayjs(item.ts).format('HH:mm'))
+                    this.values.push(item.doubleValue ? item.doubleValue.toFixed(2) : item.doubleValue === 0 ? item.doubleValue : item.longValue)
+                })
+                console.log(this.values)
+            } else {
+                this.datas.map(item => {
+                    this.xdata.push(dayjs(item.ts).format('MM-DD HH:mm'))
+                    this.values.push(item.doubleValue ? item.doubleValue.toFixed(2) : item.doubleValue === 0 ? item.doubleValue : item.longValue)
+                })
+            }
+            this.getEcharts()
+        },
+        mounted() {
+
+        },
+        data() {
+            return {
+                xdata: [],
+                values: [],
+                timeValue: [],
+                chooseTime: [],
+                switchFlag: false,
+                selectValue: '60',
+                options: [{
+                    value: '60',
+                    label: '一分钟'
+                }, {
+                    value: '300',
+                    label: '五分钟'
+                }, {
+                    value: '600',
+                    label: '十分钟'
+                }, {
+                    value: '1800',
+                    label: '三十分钟'
+                }, {
+                    value: '3600',
+                    label: '一小时'
+                }, {
+                    value: '86400',
+                    label: '一天'
+                }],
+            }
+        },
+        methods: {
+            changes() {
+                let timeValue = []
+                this.timeValue?.forEach(item => {
+                    timeValue.push(dayjs(item).valueOf())
+                })
+                this.chooseTime = timeValue
+            },
+            switchChange() {
+                this.switchFlag = !this.switchFlag
+                this.selectValue = '60'
+                this.search();
+                const loading = this.$loading({
+                    lock: true,
+                    text: '数据加载中',
+                    spinner: 'el-icon-loading',
+                    background: 'rgba(0, 0, 0, 0.7)'
+                });
+                setTimeout(() => {
+                    loading.close();
+                }, 1000);
+            },
+            search(values) {
+                let times = []
+                this.chooseTime.forEach(item => {
+                    times.push(dayjs(item).valueOf())
+                })
+                times.length > 0 ?
+                    this.switchFlag ? this.$emit('original-data', times) : this.$emit('search-data', times, Number(this.selectValue))
+                    :
+                    this.$message({
+                        showClose: true,
+                        message: '请选择查询日期',
+                        center: true,
+                        type: 'error'
+                    });
+                if (values) {
+                    this.$message({
+                        showClose: true,
+                        center: true,
+                        message: '下载中'
+                    });
+                    setTimeout(() => {
+                        this.export()
+                    }, 2000)
+                }
+            },
+            export() {
+                // 数据源
+                let data = []
+                this.datas.forEach(item => {
+                    let values = {
+                        '时间': dayjs(item.ts).format('MM-DD HH:mm:ss'),
+                        '数值': item.doubleValue,
+                    }
+                    data.push(values)
+                })
+                // 下载的路径
+                let fileName = `${this.partsName}.xlsx`
+                let filePath = '/root/' + fileName
+                // 新建workbook
+                const wb = XLSX.utils.book_new()
+                // 新建worksheet,并载入数据
+                const ws = XLSX.utils.json_to_sheet(data)
+                // 设置每列的列宽,10代表10个字符,注意中文占2个字符
+                ws['!cols'] = [
+                    { wch: 30 },
+                    { wch: 30 },
+                ]
+                // 生成xlsx文件(workbook,worksheet数据,sheet命名)
+                XLSX.utils.book_append_sheet(wb, ws, 'Sheet1')
+
+                // 写文件(workbook,xlsx文件路径+文件名)
+                XLSX.writeFile(wb, filePath)
+                this.$message({
+                    showClose: true,
+                    message: '下载成功',
+                    center: true,
+                    type: 'success'
+                });
+            },
+            getEcharts() {
+                let chartDom = document.getElementById(this.echartsId);
+                let myChart = echarts.init(chartDom, '#ffffff');
+                let option;
+                option = {
+                    legend: {
+                        show: true,
+                        data: [this.partsName],
+                        right: 56,
+                        icon: "circle",
+                        itemWidth: 6,
+                        inactiveColor: '#606769',
+                        textStyle: {
+                            color: '#B3BDC0',
+                            fontSize: 12,
+                        },
+                    },
+                    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: 14,
+                                textStyle: {
+                                    color: '#606769',
+                                },
+                            },
+                            axisLine: {
+                                show: false,
+                            },
+                            data: this.xdata,
+                        },
+                    ],
+                    yAxis: {
+                        type: "value",
+                        axisLabel: {
+                            formatter: "{value}",
+                            fontSize: 14,
+                        },
+                        axisLine: {
+                            show: false,
+                        },
+                        splitLine: {
+                            show: true,
+                            lineStyle: {
+                                color: '#606769',
+                                type: "dashed",
+                            },
+                        },
+                    },
+                    series: [{
+                        // name: this.partsName,
+                        smooth: true,
+                        showSymbol: false,
+                        data: this.values,
+                        type: 'line'
+                    }]
+                };
+                option && myChart.setOption(option);
+            },
+            closed() {
+                this.chooseTime = []
+                this.timeValue = []
+                this.switchFlag = false
+                this.selectValue = '60'
+                this.$emit('closed');
+            },
+        },
+    }
+</script>
+
+<style>
+    .showTitles {
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        justify-content: space-between;
+        margin-top: -10px;
+        font-size: 18px;
+        color: #FFFFFF;
+        height: 40px;
+    }
+
+    .titles {
+        font-size: 16px;
+        color: #FFFFFF;
+    }
+
+    .el-dialog__body {
+        padding: 30px 10px 10px 10px;
+    }
+
+    .bodys {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        background-color: black;
+        width: 100%;
+        margin-top: -30px;
+    }
+
+    .showEcharts {
+        width: 1030px;
+        height: 480px;
+        margin-left: 30px;
+        /* padding-top: 20px; */
+    }
+
+    .dataTitle {
+        width: 100%;
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        justify-content: space-between;
+        margin-top: 10px;
+    }
+
+    .picker {
+        margin-left: 20px;
+        margin-right: 16px;
+    }
+
+    .el-date-editor .el-range-input {
+        background-color: rgba(26, 26, 26, 1) !important;
+        border: none;
+        color: #ffffff !important;
+    }
+
+    .el-input__inner {
+        background-color: rgba(26, 26, 26, 1) !important;
+    }
+
+    .el-date-editor .el-range-separator {
+        color: #ffffff !important;
+    }
+
+    .el-date-table td.in-range div,
+    .el-date-table td.in-range div:hover,
+    .el-date-table.is-week-mode .el-date-table__row.current div,
+    .el-date-table.is-week-mode .el-date-table__row:hover div {
+        background-color: #CECEFF !important;
+    }
+
+    .operate {
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        justify-content: center;
+        /* margin-right: 65px; */
+    }
+
+    .buttons {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        width: 100px;
+        height: 40px;
+        background-color: rgba(26, 26, 26, 1);
+        border: 1px solid rgba(77, 77, 77, 1);
+        color: #ffffff;
+        margin-right: 28px;
+        font-size: 12px;
+    }
+
+    .model {
+        display: flex;
+        flex-direction: row;
+        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>

+ 180 - 0
src/components/boxSelect.vue

@@ -0,0 +1,180 @@
+<template>
+    <div class="box-select__container" @mousedown.left="mouseDown" @mousemove.stop="mouseMove" :class="uuid">
+        <div class="box-select__coordinate" :style="style" ref="selectContainer"></div>
+        <slot></slot>
+    </div>
+</template>
+
+<script>
+    import { debounce, isNumber } from "lodash"
+    import { ref, onUnmounted, nextTick, shallowRef } from "vue"
+
+    /**
+     * @description 判断元素是否在范围内
+     * @param {Object} dom dom元素
+     */
+    const isWithinRange = (dom, top, bottom, left, right) => {
+        const eleRect = dom.getBoundingClientRect()
+        return !(
+            eleRect.top > bottom ||
+            eleRect.bottom < top ||
+            eleRect.right < left ||
+            eleRect.left > right
+        )
+    }
+
+    export default {
+        name: "BoxSelect",
+        /**
+         * @member props
+         * @property  {String} [node] 要框选的元素,可以是元素名,也可以是class名, 也可以是id名
+         * @property  {String} [selectedClass] 已选中元素附加的class名
+         */
+        props: {
+            node: {
+                required: true,
+                type: String
+            },
+            selectedClass: {
+                type: String,
+                default: 'box-select__hypocritical'
+            }
+        },
+        // 鼠标按下
+        emits: ["mouseUp", "mouseDown"],
+        setup(props, { emit }) {
+            let top = 0,
+                left = 0,
+                width = 0,
+                height = 0,
+                startX = 0,
+                startY = 0,
+                timer = null,
+                // 记录是框选还是点击
+                mouseOn = false
+
+            const style = ref({}),
+                selectContainer = ref(null),
+                // 给当前框容器加一个唯一识别符, 以保证所选择到的元素都是当前容器的. 否则会选择到容器外同名的元素
+                uuid = shallowRef("uuid_" + new Date().valueOf())
+
+            const query = (className = '') => {
+                let domName = `.${uuid.value} ${props.node}`
+                className && (domName += `.${className}`)
+                return Array.from(document.querySelectorAll(domName) || [])
+            }
+
+            const classOperation = (ele, method = 'add', className = '') => ele.classList[method](className)
+
+            const setStyle = (styles = {}, newStyles = {}) => {
+                Object.keys(styles).map((item) => {
+                    newStyles[item] = styles[item] + (isNumber(styles[item]) ? "px" : '')
+                })
+                style.value = newStyles
+            }
+
+            const getAreaWithinElements = () => {
+                const {
+                    bottom,
+                    left,
+                    right,
+                    top
+                } = selectContainer.value.getBoundingClientRect()
+
+                // 所有可框选元素
+                const elements = query()
+                // 已选中元素
+                const selectedElements = elements.filter(item => classOperation(item, 'contains', props.selectedClass))
+                // 未选中元素
+                const unselectedElements = elements.filter(item => !classOperation(item, 'contains', props.selectedClass))
+
+                selectedElements.map(item => {
+                    const withinRange = isWithinRange(item, top, bottom, left, right)
+                    withinRange &&
+                        classOperation(item, 'contains', props.selectedClass) &&
+                        classOperation(item, 'remove', props.selectedClass)
+                })
+
+                unselectedElements.map((item) =>
+                    isWithinRange(item, top, bottom, left, right) &&
+                    classOperation(item, 'add', props.selectedClass))
+
+                return query(props.selectedClass)
+            }
+
+            const mouseDown = debounce((event) => {
+                timer = setTimeout(() => {
+                    mouseOn = true
+                    startX = event.clientX
+                    startY = event.clientY
+                    emit("mouseDown")
+                }, 300)
+                // 重置本次框选的元素列表
+                setStyle({ left, startX, top: startY, width: 0, height: 0, display: "block" })
+            })
+
+            const mouseMove = debounce((event) => {
+                if (!mouseOn) return false
+                const _width = event.clientX - startX
+                const _height = event.clientY - startY
+
+                top = _height > 0 ? startY : event.clientY
+                left = _width > 0 ? startX : event.clientX
+                width = Math.abs(_width)
+                height = Math.abs(_height)
+                setStyle({ left, top, width, height })
+            })
+
+            const mouseUp = debounce((event) => {
+                timer && clearTimeout(timer)
+                // 判断是否鼠标左键
+                if (event.which !== 1) return false
+                // 判断是框选还是点击
+                if (!mouseOn) return false
+                mouseOn = false
+                setStyle({ display: "none" })
+                // 获得已选中的元素
+                const selectedEles = getAreaWithinElements()
+                // 响应事件,并传递本次框选的元素列表
+                emit("mouseUp", selectedEles)
+            })
+
+            nextTick(() => document.addEventListener("mouseup", mouseUp))
+            onUnmounted(() => document.removeEventListener("mouseup", mouseUp))
+
+            return {
+                mouseUp,
+                mouseDown,
+                mouseMove,
+                timer,
+                style,
+                selectContainer,
+                uuid
+            }
+        }
+    }
+</script>
+
+<style lang="scss">
+    .box-select__container {
+        background-color: #ffffff;
+        height: 50vh;
+    }
+
+    .box-select__coordinate {
+        position: fixed;
+        z-index: 11;
+        left: 0;
+        top: 0;
+        width: 0;
+        height: 0;
+        background: rgba(0, 0, 0, .5);
+        border: 1px solid rgba(0, 0, 0, 1);
+        opacity: 0.6;
+        pointer-events: none;
+    }
+
+    .box-select__hypocritical {
+        background-color: blue;
+    }
+</style>

+ 186 - 0
src/components/check/areaCard.vue

@@ -0,0 +1,186 @@
+/* 自定义tabs */
+<template>
+    <!-- <transition>
+        <div :class='areaClass' @mouseover="hover = false" @mouseleave="hover = false" onselectstart="return false">
+            <div :class="headerClass">
+                <div :class='circleClass'></div>
+                <span class="gy-card-title">{{ title }}</span>
+                <img class="gy-card-decoration01" src="../../assets/img/controlcenter/decoration01.png">
+                <img class="gy-card-decoration02" src="../../assets/img/controlcenter/decoration02.png">
+            </div>
+            <div :class='contentClass'>
+                <el-scrollbar style="height: 100%">
+                    <slot></slot>
+                </el-scrollbar>
+            </div>
+        </div>
+    </transition> -->
+    <div class="body">
+        <img class="logo" src="../../assets/img/logo.png" alt="">
+        <div class="title">{{ title }}</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;">
+                    <MatrixBlock  @on-click="handleClick" :dataList="showList"></MatrixBlock>
+                </div>
+            </el-scrollbar>
+        </div>
+        <OperationRecords ref="records" v-model="display" @closed="closed()"></OperationRecords>
+        <WindturbineDetailPages v-model="dialogVisible" @close="handleClose" :windturbine="currentWindturbine">
+    </WindturbineDetailPages>
+    </div>
+</template>
+
+<script>
+    import BackgroundData from 'utils/BackgroundData'
+    import MatrixBlock from "../matrixBlock.vue";
+    import OperationRecords from "./operationRecords.vue";
+    import WindturbineDetailPages from "../WindturbineDetailPages.vue";
+    export default {
+        props: {
+            title: {
+                type: String,
+                default: '校验区',
+                required: true
+            },
+            height: {
+                type: Number,
+                default: 200,
+            },
+        },
+        components: {
+            MatrixBlock,
+            OperationRecords,
+            WindturbineDetailPages
+        },
+        data() {
+            return {
+                showList: [],
+                arr: [],
+                list: [],
+                display:false,
+                dialogVisible:false,
+                currentWindturbine: {},
+            }
+        },
+        methods: {
+            dataDeal() {
+                let flag = false
+                let showList = []
+                let arr = []
+                let checks = BackgroundData.getInstance().checkouts;
+                checks.forEach(item => {
+                    if (item.status === this.list[item.windturbineId].status) {
+                        showList.push(this.list[item.windturbineId])
+                    } else {
+                        BackgroundData.getInstance().removeCheckouts(item);
+                    }
+                    if ((new Date()).getTime() - item.checkTime > 120000) {
+                        BackgroundData.getInstance().removeCheckouts(item);
+                        arr.push(item.windturbineId)
+                        flag = true
+                    }
+                })
+                this.showList = showList
+                if (flag) {
+                    let mss = arr.join(',') + '风机超时未响应,已移除'
+                    this.$notify({
+                        title: "控制",
+                        message: mss,
+                        type: "warning",
+                        position: "bottom-right",
+                        offset: 60,
+                        duration: 3000,
+                    });
+                    flag = false
+                }
+            },
+            showRecord(){
+                this.display = true
+                this.$refs.records.dataDeal() 
+            },
+            closed(){
+                this.display = false
+            },
+            handleClick(itm) {
+                this.dialogVisible = true;
+                this.currentWindturbine = itm;
+            },
+            handleClose() {
+                this.dialogVisible = false
+            },
+        },
+        watch: {
+            "$store.getters.windturbinelist": {
+                deep: true,
+                handler: function (json) {
+                    this.list = json
+                    this.arr = BackgroundData.getInstance().checkouts;
+                    this.dataDeal()
+                },
+            },
+        },
+    }
+</script>
+
+<style scoped="scoped">
+    .body {
+        border: 1px solid #373737;
+        width: 100%;
+        margin-left: 15px;
+        margin-top: 10px;
+        height: 25vh;
+    }
+
+    .body .scoll {
+        height: 91%;
+    }
+
+    .title {
+        color: #ffffff;
+        font-size: 14px;
+        margin-left: 32px;
+        /* margin-top: 12px; */
+        margin-bottom: 10px;
+        /* width: 570px; */
+        width: 29vw;
+        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: #54B75A;
+        border-radius: 50%;
+    }
+
+    .record {
+        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);
+    }
+
+    .logo {
+        position: absolute;
+        top: 2px;
+        left: 12px;
+    }
+</style>

+ 33 - 0
src/components/check/checkArea.vue

@@ -0,0 +1,33 @@
+<template>
+  <div class="problem">
+    <AreaCard title="校验区" height="25"></AreaCard>
+  </div>
+</template>
+
+<script>
+  import AreaCard from "./areaCard.vue";
+  import BackgroundData from 'utils/BackgroundData'
+  export default {
+    name: "ProblemArea",
+    components: {
+      AreaCard,
+    },
+    props: {},
+    data() {
+      return {
+      };
+    },
+    computed: {},
+    created: function () {
+
+    },
+    methods: {
+      
+    },
+  };
+</script>
+<style scoped>
+  .problem {
+    height: 100%;
+  }
+</style>

+ 393 - 0
src/components/check/operationRecords.vue

@@ -0,0 +1,393 @@
+<template>
+    <el-dialog width="50%" @open="opened()" @closed="closed()" :show-close="false" class="my-info-dialog">
+        <template #title>
+            <div class="showTitles">
+                <div class="titles">校验记录详情</div>
+            </div>
+        </template>
+        <div class="bodys">
+            <!-- <el-cascader ref="cascaderHandle" :options="options" :props="{ checkStrictly: true }" clearable @change="handleChange">
+            </el-cascader> -->
+            <div class="left">
+                <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="rights">
+                <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:86%;">
+                    <div class="tables">
+                        <el-table :data="recordData" class="table" style=" width:100%" height="49vh" :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="windturbineId" label="风机号" width="120" align="center">
+                            </el-table-column>
+                            <el-table-column prop="controls" label="控制命令" width="120" align="center">
+                            </el-table-column>
+                            <el-table-column prop="result" label="操作结果" align="center">
+                            </el-table-column>
+                            <el-table-column prop="userName" label="操作人" width="120" 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>
+
+    </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,
+                datas: {},
+                chooseStation: {},
+                timeValue: [],
+                showData: [
+                    {
+                        id: 0,
+                        windturbineId: '全部',
+                        stationId: "",
+                        children: [
+                            {
+                                id: 1,
+                                windturbineId: '麻黄山',
+                                stationId: "MHS_FDC",
+                                children: []
+                            }, {
+                                id: 2,
+                                windturbineId: '牛首山',
+                                stationId: "NSS_FDC",
+                                children: []
+                            }, {
+                                id: 3,
+                                windturbineId: '青山',
+                                stationId: "QS_FDC",
+                                children: []
+                            }, {
+                                id: 4,
+                                windturbineId: '石板泉',
+                                stationId: "SBQ_FDC",
+                                children: []
+                            }, {
+                                id: 5,
+                                windturbineId: '香山',
+                                stationId: "XS_FDC",
+                                children: []
+                            },
+                        ]
+                    },
+                ],
+                defaultProps: {
+                    children: 'children',
+                    label: 'windturbineId'
+                },
+                recordData: [],
+                total: '',
+                controlErorCodes: [
+                    "控制成功",
+                    "控制命令发送失败",
+                    "无效的控制地址",
+                    "被控设备异常",
+                    "无效的控制功能",
+                    "网络连接错误,检查场站通信",
+                    "控制结果读取超时",
+                    "未知错误",
+                    "控制命令错误",
+                    "收到无法识别数据",
+                    "未读取到数据包",
+                    "未知错误",
+                    "风机操作过频繁",
+                    "风机被挂牌",
+                    "风机操作与风机状态不符",
+                    "需要登录",
+                ],
+            };
+        },
+        methods: {
+            dataDeal() {
+                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];
+                    switch (item.windturbineId.slice(0, 2)) {
+                        case 'MG':
+                            this.showData[0].children[0].children.push(item)
+                            break;
+                        case 'NG':
+                            this.showData[0].children[1].children.push(item)
+                            break;
+                        case 'QG':
+                            this.showData[0].children[2].children.push(item)
+                            break;
+                        case 'SG':
+                            this.showData[0].children[3].children.push(item)
+                            break;
+                        case 'XG':
+                            this.showData[0].children[4].children.push(item)
+                            break;
+                    }
+                }
+                console.log(this.showData);
+            },
+            handleChange(value) {
+                this.chooseStation = value
+                this.pageIndex = 1
+                this.getControlRecord(value)
+            },
+            closed() {
+                this.pageIndex = 1
+                this.chooseStation = {}
+                this.showData = [
+                    {
+                        id: 0,
+                        windturbineId: '全部',
+                        stationId: "",
+                        children: [
+                            {
+                                id: 1,
+                                windturbineId: '麻黄山',
+                                stationId: "MHS_FDC",
+                                children: []
+                            }, {
+                                id: 2,
+                                windturbineId: '牛首山',
+                                stationId: "NSS_FDC",
+                                children: []
+                            }, {
+                                id: 3,
+                                windturbineId: '青山',
+                                stationId: "QS_FDC",
+                                children: []
+                            }, {
+                                id: 4,
+                                windturbineId: '石板泉',
+                                stationId: "SBQ_FDC",
+                                children: []
+                            }, {
+                                id: 5,
+                                windturbineId: '香山',
+                                stationId: "XS_FDC",
+                                children: []
+                            },
+                        ]
+                    },
+                ],
+                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.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]
+                        })
+                        this.total = res.data.total
+                        this.recordData = res.data.dataList
+                    }
+                })
+            },
+        },
+        watch: {
+            filterText(val) {
+                this.$refs.tree.filter(val);
+            }
+        },
+    }
+</script>
+
+<style scoped>
+    .showTitles {
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        justify-content: space-between;
+        margin-top: -10px;
+        font-size: 18px;
+        color: #FFFFFF;
+        height: 40px;
+    }
+
+    .titles {
+        font-size: 16px;
+        color: #FFFFFF;
+    }
+
+    .el-dialog__body {
+        padding: 30px 10px 10px 10px;
+    }
+
+    .bodys {
+        display: flex;
+        flex-direction: row;
+        background-color: black;
+        width: 100%;
+        margin-top: -30px;
+        height: 60vh;
+    }
+
+    .left {
+        width: 20%;
+        height: 100%;
+        background-color: rgba(77, 77, 77, 1);
+        border-right: 2px solid #000000;
+    }
+
+    .rights {
+        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>

+ 972 - 0
src/components/control/areaCard.vue

@@ -0,0 +1,972 @@
+/* 自定义tabs */
+<template>
+  <div class="body" :style="style">
+    <img class="logo" src="../../assets/img/logo.png" alt="" />
+    <div class="title">
+      <div>{{ title }}</div>
+      <div style="display: flex; flex-direction: row; align-items: center">
+        <div v-for="(item, index) in controlTypeList" :key="index">
+          <div
+            v-if="!item.type"
+            :class="
+              index === 0
+                ? 'controlTypesLeft'
+                : index === 4
+                ? 'controlTypesRight'
+                : 'controlTypes'
+            "
+            @click="handleTypeChange(item)"
+          >
+            {{ item.name }}
+          </div>
+          <div
+            v-if="item.type"
+            :class="
+              index === 0
+                ? 'onControlTypesLeft'
+                : index === 4
+                ? 'onControlTypesRight'
+                : 'onControlTypes'
+            "
+            @click="handleTypeChange(item)"
+          >
+            {{ item.name }}
+          </div>
+        </div>
+      </div>
+    </div>
+    <div style="margin-top: 50px; height: 85%" @contextmenu="contextmenu">
+      <div class="scoll currentScroll">
+        <div class="currentScroll" style="height: 100%; overflow-y: scroll">
+          <div class="matrix" v-if="startList.length > 0">
+            <div class="problemTitle">启动</div>
+            <MatrixBlock
+              @on-click="handleDetial"
+              @choose-click="handleClick"
+              :dataList="startList"
+            >
+            </MatrixBlock>
+          </div>
+          <div class="matrix" v-if="stopList.length > 0">
+            <div class="problemTitle">停机</div>
+            <MatrixBlock
+              @on-click="handleDetial"
+              @choose-click="handleClick"
+              :dataList="stopList"
+            >
+            </MatrixBlock>
+          </div>
+          <div class="matrix" v-if="maintainList.length > 0">
+            <div class="problemTitle">维护</div>
+            <MatrixBlock
+              @on-click="handleDetial"
+              @choose-click="handleClick"
+              :dataList="maintainList"
+            >
+            </MatrixBlock>
+          </div>
+          <div class="matrix" v-if="unMaintainList.length > 0">
+            <div class="problemTitle">取消维护</div>
+            <MatrixBlock
+              @on-click="handleDetial"
+              @choose-click="handleClick"
+              :dataList="unMaintainList"
+            >
+            </MatrixBlock>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div v-if="current == 1" class="send" @click="handleSend">发送</div>
+    <!-- <div class="success" v-if="showFlag&&current===0">指令发送成功</div> -->
+  </div>
+  <WindturbineDetailPages
+    v-model="dialogVisible"
+    @close="handleClose"
+    :windturbine="currentWindturbine"
+  >
+  </WindturbineDetailPages>
+  <StationSvgDetailPages
+    v-model="svgVisible"
+    :stationName="stationName"
+    :svgWeb="svgWeb"
+    @close="handleClose"
+  >
+  </StationSvgDetailPages>
+</template>
+
+<script>
+import BackgroundData from "utils/BackgroundData";
+import WindturbineDetailPages from "../WindturbineDetailPages.vue";
+import MatrixBlock from "../matrixBlock.vue";
+import MessageBridge from "utils/MessageBridge";
+import api from "api/index";
+import StationSvgDetailPages from "../stationSvgDetailPages.vue";
+export default {
+  name: "gy-card",
+  components: {
+    MatrixBlock,
+    WindturbineDetailPages,
+    StationSvgDetailPages,
+  },
+  created: function () {
+    this.initData();
+    this.suggestion();
+    this.getControlType();
+  },
+  emits: ["parentRun"],
+  props: {
+    title: {
+      type: String,
+      default: "",
+      required: true,
+    },
+    height: {
+      type: Number,
+      default: 200,
+    },
+  },
+  data() {
+    return {
+      current: 1,
+      windturbinelist: {},
+      titleList: [],
+      startList: [],
+      stopList: [],
+      maintainList: [],
+      unMaintainList: [],
+      chooseList: [],
+      sendList: [],
+      currentWindturbine: {},
+      dialogVisible: false,
+      svgVisible: false,
+      // showFlag: false,
+      svgWeb: "",
+      stationName: "",
+      // 定时器
+      timer: "",
+      controlTypeList: [],
+      controlErorCodes: [
+        "控制成功",
+        "控制命令发送失败",
+        "无效的控制地址",
+        "被控设备异常",
+        "无效的控制功能",
+        "网络连接错误,检查场站通信",
+        "控制结果读取超时",
+        "未知错误",
+        "控制命令错误",
+        "收到无法识别数据",
+        "未读取到数据包",
+        "未知错误",
+        "风机操作过频繁",
+        "风机被挂牌",
+        "风机操作与风机状态不符",
+        "需要登录",
+      ],
+    };
+  },
+  computed: {
+    style() {
+      return `width: 100%; height: ${this.height}vh;`;
+    },
+  },
+  methods: {
+    getControlType() {
+      api.getControlType().then((res) => {
+        if (res) {
+          this.controlTypeList = res.data;
+        }
+      });
+    },
+    control(current) {
+      this.current = current === 0 ? current : current === 1 ? current : 1;
+      this.suggestion();
+    },
+    initData: function () {
+      let mb = MessageBridge.getInstance();
+      mb.unregister({ key: "/topic/suggestion" });
+      let vs = [{ key: "/topic/suggestion", action: this.suggestion }];
+      let vss = [
+        { key: "/topic/voice-control", action: this.windturbineMessage },
+      ];
+      this.vss = vss;
+      mb.register(vs);
+      mb.register(vss);
+    },
+    suggestion(msg, headers) {
+      msg ? this.$store.commit("suggestion", JSON.parse(msg)) : "";
+      let bd = BackgroundData.getInstance();
+      this.titleList = msg ? JSON.parse(msg) : this.$store.state.suggestion;
+      if (this.current === 0) {
+        let dateList = [];
+        this.titleList.forEach((item) => {
+          let status = this.controlTypeList.filter(
+            (val) =>
+              val.stationId ===
+              this.windturbinelist[item.windturbineId].stationId
+          )[0].type;
+          if (status) {
+            let arr = Object.keys(this.windturbinelist).sort();
+            this.windturbinelist =
+              arr.length !== 0
+                ? this.windturbinelist
+                : this.$store.state.windturbinelist;
+            switch (item.operateStyle) {
+              case "Start":
+                this.windturbinelist[item.windturbineId].controlType = 1;
+                break;
+              case "Stop":
+                this.windturbinelist[item.windturbineId].controlType = 2;
+                break;
+              case "Maintain":
+                this.windturbinelist[item.windturbineId].controlType = 6;
+                break;
+              case "UnMaintain":
+                this.windturbinelist[item.windturbineId].controlType = 8;
+                break;
+            }
+            dateList.push(this.windturbinelist[item.windturbineId]);
+          }
+        });
+        let mss = {};
+        mss.type = "send";
+        mss.deviceType = "Auto";
+        this.timer = setTimeout(() => {
+          if (dateList.length > 0) {
+            this.sendCommand(mss, dateList);
+          }
+          // this.showFlag = true
+          clearInterval(this.timer);
+        }, 3000);
+      }
+    },
+    windturbineMessage(msg) {
+      if (this.$store.state.current === 1 || this.$store.state.current === 0) {
+        let arr = [];
+        if (msg === "CLOSE") {
+          arr.push(msg);
+        } else {
+          arr = msg.split("-");
+        }
+        this.dialogVisible = false;
+        this.svgVisible = false;
+        this.svgWeb = "";
+        if (arr[0] === "OPEN_FJ") {
+          this.currentWindturbine = this.windturbinelist[arr[1]];
+          setTimeout(() => {
+            this.dialogVisible = true;
+          }, 500);
+        } else if (arr[0] === "CLOSE") {
+          this.dialogVisible = false;
+          this.svgVisible = false;
+        } else if (arr[0] === "OPEN_SYZ") {
+          this.showSvg = true;
+          this.svgVisible = true;
+          this.svgWeb = arr[1];
+          this.stationName = this.boosterStation[arr[1]].name;
+        } else if (
+          arr[0] === "CONTROL_START" ||
+          arr[0] === "CONTROL_STOP" ||
+          arr[0] === "CONTROL_MAINTAIN" ||
+          arr[0] === "CONTROL_UNMAINTAIN"
+        ) {
+          let windControlList = [];
+          let mss = {};
+          arr.forEach((item) => {
+            if (
+              item ===
+              (this.windturbinelist[item]
+                ? this.windturbinelist[item].windturbineId
+                : "")
+            ) {
+              switch (arr[0]) {
+                case "CONTROL_START":
+                  this.windturbinelist[item].controlType = "1";
+                  break;
+                case "CONTROL_STOP":
+                  this.windturbinelist[item].controlType = "2";
+                  break;
+                case "CONTROL_MAINTAIN":
+                  this.windturbinelist[item].controlType = "6";
+                  break;
+                case "CONTROL_UNMAINTAIN":
+                  this.windturbinelist[item].controlType = "8";
+                  break;
+              }
+              windControlList.push(this.windturbinelist[item]);
+            }
+          });
+          mss.type = "send";
+          this.sendCommand(mss, windControlList);
+        } else if (
+          arr[0] === "CONTROL_LOCK_OVERHAUL" ||
+          arr[0] === "CONTROL_LOCK_MAINTAIN" ||
+          arr[0] === "CONTROL_LOCK_LNVOLVED_OVERHAUL" ||
+          arr[0] === "CONTROL_LOCK_LNVOLVED_MAINTAIN" ||
+          arr[0] === "CONTROL_LOCK_LNVOLVED_PG" ||
+          arr[0] === "CONTROL_LOCK_LNVOLVED_WEATHER" ||
+          arr[0] === "CONTROL_UNLOCK"
+        ) {
+          let windturbine = this.windturbinelist[arr[1]];
+          switch (arr[0]) {
+            case "CONTROL_LOCK":
+              this.sendLock({ value: "Lock" }, windturbine);
+              break;
+            case "CONTROL_LOCK_OVERHAUL":
+              this.sendLock({ value: "CheckLock" }, windturbine);
+              break;
+            case "CONTROL_LOCK_MAINTAIN":
+              this.sendLock({ value: "FaultLock" }, windturbine);
+              break;
+            case "CONTROL_LOCK_LNVOLVED_OVERHAUL":
+              this.sendLock({ value: "StationCheckLock" }, windturbine);
+              break;
+            case "CONTROL_LOCK_LNVOLVED_MAINTAIN":
+              this.sendLock({ value: "StationFaulLock" }, windturbine);
+              break;
+            case "CONTROL_LOCK_LNVOLVED_PG":
+              this.sendLock({ value: "StationPowerLineLock" }, windturbine);
+              break;
+            case "CONTROL_LOCK_LNVOLVED_WEATHER":
+              this.sendLock({ value: "StationWeatherLock" }, windturbine);
+              break;
+            case "CONTROL_UNLOCK":
+              this.sendLock({ value: "UnLock" }, windturbine);
+              break;
+          }
+        } else if (arr[0] === "CONTROL_SART_RECOMMENDATION") {
+          let mss = {};
+          mss.type = "send";
+          this.startList.forEach((item) => {
+            item.controlType = "1";
+          });
+          this.sendCommand(mss, this.startList);
+        } else if (arr[0] === "CONTROL_STOP_RECOMMENDATION") {
+          let mss = {};
+          mss.type = "send";
+          this.stopList.forEach((item) => {
+            item.controlType = "2";
+          });
+          this.sendCommand(mss, this.stopList);
+        } else if (arr[0] === "CONTROL_RECOMMENDATION_ALL") {
+          let windControlList = [];
+          let mss = {};
+          mss.type = "send";
+          this.startList.forEach((item) => {
+            item.controlType = "1";
+            windControlList.push(item);
+          });
+          this.stopList.forEach((item) => {
+            item.controlType = "2";
+            windControlList.push(item);
+          });
+          this.maintainList.forEach((item) => {
+            item.controlType = "6";
+            windControlList.push(item);
+          });
+          this.unMaintainList.forEach((item) => {
+            item.controlType = "8";
+            windControlList.push(item);
+          });
+          this.sendCommand(mss, windControlList);
+        }
+      }
+    },
+    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.startList.forEach((item) => {
+        if (item.windturbineId === values.windturbineId) {
+          item.active = !item.active;
+        }
+      });
+      this.stopList.forEach((item) => {
+        if (item.windturbineId === values.windturbineId) {
+          item.active = !item.active;
+        }
+      });
+      this.maintainList.forEach((item) => {
+        if (item.windturbineId === values.windturbineId) {
+          item.active = !item.active;
+        }
+      });
+      this.unMaintainList.forEach((item) => {
+        if (item.windturbineId === values.windturbineId) {
+          item.active = !item.active;
+        }
+      });
+    },
+    handleDetial(itm) {
+      this.dialogVisible = true;
+      this.currentWindturbine = itm;
+    },
+    handleClose() {
+      this.dialogVisible = false;
+      this.svgVisible = false;
+    },
+    handleSend() {
+      if (this.chooseList.length > 0) {
+        this.chooseList.forEach((item) => {
+          if (item.operateStyle === "Start") {
+            item.controlType = 1;
+          } else if (item.operateStyle === "Stop") {
+            item.controlType = 2;
+          } else if (item.operateStyle === "Maintain") {
+            item.controlType = 6;
+          } else if (item.operateStyle === "UnMaintain") {
+            item.controlType = 8;
+          }
+        });
+        let mss = {};
+        mss.type = "send";
+        mss.deviceType = "Recommend";
+        this.sendCommand(mss, this.chooseList);
+      }
+    },
+    /* 右键菜单 */
+    contextmenu() {
+      const { remote } = require("electron");
+      let that = this;
+      const menuTemplate = [
+        {
+          label: "发送",
+          click() {
+            that.handleSend();
+          },
+        },
+        {
+          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" });
+              },
+            },
+          ],
+        },
+      ];
+      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 = windturbine;
+      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: this.current === 0 ? true : false,
+            deviceType: msg.deviceType,
+          };
+          pairs[ct.windturbineId] = ct;
+        });
+        api.windturbControl(pairs).then((res) => {
+          if (res) {
+            // this.showFlag = false
+            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);
+          }
+        });
+      }
+    },
+    clearSelected() {
+      this.startList.forEach((item) => {
+        item.active = false;
+      });
+      this.stopList.forEach((item) => {
+        item.active = false;
+      });
+      this.chooseList = [];
+    },
+    removeList(mk) {
+      let indx = -1;
+      for (let id in this.titleList) {
+        if (this.titleList[id].windturbineId == mk.windturbineId) {
+          indx = id;
+          break;
+        }
+      }
+      if (indx < 0) return;
+      this.titleList.splice(indx, 1);
+    },
+    /* 控制成功 */
+    controlSuccess(msg) {
+      let bd = BackgroundData.getInstance();
+      for (let id in msg.data) {
+        let val = msg.data[id];
+        if (val.errorCode !== "0") {
+          bd.removeCheckouts(val);
+          this.removeList(val);
+        }
+      }
+      if (msg.data || msg.data !== {}) {
+        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,
+        });
+      } else {
+        this.$notify({
+          title: "控制出现错误",
+          message: "控制失败,请重试",
+          type: "warning",
+          position: "bottom-right",
+          offset: 60,
+          duration: 3000,
+        });
+      }
+    },
+
+    /* 控制失败 */
+    controlError(err) {
+      this.$notify({
+        title: "控制出现错误",
+        message: err.message,
+        type: "warning",
+        position: "bottom-right",
+        offset: 60,
+        duration: 3000,
+      });
+    },
+    sendMessage(url1) {
+      this.messageUrl = url1;
+      // let link = document.createElement('a')
+      // link.href = url1
+      // link.click()
+    },
+    handleTypeChange(val) {
+      //   val.type = !val.type;
+      let bd = BackgroundData.getInstance();
+      if (!bd.LoginUser) {
+        this.$notify({
+          title: "请登录",
+          message: "控制风机需要先登录!",
+          type: "warning",
+          position: "bottom-right",
+          offset: 60,
+          duration: 3000,
+        });
+        return;
+      }
+      api
+        .uodateControlType({
+          stationid: val.stationId,
+          type: !val.type,
+          userName: bd.LoginUser.name,
+        })
+        .then((res) => {
+          if (res.data === "success") {
+            this.getControlType();
+          }
+        });
+    },
+  },
+  watch: {
+    "$store.getters.windturbinelist": {
+      deep: true,
+      handler: function (json) {
+        this.windturbinelist = json;
+        let arr = Object.keys(json).sort();
+        this.stopList = [];
+        this.startList = [];
+        this.maintainList = [];
+        this.unMaintainList = [];
+        for (let id of arr) {
+          let val = json[id];
+          this.chooseList.forEach((item) => {
+            if (item.windturbineId === val.windturbineId) {
+              val.active = true;
+            }
+          });
+          this.titleList.forEach((item) => {
+            if (item.windturbineId === val.windturbineId) {
+              val.operateStyle = item.operateStyle;
+              if (item.operateStyle === "Start" && val.status === 2) {
+                this.startList.push(val);
+              } else if (item.operateStyle === "Stop" && val.status === 4) {
+                if (item.reasonType === "ElectricityRestrictions") {
+                  val.reasonType = item.reasonType;
+                }
+                this.stopList.push(val);
+              } else if (item.operateStyle === "Maintain" && val.status === 2) {
+                this.maintainList.push(val);
+              } else if (
+                item.operateStyle === "UnMaintain" &&
+                val.status === 6
+              ) {
+                this.unMaintainList.push(val);
+              }
+            }
+          });
+        }
+        let checkoutList = BackgroundData.getInstance().checkouts;
+        checkoutList.forEach((item) => {
+          let starIndex = null;
+          let stopIndex = null;
+          let maintainIndex = null;
+          let unMaintainIndex = null;
+          let starFlag = false;
+          let stopFlag = false;
+          let maintainFlag = false;
+          let unMaintainFlag = false;
+          this.startList.forEach((param, index) => {
+            if (item.windturbineId === param.windturbineId) {
+              starIndex = index;
+              starFlag = true;
+            }
+          });
+          this.stopList.forEach((param, index) => {
+            if (item.windturbineId === param.windturbineId) {
+              stopIndex = index;
+              stopFlag = true;
+            }
+          });
+          this.maintainList.forEach((param, index) => {
+            if (item.windturbineId === param.windturbineId) {
+              maintainIndex = index;
+              maintainFlag = true;
+            }
+          });
+          this.unMaintainList.forEach((param, index) => {
+            if (item.windturbineId === param.windturbineId) {
+              unMaintainIndex = index;
+              unMaintainFlag = true;
+            }
+          });
+          starFlag ? this.startList.splice(starIndex, 1) : "";
+          stopFlag ? this.stopList.splice(stopIndex, 1) : "";
+          maintainFlag ? this.maintainList.splice(maintainIndex, 1) : "";
+          unMaintainFlag ? this.unMaintainList.splice(unMaintainIndex, 1) : "";
+        });
+      },
+    },
+    "$store.getters.current": {
+      handler: function (json) {
+        this.current = json;
+        this.getControlType();
+        if (json === 0) {
+          let dateList = [];
+          this.titleList.forEach((item) => {
+            let status = this.controlTypeList.filter(
+              (val) =>
+                val.stationId ===
+                this.windturbinelist[item.windturbineId].stationId
+            )[0].type;
+            if (status) {
+              let arr = Object.keys(this.windturbinelist).sort();
+              this.windturbinelist =
+                arr.length !== 0
+                  ? this.windturbinelist
+                  : this.$store.state.windturbinelist;
+              switch (item.operateStyle) {
+                case "Start":
+                  this.windturbinelist[item.windturbineId].controlType = 1;
+                  break;
+                case "Stop":
+                  this.windturbinelist[item.windturbineId].controlType = 2;
+                  break;
+                case "Maintain":
+                  this.windturbinelist[item.windturbineId].controlType = 6;
+                  break;
+                case "UnMaintain":
+                  this.windturbinelist[item.windturbineId].controlType = 8;
+                  break;
+              }
+              dateList.push(this.windturbinelist[item.windturbineId]);
+            }
+          });
+          let mss = {};
+          mss.type = "send";
+          mss.deviceType = "Auto";
+          this.timer = setTimeout(() => {
+            if (dateList.length > 0) {
+              this.sendCommand(mss, dateList);
+            }
+            this.showFlag = false;
+            clearInterval(this.timer);
+          }, 3000);
+        }
+      },
+    },
+  },
+};
+</script>
+
+<style scoped="scoped">
+.body {
+  border: 1px solid #373737;
+  width: 100%;
+  margin-left: 15px;
+  margin-top: 20px;
+}
+
+.body .scoll {
+  height: 91%;
+  overflow-y: scroll;
+}
+
+.title {
+  color: #ffffff;
+  font-size: 14px;
+  margin-left: 32px;
+  /* margin-top: 12px; */
+  margin-bottom: 10px;
+  /* width: 570px; */
+  width: 29vw;
+  height: 50px;
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  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: #54b75a;
+  border-radius: 50%;
+}
+
+.logo {
+  position: absolute;
+  top: 12px;
+  left: 12px;
+}
+
+.matrix {
+  margin-left: 20px;
+  /* margin-right: 10px; */
+  padding-bottom: 20px;
+  border-bottom: 1px solid rgba(31, 31, 31, 1);
+}
+
+.problemTitle {
+  font-size: 12px;
+  color: #bfbfbf;
+  margin-top: 20px;
+  margin-bottom: 20px;
+  margin-left: 12px;
+}
+
+.send {
+  width: 86px;
+  height: 26px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: rgba(84, 183, 90, 1);
+  color: #ffffff;
+  font-size: 14px;
+  position: absolute;
+  bottom: 20px;
+  right: 10px;
+}
+
+.success {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 250px;
+  height: 48px;
+  position: absolute;
+  bottom: 20px;
+  right: 20%;
+  border: 1px solid rgba(55, 55, 55, 1);
+  border-radius: 10px;
+  color: #ffffff;
+  font-size: 14px;
+}
+
+.controlTypes {
+  width: 80px;
+  height: 30px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: 1px solid rgba(51, 51, 51, 1);
+}
+.controlTypesLeft {
+  width: 80px;
+  height: 30px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: 1px solid rgba(51, 51, 51, 1);
+  border-top-left-radius: 15px;
+  border-bottom-left-radius: 15px;
+}
+.controlTypesRight {
+  width: 80px;
+  height: 30px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: 1px solid rgba(51, 51, 51, 1);
+  border-top-right-radius: 15px;
+  border-bottom-right-radius: 15px;
+}
+.onControlTypes {
+  width: 80px;
+  height: 30px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: 1px solid rgba(51, 51, 51, 1);
+  background-color: rgba(37, 116, 219, 1);
+}
+.onControlTypesLeft {
+  width: 80px;
+  height: 30px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  /* border: 1px solid rgba(37, 116, 219, 1); */
+  border-top-left-radius: 15px;
+  border-bottom-left-radius: 15px;
+  background-color: rgba(37, 116, 219, 1);
+}
+.onControlTypesRight {
+  width: 80px;
+  height: 30px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  /* border: 1px solid rgba(37, 116, 219, 1); */
+  border-top-right-radius: 15px;
+  border-bottom-right-radius: 15px;
+  background-color: rgba(37, 116, 219, 1);
+}
+</style>

+ 877 - 0
src/components/control/controlAllArea.vue

@@ -0,0 +1,877 @@
+<template>
+  <div class="problem" @contextmenu="contextmenu">
+    <div class="body">
+      <img class="logo" src="../../assets/img/logo.png" alt="" />
+      <div class="titleBar">
+        <div class="title">设备区</div>
+        <el-select
+          @change="listedChange()"
+          class="inputs"
+          v-model="selectValue"
+          placeholder="请选择"
+        >
+          <el-option
+            v-for="item in options"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          >
+          </el-option>
+        </el-select>
+      </div>
+      <div style="margin-top: 20px; margin-left: 35px; height: 85%">
+        <div class="scoll">
+          <div
+            class="matrix currentScroll"
+            style="height: 100%;overflow-y:scroll"
+            v-if="showList.length > 0"
+          >
+            <!-- <div class="problemTitle">待启动</div> -->
+            <MatrixBlock
+              @choose-click="handleClick"
+              @on-click="handleDetails"
+              :dataList="showList"
+            >
+            </MatrixBlock>
+          </div>
+        </div>
+      </div>
+    </div>
+    <WindturbineDetailPages
+      v-model="dialogVisible"
+      @close="handleClose"
+      :svgWeb="svgWeb"
+      :windturbine="currentWindturbine"
+    ></WindturbineDetailPages>
+    <StationSvgDetailPages
+    v-model="showSvg"
+    :stationName="stationName"
+    :svgWeb="svgWeb"
+    @close="close"
+  ></StationSvgDetailPages>
+  </div>
+</template>
+
+<script>
+import WindturbineDetailPages from "../WindturbineDetailPages.vue";
+import MatrixBlock from "../matrixBlock.vue";
+import StationSvgDetailPages from "../stationSvgDetailPages.vue";
+import BackgroundData from "utils/BackgroundData";
+import MessageBridge from "utils/MessageBridge";
+import api from "api/index";
+export default {
+  name: "ProblemArea",
+  components: {
+    WindturbineDetailPages,
+    MatrixBlock,
+    StationSvgDetailPages,
+  },
+  props: {
+    current: {
+      type: Number,
+    },
+    datas: {
+      type: String,
+    },
+  },
+  data() {
+    return {
+      dataList: [],
+      showList: [],
+      chooseList: [],
+      lockValues: [],
+      currentWindturbine: {},
+      dialogVisible: false,
+      showSvg: false,
+      svgWeb: "",
+      windturbinelist: {},
+      options: [
+        {
+          value: "0",
+          label: "问题设备",
+        },
+        {
+          value: "1",
+          label: "故障",
+        },
+        {
+          value: "2",
+          label: "维护",
+        },
+        {
+          value: "3",
+          label: "离线",
+        },
+        {
+          value: "4",
+          label: "挂牌",
+        },
+        {
+          value: "5",
+          label: "麻黄山",
+        },
+        {
+          value: "6",
+          label: "牛首山",
+        },
+        {
+          value: "7",
+          label: "青山",
+        },
+        {
+          value: "8",
+          label: "石板泉",
+        },
+        {
+          value: "9",
+          label: "香山",
+        },
+      ],
+      selectValue: "0",
+      controlErorCodes: [
+        "控制成功",
+        "控制命令发送失败",
+        "无效的控制地址",
+        "被控设备异常",
+        "无效的控制功能",
+        "网络连接错误,检查场站通信",
+        "控制结果读取超时",
+        "未知错误",
+        "控制命令错误",
+        "收到无法识别数据",
+        "未读取到数据包",
+        "未知错误",
+        "风机操作过频繁",
+        "风机被挂牌",
+        "风机操作与风机状态不符",
+        "需要登录",
+      ],
+    };
+  },
+  computed: {},
+  created: function () {
+    this.initData();
+    this.controls();
+    this.getLocks();
+  },
+  methods: {
+    controls() {
+      let json = this.$store.state.windturbinelist;
+      this.dataList = [];
+      this.showList = [];
+      let arr = Object.keys(json).sort();
+      for (let id of arr) {
+        let val = json[id];
+        this.chooseList.forEach((item) => {
+          if (item.windturbineId === val.windturbineId) {
+            val.active = true;
+          }
+        });
+        this.dataList.push(val);
+        switch (Number(this.selectValue)) {
+          case 0:
+            if (
+              val.status === 5 ||
+              val.status === 6 ||
+              val.status === 7 ||
+              val.lockValue > 0
+            ) {
+              this.showList.push(val);
+            }
+            break;
+          case 1:
+            val.status === 5 ? this.showList.push(val) : "";
+            break;
+          case 2:
+            val.status === 6 ? this.showList.push(val) : "";
+            break;
+          case 3:
+            val.status === 7 ? this.showList.push(val) : "";
+            break;
+          case 4:
+            val.lockValue > 0 ? this.showList.push(val) : "";
+            break;
+          case 5:
+            val.windturbineId.substring(0, 2) === "MG"
+              ? this.showList.push(val)
+              : "";
+            break;
+          case 6:
+            val.windturbineId.substring(0, 2) === "NG"
+              ? this.showList.push(val)
+              : "";
+            break;
+          case 7:
+            val.windturbineId.substring(0, 2) === "QG"
+              ? this.showList.push(val)
+              : "";
+            break;
+          case 8:
+            val.windturbineId.substring(0, 2) === "SG"
+              ? this.showList.push(val)
+              : "";
+            break;
+          case 9:
+            val.windturbineId.substring(0, 2) === "XG"
+              ? this.showList.push(val)
+              : "";
+            break;
+        }
+      }
+      let checkoutList = BackgroundData.getInstance().checkouts;
+      checkoutList.forEach((item) => {
+        let showIndex = null;
+        this.showList.forEach((param, index) => {
+          if (item.windturbineId === param.windturbineId) {
+            showIndex = index;
+          }
+        });
+        this.showList.splice(showIndex, 1);
+      });
+    },
+    getLocks() {
+      api.getCustomerLock().then((res) => {
+        if (res) {
+          this.lockValues = res.data;
+        }
+      });
+    },
+    initData: function () {
+      let mb = MessageBridge.getInstance();
+      let vss = [
+        { key: "/topic/voice-control", action: this.windturbineMessage },
+      ];
+      mb.register(vss);
+    },
+    windturbineMessage(msg) {
+      if (this.$store.state.current === 2) {
+        let arr = [];
+        if (msg === "CLOSE") {
+          arr.push(msg);
+        } else {
+          arr = msg.split("-");
+        }
+        this.dialogVisible = false;
+        this.showSvg = false;
+        this.svgWeb = "";
+        if (arr[0] === "OPEN_FJ") {
+          this.currentWindturbine = this.windturbinelist[arr[1]];
+          this.dialogVisible = true;
+        } else if (arr[0] === "CLOSE") {
+          this.dialogVisible = false;
+        } else if (arr[0] === "OPEN_SYZ") {
+          this.currentWindturbine = this.windturbinelist[arr[1]];
+          this.showSvg = true;
+          this.svgVisible = true;
+          this.svgWeb = arr[1];
+        } else if (
+          arr[0] === "CONTROL_START" ||
+          arr[0] === "CONTROL_STOP" ||
+          arr[0] === "CONTROL_MAINTAIN"
+        ) {
+          let windControlList = [];
+          let mss = {};
+          arr.forEach((item) => {
+            if (
+              item ===
+              (this.windturbinelist[item]
+                ? this.windturbinelist[item].windturbineId
+                : "")
+            ) {
+              switch (arr[0]) {
+                case "CONTROL_START":
+                  this.windturbinelist[item].controlType = "1";
+                  break;
+                case "CONTROL_STOP":
+                  this.windturbinelist[item].controlType = "2";
+                  break;
+                case "CONTROL_MAINTAIN":
+                  this.windturbinelist[item].controlType = "6";
+                  break;
+                case "CONTROL_UNMAINTAIN":
+                  this.windturbinelist[item].controlType = "8";
+                  break;
+              }
+              windControlList.push(this.windturbinelist[item]);
+            }
+          });
+          mss.type = "send";
+          this.sendCommand(mss, windControlList);
+        } else if (
+          arr[0] === "CONTROL_LOCK_OVERHAUL" ||
+          arr[0] === "CONTROL_LOCK_MAINTAIN" ||
+          arr[0] === "CONTROL_LOCK_LNVOLVED_OVERHAUL" ||
+          arr[0] === "CONTROL_LOCK_LNVOLVED_MAINTAIN" ||
+          arr[0] === "CONTROL_LOCK_LNVOLVED_PG" ||
+          arr[0] === "CONTROL_LOCK_LNVOLVED_WEATHER" ||
+          arr[0] === "CONTROL_UNLOCK"
+        ) {
+          let windturbine = this.windturbinelist[arr[1]];
+          switch (arr[0]) {
+            case "CONTROL_LOCK_OVERHAUL":
+              this.sendLock({ value: "CheckLock" }, windturbine);
+              break;
+            case "CONTROL_LOCK_MAINTAIN":
+              this.sendLock({ value: "FaultLock" }, windturbine);
+              break;
+            case "CONTROL_LOCK_LNVOLVED_OVERHAUL":
+              this.sendLock({ value: "StationCheckLock" }, windturbine);
+              break;
+            case "CONTROL_LOCK_LNVOLVED_MAINTAIN":
+              this.sendLock({ value: "StationFaulLock" }, windturbine);
+              break;
+            case "CONTROL_LOCK_LNVOLVED_PG":
+              this.sendLock({ value: "StationPowerLineLock" }, windturbine);
+              break;
+            case "CONTROL_LOCK_LNVOLVED_WEATHER":
+              this.sendLock({ value: "StationWeatherLock" }, windturbine);
+              break;
+            case "CONTROL_UNLOCK":
+              this.sendLock({ value: "UnLock" }, windturbine);
+              break;
+          }
+        }
+      }
+    },
+    /* 右键菜单 */
+    contextmenu() {
+      const remote = require("electron").remote;
+      let that = this;
+      let menuTemplate = [];
+      if (
+        this.selectValue === "0" ||
+        this.selectValue === "1" ||
+        this.selectValue === "2" ||
+        this.selectValue === "3" ||
+        this.selectValue === "4"
+      ) {
+        menuTemplate = [
+          // {
+          //     label: "标注",
+          //     click() {
+          //         that.sendLock({ type: "marking" });
+          //     },
+          // },
+          {
+            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" });
+            },
+          },
+        ];
+      } else {
+        menuTemplate = [
+          {
+            label: "启动",
+            click() {
+              that.sendCommand({ controlType: "1" });
+            },
+          },
+          {
+            label: "停机",
+            click() {
+              that.sendCommand({ controlType: "2" });
+            },
+          },
+          {
+            label: "复位",
+            click() {
+              that.sendCommand({ controlType: "5" });
+            },
+          },
+          {
+            label: "维护",
+            click() {
+              that.sendCommand({ controlType: "6" });
+            },
+          },
+          {
+            label: "取消维护",
+            click() {
+              that.sendCommand({ controlType: "8" });
+            },
+          },
+          {
+            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.sendLock({ type: "marking" });
+          //     },
+          // },
+        ];
+      }
+
+      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,
+          };
+          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);
+          }
+        });
+      }
+    },
+
+    /* 清除所有选择 */
+    clearSelected() {
+      this.chooseList = [];
+    },
+    /* 控制成功 */
+    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,
+      });
+    },
+    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.showList.forEach((item) => {
+        if (item.windturbineId === values.windturbineId) {
+          item.active = !item.active;
+        }
+      });
+    },
+    listedChange() {
+      this.chooseList = [];
+      this.showList = [];
+      this.dataList.forEach((val) => {
+        val.active = false;
+        switch (Number(this.selectValue)) {
+          case 0:
+            if (
+              val.status === 5 ||
+              val.status === 6 ||
+              val.status === 7 ||
+              val.lockValue > 0
+            ) {
+              this.showList.push(val);
+            }
+            break;
+          case 1:
+            val.status === 5 ? this.showList.push(val) : "";
+            break;
+          case 2:
+            val.status === 6 ? this.showList.push(val) : "";
+            break;
+          case 3:
+            val.status === 7 ? this.showList.push(val) : "";
+            break;
+          case 4:
+            val.lockValue > 0 ? this.showList.push(val) : "";
+            break;
+          case 5:
+            val.windturbineId.substring(0, 2) === "MG"
+              ? this.showList.push(val)
+              : "";
+            break;
+          case 6:
+            val.windturbineId.substring(0, 2) === "NG"
+              ? this.showList.push(val)
+              : "";
+            break;
+          case 7:
+            val.windturbineId.substring(0, 2) === "QG"
+              ? this.showList.push(val)
+              : "";
+            break;
+          case 8:
+            val.windturbineId.substring(0, 2) === "SG"
+              ? this.showList.push(val)
+              : "";
+            break;
+          case 9:
+            val.windturbineId.substring(0, 2) === "XG"
+              ? this.showList.push(val)
+              : "";
+            break;
+        }
+      });
+    },
+    handleDetails(itm) {
+      this.dialogVisible = true;
+      this.currentWindturbine = itm;
+    },
+    handleClose() {
+      this.dialogVisible = false;
+      this.showSvg = false;
+      this.getLocks();
+    },
+  },
+  watch: {
+    "$store.getters.windturbinelist": {
+      deep: true,
+      handler: function (json) {
+        this.windturbinelist = json;
+        this.dataList = [];
+        this.showList = [];
+        let arr = Object.keys(json).sort();
+        for (let id of arr) {
+          let val = json[id];
+          this.chooseList.forEach((item) => {
+            if (item.windturbineId === val.windturbineId) {
+              val.active = true;
+            }
+          });
+          if (val.lockValue === 9) {
+            val.lockValues = this.lockValues.filter(
+              (item) => val.windturbineId === item.windturbineID
+            )[0]?.value;
+          }
+          this.dataList.push(val);
+          switch (Number(this.selectValue)) {
+            case 0:
+              if (
+                val.status === 5 ||
+                val.status === 6 ||
+                val.status === 7 ||
+                val.lockValue > 0
+              ) {
+                this.showList.push(val);
+              }
+              break;
+            case 1:
+              val.status === 5 ? this.showList.push(val) : "";
+              break;
+            case 2:
+              val.status === 6 ? this.showList.push(val) : "";
+              break;
+            case 3:
+              val.status === 7 ? this.showList.push(val) : "";
+              break;
+            case 4:
+              val.lockValue > 0 ? this.showList.push(val) : "";
+              break;
+            case 5:
+              val.windturbineId.substring(0, 2) === "MG"
+                ? this.showList.push(val)
+                : "";
+              break;
+            case 6:
+              val.windturbineId.substring(0, 2) === "NG"
+                ? this.showList.push(val)
+                : "";
+              break;
+            case 7:
+              val.windturbineId.substring(0, 2) === "QG"
+                ? this.showList.push(val)
+                : "";
+              break;
+            case 8:
+              val.windturbineId.substring(0, 2) === "SG"
+                ? this.showList.push(val)
+                : "";
+              break;
+            case 9:
+              val.windturbineId.substring(0, 2) === "XG"
+                ? this.showList.push(val)
+                : "";
+              break;
+          }
+        }
+        let checkoutList = BackgroundData.getInstance().checkouts;
+        checkoutList.forEach((item) => {
+          let showIndex = null;
+          this.showList.forEach((param, index) => {
+            if (item.windturbineId === param.windturbineId) {
+              showIndex = index;
+            }
+          });
+          this.showList.splice(showIndex, 1);
+        });
+      },
+    },
+  },
+};
+</script>
+<style scoped>
+.problem {
+  height: 100%;
+}
+
+.body {
+  border: 1px solid #373737;
+  width: 100%;
+  margin-left: 15px;
+  margin-top: 10px;
+  height: 61vh;
+}
+
+.body .scoll {
+  height: 91%;
+}
+
+.titleBar {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+}
+
+.title {
+  color: #ffffff;
+  font-size: 14px;
+  margin-left: 32px;
+  /* margin-top: 12px; */
+  margin-bottom: 10px;
+  /* width: 570px; */
+  width: 29vw;
+  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: #54b75a;
+  border-radius: 50%;
+}
+
+.inputs {
+  border: none;
+  width: 174px !important;
+  margin-left: 110px;
+}
+
+.el-input__inner {
+  background-color: rgb(100, 100, 100) !important;
+  color: rgb(220, 220, 220) !important;
+  border: 1px solid red !important;
+}
+
+.logo {
+  position: absolute;
+  top: 2px;
+  left: 12px;
+}
+</style>

+ 48 - 0
src/components/control/controlArea.vue

@@ -0,0 +1,48 @@
+<template>
+  <div class="problem">
+    <AreaCard
+      title="控制区"
+      height="60"
+      :current="current"
+      ref="areaCard"
+    ></AreaCard>
+  </div>
+</template>
+
+<script>
+import AreaCard from "./areaCard.vue";
+import BackgroundData from "utils/BackgroundData";
+export default {
+  name: "ProblemArea",
+  components: {
+    AreaCard,
+  },
+  props: {
+    current: {
+      type: Number,
+    },
+  },
+  data() {
+    return {
+      ls: {
+        maintain: { key: "维护", value: [] },
+        malfunction: { key: "故障", value: [] },
+        offline: { key: "离线", value: [] },
+        lockd: { key: "挂牌", value: [] },
+      },
+    };
+  },
+  computed: {},
+  created() {},
+  methods: {
+    control(current) {
+      this.$refs.areaCard.control(current);
+    },
+  },
+};
+</script>
+<style scoped>
+.problem {
+  height: 100%;
+}
+</style>

文件差异内容过多而无法显示
+ 145 - 0
src/components/dataDetails.vue


+ 264 - 0
src/components/focus/PhotoelectricDetailPages.vue

@@ -0,0 +1,264 @@
+<template>
+	<el-dialog width="55%" @closed="closed()" :show-close="false" class="my-info-dialog">
+		<template #title>
+			<div class="showTitle">
+				<img class="titleImg" src="../../assets/img/controlcenter/daraTrue.png" alt="">
+				<div class="titles">{{stationName}}</div>
+				<!-- <div class="icon">(麻黄山)</div> -->
+			</div>
+		</template>
+		<div class="body">
+			<div class="dataList">
+				<div class="data">
+					<div class="name">{{data.PowerSet.name}}:</div>
+					<div class="num">{{data.PowerSet?.value}}</div>
+					<div class="unit">MW</div>
+				</div>
+				<div class="data">
+					<div class="name">{{data.TheoryPower.name}}:</div>
+					<div class="num">{{data.TheoryPower?.value}}</div>
+					<div class="unit">MW</div>
+				</div>
+				<div class="data">
+					<div class="name">{{data.AgcLower.name}}:</div>
+					<div class="num">{{data.AgcLower?.value}}</div>
+					<div class="unit">MW</div>
+				</div>
+				<div class="data">
+					<div class="name">{{data.ActualPower.name}}:</div>
+					<div class="num">{{data.ActualPower?.value}}</div>
+					<div class="unit">MW</div>
+				</div>
+				<div class="data">
+					<div class="name">{{data.AgcUp.name}}:</div>
+					<div class="num">{{data.AgcUp?.value}}</div>
+					<div class="unit">MW</div>
+				</div>
+				<div class="data">
+					<div class="name">{{data.ForecastPower.name}}:</div>
+					<div class="num">{{data.ForecastPower?.value}}</div>
+					<div class="unit">MW</div>
+				</div>
+			</div>
+			<div class="condition">
+				<div class="status">
+					<div class="name">{{data.AgcIn.name}}:</div>
+					<img v-if="data.AgcIn.value === 0" class="statusIcon"
+						src="../../assets/img/controlcenter/daraTrue.png">
+					<img v-else-if="data.AgcIn.value === 1" class="statusIcon"
+						src="../../assets/img/controlcenter/dataFalse.png">
+					<div v-else-if="data.AgcIn.value === ''">
+						暂无数据
+					</div>
+				</div>
+				<div class="status">
+					<div class="name">{{data.AgcFar.name}}:</div>
+					<img v-if="data.AgcFar.value === 0" class="statusIcon"
+						src="../../assets/img/controlcenter/daraTrue.png">
+					<img v-else-if="data.AgcFar.value === 1" class="statusIcon"
+						src="../../assets/img/controlcenter/dataFalse.png">
+					<div v-else-if="data.AgcFar.value === ''">
+						暂无数据
+					</div>
+				</div>
+				<div class="status">
+					<div class="name">{{data.SumLock.name}}:</div>
+					<img v-if="data.SumLock.value === 0" class="statusIcon"
+						src="../../assets/img/controlcenter/daraTrue.png">
+					<img v-else-if="data.SumLock.value === 1" class="statusIcon"
+						src="../../assets/img/controlcenter/dataFalse.png">
+					<div v-else-if="data.SumLock.value === ''">
+						暂无数据
+					</div>
+				</div>
+				<div class="status">
+					<div class="name">{{data.SubLock.name}}:</div>
+					<img v-if="data.SubLock.value === 0" class="statusIcon"
+						src="../../assets/img/controlcenter/daraTrue.png">
+					<img v-else-if="data.SubLock.value === 1" class="statusIcon"
+						src="../../assets/img/controlcenter/dataFalse.png">
+					<div v-else-if="data.SubLock.value === ''">
+						暂无数据
+					</div>
+				</div>
+			</div>
+			<!-- <button @click='ChangeColors()'>测试按钮</button> -->
+			<!-- <div id="main" class="echartsBox"></div> -->
+			<MultipleLineChart ref="multipleLineChart" height="400px" :units="powerLineChartData.units" :list="powerLineChartData.value"
+				 :showLegend="true" />
+		</div>
+	</el-dialog>
+</template>
+
+<script>
+	// import UniformCodes from "../../assets/script/UniformCodes";
+	// import { config } from '../../config';
+	// import axios from 'axios';
+	// import BackgroundData from "../../assets/script/BackgroundData"
+	import MultipleLineChart from "./multiple-line-chart.vue";
+	import dayjs from 'dayjs'
+	export default {
+		components: {
+			MultipleLineChart
+		},
+		props: {
+			stationName: {
+				type: String,
+				default: ''
+			},
+			data: {
+				type: Array
+			},
+		},
+		data() {
+			return {
+				chartData: {
+					units: [""],
+					value: [],
+				},
+				colors: ["rgba(75, 85, 174, 1)", "rgba(05, 187, 76, 1)"],
+				timeData: [],
+				PowerSet: [],
+				ActualPower: [],
+				index: 0,
+				powerLineChartData: {},
+			};
+		},
+		methods: {
+			closed() {
+				//勿删,传递关闭方法
+			},
+			ChangeColors() {
+				this.colors = ["#aa2116", "#fcaf17"]
+			},
+			initData(PowerSet, ActualPower) {
+				// this.chartData.units = ["(MW)", "(MW)"];
+				this.chartData.value[0] = {
+					title: "有功设定限值(MW)",
+					yAxisIndex: 0,
+					value: []
+				};
+				this.chartData.value[1] = {
+					title: "实发有功(MW)",
+					yAxisIndex: 0,
+					value: []
+				}
+				PowerSet.forEach(item => {
+					this.chartData.value[0].value.push({
+						text: dayjs(item.ts).format('hh:mm'),
+						value: parseFloat((item.doubleValue).toFixed(2))
+					})
+				})
+				ActualPower.forEach(item => {
+					this.chartData.value[1].value.push({
+						text: dayjs(item.ts).format('hh:mm'),
+						value: parseFloat((item.doubleValue).toFixed(2))
+					})
+				})
+				this.powerLineChartData = this.chartData;
+				this.$refs.multipleLineChart.initChart(this.chartData)
+			}
+		},
+	};
+</script>
+<style scoped>
+	.echartsBox {
+		width: 64rem;
+		height: 220px;
+		overflow: hidden;
+	}
+
+	.el-dialog__header {
+		background-color: #000000;
+	}
+
+	.showTitle {
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		justify-content: center;
+		margin-top: -10px;
+		font-size: 18px;
+		color: #FFFFFF;
+	}
+
+	.titleImg {
+		width: 16px;
+		height: 16px;
+		margin-right: 13px;
+	}
+
+	.icon {
+		font-size: 12px;
+		margin-left: 10px;
+		margin-top: 5px;
+	}
+
+	.body {
+		background-color: black;
+		width: 100%;
+		margin-top: -30px;
+		/* height: 200px; */
+	}
+
+	.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: 22px;
+	}
+
+	.name {
+		width: 40%;
+		display: flex;
+		flex-direction: row-reverse;
+		font-size: 12px;
+		color: #FFFFFF;
+	}
+
+	.num {
+		margin-left: 59px;
+		font-size: 16px;
+		color: #05BB4C;
+		min-width: 40px;
+	}
+
+	.unit {
+		font-size: 16px;
+		color: #FFFFFF;
+		margin-left: 20px;
+	}
+
+	.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;
+	}
+
+	.statusIcon {
+		width: 14px;
+		height: 14px;
+		margin-left: 8px;
+	}
+</style>

+ 0 - 0
src/components/focus/agcDetails.vue


部分文件因为文件数量过多而无法显示