yangxiao vor 4 Jahren
Ursprung
Commit
b800caf933

+ 4 - 0
package.json

@@ -9,12 +9,16 @@
     "lint": "vue-cli-service lint"
   },
   "dependencies": {
+    "axios": "^0.21.1",
     "core-js": "^3.6.5",
     "echarts": "^5.1.1",
     "echarts-gl": "^2.0.4",
+    "element-plus": "^1.0.2-beta.46",
     "font-awesome": "^4.7.0",
+    "stompjs": "^2.3.3",
     "vivus": "^0.4.6",
     "vue": "^3.0.0",
+    "vue-axios": "^3.2.4",
     "vue-router": "^4.0.0-0",
     "vuex": "^4.0.0-0"
   },

+ 22 - 0
public/static/config/modeConfig.js

@@ -0,0 +1,22 @@
+
+// 本地联调开关
+const localTest = 0;
+
+// 服务器地址
+let baseURL = null;
+
+// websocket 服务器地址
+let websocketUrl = null;
+
+if (localTest) {
+  baseURL = "http://192.168.10.23:8082/" // 联机调试 - 石林
+  websocketUrl = (baseURL.replace(/http:\/\//g, "")) + "gyee-websocket";
+} else {
+  baseURL = "http://10.155.32.4:8082/" // 正式环境
+  websocketUrl = (baseURL.replace(/http:\/\//g, "")) + "gyee-websocket";
+}
+
+window.__MODE__ = {
+  baseURL,
+  websocketUrl
+};

+ 82 - 106
src/App.vue

@@ -1,119 +1,66 @@
 <template>
   <div class="main">
     <div class="header-body">
-      <div class="header-title">
-        <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="16.667vh" height="3.704vh" viewBox="0 0 377.437 91.615" enable-background="new 0 0 377.437 91.615" xml:space="preserve">
+      <div class="header-title" @click="disconnect">
+        <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+          width="16.667vh" height="3.704vh" viewBox="0 0 377.437 91.615" enable-background="new 0 0 377.437 91.615"
+          xml:space="preserve">
           <g id="图层_1">
             <g>
-              <path
-                id="XMLID_489_"
-                fill="#FFF"
-                d="M148.946,81.252c-6.114,0-10.656-4.561-10.656-10.33v-0.061c0-5.708,4.448-10.389,10.833-10.389c3.919,0,6.269,1.265,8.197,3.103l-2.912,3.241c-1.602-1.407-3.233-2.266-5.315-2.266c-3.503,0-6.025,2.811-6.025,6.256v0.055c0,3.444,2.463,6.313,6.025,6.313c2.378,0,3.833-0.915,5.468-2.35l2.909,2.84C155.329,79.877,152.955,81.252,148.946,81.252z"
-              />
+              <path id="XMLID_489_" fill="#FFF" d="M148.946,81.252c-6.114,0-10.656-4.561-10.656-10.33v-0.061c0-5.708,4.448-10.389,10.833-10.389c3.919,0,6.269,1.265,8.197,3.103l-2.912,3.241c-1.602-1.407-3.233-2.266-5.315-2.266c-3.503,0-6.025,2.811-6.025,6.256v0.055c0,3.444,2.463,6.313,6.025,6.313c2.378,0,3.833-0.915,5.468-2.35l2.909,2.84C155.329,79.877,152.955,81.252,148.946,81.252z" />
               <polygon id="XMLID_488_" fill="#FFF" points="173.271,60.817 173.271,68.472 164.839,68.472 164.839,60.817 160.263,60.817 160.263,80.907 164.839,80.907 164.839,72.547 173.271,72.547 173.271,80.907 177.843,80.907 177.843,60.817" />
               <path id="XMLID_486_" fill="#FFF" d="M195.929,80.907l-10.063-12.77v12.77h-4.516v-20.09h4.214l9.743,12.373V60.817h4.514v20.09H195.929z" />
-              <path
-                id="XMLID_484_"
-                fill="#FFF"
-                d="M304.535,81.252c-6.47,0-10.928-4.39-10.928-10.33v-0.061c0-5.708,4.606-10.389,10.901-10.389c3.741,0,5.992,0.845,8.429,2.482l-2.564,3.243c-1.789-1.208-3.028-1.694-6.012-1.646c-3.325,0.055-5.967,2.839-5.967,6.256v0.055c0,3.676,2.607,6.374,6.291,6.374c1.664,0,3.146-0.401,4.307-1.206v-2.871h-2.908v-3.817h7.332v8.725C311.277,79.817,308.336,81.252,304.535,81.252z"
-              />
+              <path id="XMLID_484_" fill="#FFF" d="M304.535,81.252c-6.47,0-10.928-4.39-10.928-10.33v-0.061c0-5.708,4.606-10.389,10.901-10.389c3.741,0,5.992,0.845,8.429,2.482l-2.564,3.243c-1.789-1.208-3.028-1.694-6.012-1.646c-3.325,0.055-5.967,2.839-5.967,6.256v0.055c0,3.676,2.607,6.374,6.291,6.374c1.664,0,3.146-0.401,4.307-1.206v-2.871h-2.908v-3.817h7.332v8.725C311.277,79.817,308.336,81.252,304.535,81.252z" />
               <path id="XMLID_482_" fill="#FFF" d="M245.533,80.907l-10.063-12.77v12.77h-4.515v-20.09h4.213l9.744,12.373V60.817h4.513v20.09H245.533z" />
               <path id="XMLID_480_" fill="#FFF" d="M321.476,80.907v-8.793l-6.949-11.297h5.346l4.361,7.936l4.397-7.936h5.196l-6.951,11.238v8.853H321.476z" />
               <polygon fill="#FFF" points="228.012,64.895 228.012,60.817 211.357,60.817 211.357,80.907 228.012,80.907 228.012,76.83 215.967,76.83 215.967,72.831 226.732,72.831 226.732,68.753 215.967,68.753 215.967,64.895 " />
               <polygon fill="#FFF" points="269.557,64.895 269.557,60.817 252.902,60.817 252.902,80.907 269.557,80.907 269.557,76.83 257.511,76.83 257.511,72.831 268.277,72.831 268.277,68.753 257.511,68.753 257.511,64.895 " />
-              <path
-                fill="#FFF"
-                d="M291.333,80.907l-3.983-7.74c2.177-1.005,3.696-3.265,3.696-5.896v0c0-3.564-2.784-6.454-6.22-6.454H272.98v20.09h4.57v-7.182h5.515l3.695,7.182H291.333z M277.55,64.895h6.774c1.265,0,2.29,1.064,2.29,2.376v0c0,1.312-1.025,2.376-2.29,2.376h-6.774V64.895z"
-              />
+              <path fill="#FFF" d="M291.333,80.907l-3.983-7.74c2.177-1.005,3.696-3.265,3.696-5.896v0c0-3.564-2.784-6.454-6.22-6.454H272.98v20.09h4.57v-7.182h5.515l3.695,7.182H291.333z M277.55,64.895h6.774c1.265,0,2.29,1.064,2.29,2.376v0c0,1.312-1.025,2.376-2.29,2.376h-6.774V64.895z" />
             </g>
             <g>
               <g>
-                <path
-                  id="XMLID_479_"
-                  fill="#FFF"
-                  d="M167.55,39.067h-1.561c-0.546-2.03-1.035-3.547-1.82-5.373l-4.36-0.004
+                <path id="XMLID_479_" fill="#FFF" d="M167.55,39.067h-1.561c-0.546-2.03-1.035-3.547-1.82-5.373l-4.36-0.004
 c0.771,2.025,1.339,3.833,1.692,5.377h-3.128v-6.282h8.215v-3.861h-8.215v-4.49h8.393v-3.899h-21.599v3.899h8.101v4.49h-7.686
-v3.861h7.686v6.282h-8.758v3.976h23.04V39.067z"
-                />
-                <path
-                  id="XMLID_476_"
-                  fill="#FFF"
-                  d="M170.113,14.394l-28.202,0.001c-2.03,0-3.621,1.457-3.621,3.316l0.002,28.005c0.001,2.115,1.9,3.424,3.66,3.424h28.409c0.824,0,1.732-0.351,2.432-0.939c0.807-0.679,1.251-1.602,1.251-2.596l-0.001-27.778C174.042,15.742,172.5,14.394,170.113,14.394z M168.858,18.367v26.724l-25.463,0V18.369L168.858,18.367z"
-                />
+v3.861h7.686v6.282h-8.758v3.976h23.04V39.067z" />
+                <path id="XMLID_476_" fill="#FFF" d="M170.113,14.394l-28.202,0.001c-2.03,0-3.621,1.457-3.621,3.316l0.002,28.005c0.001,2.115,1.9,3.424,3.66,3.424h28.409c0.824,0,1.732-0.351,2.432-0.939c0.807-0.679,1.251-1.602,1.251-2.596l-0.001-27.778C174.042,15.742,172.5,14.394,170.113,14.394z M168.858,18.367v26.724l-25.463,0V18.369L168.858,18.367z" />
               </g>
               <g>
-                <path
-                  id="XMLID_475_"
-                  fill="#FFF"
-                  d="M234.621,16.644h-4.845l2.238,5.092h-6.883l4.632-7.075h-5.637l-4.689,7.134c-0.575,0.918-0.678,1.757-0.296,2.503c0.463,0.803,1.204,1.227,2.21,1.26l14.021-0.001c0.056-0.004,1.374-0.119,1.961-1.121c0.408-0.696,0.352-1.623-0.169-2.754C236.499,20.237,234.621,16.644,234.621,16.644z"
-                />
-                <path
-                  id="XMLID_471_"
-                  fill="#FFF"
-                  d="M236.358,27.874c-0.485-0.513-1.212-0.773-2.16-0.773h-11.46c-2.727,0-2.758,2.355-2.758,2.379v19.587h4.861v-6.638h7.269v2.625h-4.913v3.937l6.701-0.002c2.039,0,3.072-0.957,3.072-2.843l-0.001-16.651C236.971,29.456,237.012,28.565,236.358,27.874z M232.11,30.884v2.218h-7.269v-2.218H232.11z M232.11,36.658v2.215h-7.269v-2.215
-H232.11z"
-                />
+                <path id="XMLID_475_" fill="#FFF" d="M234.621,16.644h-4.845l2.238,5.092h-6.883l4.632-7.075h-5.637l-4.689,7.134c-0.575,0.918-0.678,1.757-0.296,2.503c0.463,0.803,1.204,1.227,2.21,1.26l14.021-0.001c0.056-0.004,1.374-0.119,1.961-1.121c0.408-0.696,0.352-1.623-0.169-2.754C236.499,20.237,234.621,16.644,234.621,16.644z" />
+                <path id="XMLID_471_" fill="#FFF" d="M236.358,27.874c-0.485-0.513-1.212-0.773-2.16-0.773h-11.46c-2.727,0-2.758,2.355-2.758,2.379v19.587h4.861v-6.638h7.269v2.625h-4.913v3.937l6.701-0.002c2.039,0,3.072-0.957,3.072-2.843l-0.001-16.651C236.971,29.456,237.012,28.565,236.358,27.874z M232.11,30.884v2.218h-7.269v-2.218H232.11z M232.11,36.658v2.215h-7.269v-2.215
+H232.11z" />
                 <path id="XMLID_470_" fill="#FFF" d="M242.25,30.455l13.047,0.002v-4.014h-10.943V25.07c7.277-2.622,11.396-9.303,11.396-9.303h-5.433c0,0-2.434,3.517-5.964,4.758v-5.864h-5.064l0.002,13.225C239.291,29.519,240.369,30.455,242.25,30.455z" />
-                <path
-                  id="XMLID_469_"
-                  fill="#FFF"
-                  d="M244.353,37.835v-6.236h-5.023l0.002,14.284c0,2.032,1.009,3.106,2.918,3.106l13.047,0v-4.051h-10.943v-2.266c6.72-2.542,11.458-10.166,11.458-10.166h-5.463C250.348,32.507,248.039,36.192,244.353,37.835z"
-                />
+                <path id="XMLID_469_" fill="#FFF" d="M244.353,37.835v-6.236h-5.023l0.002,14.284c0,2.032,1.009,3.106,2.918,3.106l13.047,0v-4.051h-10.943v-2.266c6.72-2.542,11.458-10.166,11.458-10.166h-5.463C250.348,32.507,248.039,36.192,244.353,37.835z" />
               </g>
-              <path
-                fill="#FFF"
-                d="M183.913,20.6h25.993v5.788h4.901l-0.001-6.153c0-2.054-1.338-3.382-3.409-3.382h-11.566v-2.773h-5.542v2.773h-11.27c-2.447,0-3.967,1.296-3.967,3.382v6.153h4.861L183.913,20.6z M206.875,37.054h2.163l4.669-9.237H208.6l-3.441,6.245c-0.656-1.251-1.267-2.746-1.791-4.375h-2.899c-0.464-0.776-1.154-1.718-1.886-2.574c0.149-0.216,0.356-0.573,0.622-1.043l0.016-0.028h9.064v-3.709h-22.71v3.709h7.542c-3.771,2.954-11.774,4.27-13.435,4.518v4.199c1.49-0.195,9.366-1.363,15.546-4.938c0.19,0.258,0.519,0.775,0.69,1.048c-4.112,4.071-14.113,5.95-16.236,6.312v4.247c1.536-0.243,10.602-1.82,17.617-6.536c0.08,0.459,0.094,0.901,0.158,1.861c-4.899,3.313-9.952,5.405-17.775,7.207v4.28c1.733-0.309,11.518-2.4,17.775-6.687v2.684c0,0.691-0.642,1.331-1.338,1.321h-5.732v3.891h7.327c2.973,0,4.516-1.455,4.516-4.354v-7.226c2.196,3.848,6.276,8.845,13.004,10.846v-4.457C213.257,43.436,208.773,40.441,206.875,37.054z"
-              />
+              <path fill="#FFF" d="M183.913,20.6h25.993v5.788h4.901l-0.001-6.153c0-2.054-1.338-3.382-3.409-3.382h-11.566v-2.773h-5.542v2.773h-11.27c-2.447,0-3.967,1.296-3.967,3.382v6.153h4.861L183.913,20.6z M206.875,37.054h2.163l4.669-9.237H208.6l-3.441,6.245c-0.656-1.251-1.267-2.746-1.791-4.375h-2.899c-0.464-0.776-1.154-1.718-1.886-2.574c0.149-0.216,0.356-0.573,0.622-1.043l0.016-0.028h9.064v-3.709h-22.71v3.709h7.542c-3.771,2.954-11.774,4.27-13.435,4.518v4.199c1.49-0.195,9.366-1.363,15.546-4.938c0.19,0.258,0.519,0.775,0.69,1.048c-4.112,4.071-14.113,5.95-16.236,6.312v4.247c1.536-0.243,10.602-1.82,17.617-6.536c0.08,0.459,0.094,0.901,0.158,1.861c-4.899,3.313-9.952,5.405-17.775,7.207v4.28c1.733-0.309,11.518-2.4,17.775-6.687v2.684c0,0.691-0.642,1.331-1.338,1.321h-5.732v3.891h7.327c2.973,0,4.516-1.455,4.516-4.354v-7.226c2.196,3.848,6.276,8.845,13.004,10.846v-4.457C213.257,43.436,208.773,40.441,206.875,37.054z" />
               <g>
                 <polygon id="XMLID_468_" fill="#FFF" points="268.998,32.332 264.811,23.662 259.317,23.662 263.189,32.332" />
                 <polygon id="XMLID_467_" fill="#FFF" points="268.756,22.309 264.964,14.394 259.558,14.394 263.006,22.309 " />
-                <path
-                  fill="#FFF"
-                  d="M268.529,34.2h-5.266l-0.025,0.219c-0.008,0.072-1.178,6.718-4.536,14.771h5.556c3.063-6.815,4.233-14.631,4.242-14.717
-L268.529,34.2z"
-                />
-                <path
-                  id="XMLID_463_"
-                  fill="#FFF"
-                  d="M295.075,32.643l-0.001-9.424c0-1.685-1.122-2.613-3.159-2.613h-4.069v-1.97h8.552v-3.861l-23.179,0
+                <path fill="#FFF" d="M268.529,34.2h-5.266l-0.025,0.219c-0.008,0.072-1.178,6.718-4.536,14.771h5.556c3.063-6.815,4.233-14.631,4.242-14.717
+L268.529,34.2z" />
+                <path id="XMLID_463_" fill="#FFF" d="M295.075,32.643l-0.001-9.424c0-1.685-1.122-2.613-3.159-2.613h-4.069v-1.97h8.552v-3.861l-23.179,0
 c-2.138,0-3.314,1.033-3.314,2.907v15.127c0.094,4.181-0.5,10.588-2.858,16.035l-0.149,0.346h5.222l0.062-0.157
 c1.788-4.525,2.667-10.194,2.667-15.55V18.636h8.272v1.97l-3.532,0c-1.978,0-3.045,1.346-3.045,2.613v9.389
 c0,2.487,1.452,2.83,3.021,2.83h3.995v9.957h-2.495v3.861l4.273,0c1.978,0,3.205-1.082,3.205-2.822V35.439h3.268
 C293.461,35.439,295.075,35.223,295.075,32.643z M290.214,24.198v2.064h-8.812l-0.001-2.064H290.214z M290.214,29.819v2.064
-h-8.811v-2.064H290.214z"
-                />
-                <path
-                  id="XMLID_462_"
-                  fill="#FFF"
-                  d="M281.646,37.1c-1.886,0-3.186,0-4.351,0c-0.627,5.028-3.023,11.032-3.023,11.032h4.543
-C278.815,48.132,281.02,43.161,281.646,37.1z"
-                />
+h-8.811v-2.064H290.214z" />
+                <path id="XMLID_462_" fill="#FFF" d="M281.646,37.1c-1.886,0-3.186,0-4.351,0c-0.627,5.028-3.023,11.032-3.023,11.032h4.543
+C278.815,48.132,281.02,43.161,281.646,37.1z" />
                 <path fill="#FFF" d="M294.034,37.1h-4.363c0.198,1.057,1.316,6.682,3.187,11.032h4.584C295.631,43.114,294.361,38.359,294.034,37.1z" />
               </g>
-              <path
-                fill="#FFF"
-                d="M337.303,37.937h-15.507v-1.854h13.598v-3.657h-12.877v-1.711h11.708V27.22h-11.708v-1.464h11.83v-3.575h-11.83v-1.527
+              <path fill="#FFF" d="M337.303,37.937h-15.507v-1.854h13.598v-3.657h-12.877v-1.711h11.708V27.22h-11.708v-1.464h11.83v-3.575h-11.83v-1.527
 h12.887v-3.737h-12.847c-0.535-2.42-0.683-2.698-0.683-2.698h-5.107c0.16,0.604,0.42,1.602,0.686,2.698h-7
 c0.766-1.27,0.968-2.103,1.056-2.698l-4.921,0c-0.208,0.749-1.412,4.409-5.522,6.996v4.682c1.223-0.327,1.979-0.9,2.491-1.249
 v8.921c0,0.873,0.251,1.537,0.746,1.975c0.768,0.681,1.833,0.543,1.844,0.539h10.504v1.854h-15.305v3.938h5.432
 c-0.691,1.998-3.551,6.909-3.551,6.909h5.647c0,0,2.693-4.816,3.358-6.909h4.418v7.381h5.146v-7.381h4.416
 c0.857,2.406,3.469,6.909,3.469,6.909h5.637c0,0-2.983-5.131-3.66-6.909h5.646V37.937z M317.453,32.427H308.5v-1.711h8.953V32.427
-z M317.453,27.22H308.5v-1.464h8.953V27.22z M317.453,22.181H308.5v-1.527h8.953V22.181z"
-              />
+z M317.453,27.22H308.5v-1.464h8.953V27.22z M317.453,22.181H308.5v-1.527h8.953V22.181z" />
               <g>
-                <path
-                  fill="#FFF"
-                  id="XMLID_459_"
-                  d="M377.435,18.514c0-2.424-1.459-3.814-4.004-3.814l-27.645,0.001c-2.516,0-3.901,1.322-3.901,3.723
+                <path fill="#FFF" id="XMLID_459_" d="M377.435,18.514c0-2.424-1.459-3.814-4.004-3.814l-27.645,0.001c-2.516,0-3.901,1.322-3.901,3.723
 l0.005,27.152c0,2.556,1.81,3.449,4.039,3.449l0.046,0.003l27.269-0.003c2.292,0,4.193-0.972,4.193-3.449L377.435,18.514z
- M372.292,44.977h-25.341V18.675l25.34-0.003L372.292,44.977z"
-                />
-                <path
-                  fill="#FFF"
-                  d="M366.732,23.889v-4.182h-5.146v4.182h-12.902v4.052h8.563c-1.48,3.031-5.104,7.505-8.642,9.59v4.647
+ M372.292,44.977h-25.341V18.675l25.34-0.003L372.292,44.977z" />
+                <path fill="#FFF" d="M366.732,23.889v-4.182h-5.146v4.182h-12.902v4.052h8.563c-1.48,3.031-5.104,7.505-8.642,9.59v4.647
 c6.305-2.621,10.252-7.973,12.981-12.76v10.448h-6.755v4.014h7.576c2.708,0,4.325-1.467,4.325-3.923V27.941h4.158v-4.052H366.732
-z"
-                />
+z" />
               </g>
             </g>
             <g>
@@ -123,34 +70,23 @@ z"
                 <stop offset="0.75" style="stop-color:#CC2A1C" />
                 <stop offset="1" style="stop-color:#C11920" />
               </linearGradient>
-              <path
-                fill="url(#SVGID_1_)"
-                d="M102.96,39.692L77.737,64.915l-2.879-2.878l23.934-23.932c-6.846-2.449-14.003-4.243-21.396-5.306
+              <path fill="url(#SVGID_1_)" d="M102.96,39.692L77.737,64.915l-2.879-2.878l23.934-23.932c-6.846-2.449-14.003-4.243-21.396-5.306
 			L61.508,48.687l-2.879-2.879l13.626-13.625c-3.539-0.341-7.127-0.518-10.756-0.518c-5.668,0-11.237,0.427-16.676,1.249
 			L31.928,45.808l16.229,16.229l-2.879,2.878L26.171,45.808l11.593-11.593C25.018,37,13.093,41.981,2.406,48.742l42.873,42.874
-			l16.229-16.229l16.229,16.229l42.867-42.867C115.039,45.228,109.138,42.189,102.96,39.692z"
-              />
-              <path
-                id="XMLID_457_"
-                fill="none"
-                d="M122.614,44.877l-12.419-12.419L77.737,64.915l-2.879-2.878l31.538-31.538
+			l16.229-16.229l16.229,16.229l42.867-42.867C115.039,45.228,109.138,42.189,102.96,39.692z" />
+              <path id="XMLID_457_" fill="none" d="M122.614,44.877l-12.419-12.419L77.737,64.915l-2.879-2.878l31.538-31.538
 			c0.509-0.508,0.509-1.332,0-1.84l-12.43-12.431L61.508,48.687l-2.879-2.879L90.26,14.176c0.456-0.456,0.456-1.196,0-1.652
 			L77.737,0L31.928,45.808l16.229,16.229l-2.879,2.878L26.171,45.808l31.467-31.466c0.547-0.547,0.547-1.435,0-1.982L45.279,0
 			L0.374,44.906c-0.498,0.498-0.498,1.306,0,1.804l44.905,44.905l16.229-16.229l16.229,16.229l44.877-44.876
-			C123.128,46.225,123.128,45.391,122.614,44.877z"
-              />
+			C123.128,46.225,123.128,45.391,122.614,44.877z" />
             </g>
           </g>
           <g id="图层_3">
-            <path
-              id="XMLID_458_"
-              fill="#C11920"
-              d="M122.614,44.877l-12.419-12.419L77.737,64.915l-2.879-2.878l31.538-31.538
+            <path id="XMLID_458_" fill="#C11920" d="M122.614,44.877l-12.419-12.419L77.737,64.915l-2.879-2.878l31.538-31.538
 c0.509-0.508,0.509-1.332,0-1.84l-12.43-12.431L61.508,48.687l-2.879-2.879L90.26,14.176c0.456-0.456,0.456-1.196,0-1.652L77.737,0
 L31.928,45.808l16.229,16.229l-2.879,2.878L26.171,45.808l31.467-31.466c0.547-0.547,0.547-1.435,0-1.982L45.279,0L0.374,44.906
 c-0.498,0.498-0.498,1.306,0,1.804l44.905,44.905l16.229-16.229l16.229,16.229l44.877-44.876
-C123.128,46.225,123.128,45.391,122.614,44.877z"
-            />
+C123.128,46.225,123.128,45.391,122.614,44.877z" />
           </g>
           <g id="图层_2">
             <linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="61.5" y1="30.1548" x2="61.5" y2="66.792">
@@ -159,20 +95,21 @@ C123.128,46.225,123.128,45.391,122.614,44.877z"
               <stop offset="0.75" style="stop-color:#CC2A1C" />
               <stop offset="1" style="stop-color:#C11920" />
             </linearGradient>
-            <path
-              fill="url(#SVGID_2_)"
-              d="M102.956,39.692L77.732,64.915l-2.879-2.878l23.934-23.932c-6.846-2.449-14.003-4.243-21.396-5.306
+            <path fill="url(#SVGID_2_)" d="M102.956,39.692L77.732,64.915l-2.879-2.878l23.934-23.932c-6.846-2.449-14.003-4.243-21.396-5.306
 L61.503,48.687l-2.879-2.879L72.25,32.182c-3.539-0.341-7.127-0.518-10.756-0.518c-5.668,0-11.237,0.427-16.676,1.249
 L31.923,45.808l16.229,16.229l-2.879,2.878L26.167,45.808l11.593-11.593C25.013,37,13.088,41.981,2.401,48.742l42.873,42.874
-l16.229-16.229l16.229,16.229l42.867-42.867C115.034,45.228,109.133,42.189,102.956,39.692z"
-            />
+l16.229-16.229l16.229,16.229l42.867-42.867C115.034,45.228,109.133,42.189,102.956,39.692z" />
           </g>
           <g id="图层_4"></g>
         </svg>
       </div>
-      <div class="header-menu-body"><Header /></div>
+      <div class="header-menu-body">
+        <Header />
+      </div>
+    </div>
+    <div class="menu-body">
+      <Menu />
     </div>
-    <div class="menu-body"><Menu /></div>
     <div class="main-body">
       <router-view />
     </div>
@@ -183,16 +120,55 @@ l16.229-16.229l16.229,16.229l42.867-42.867C115.034,45.228,109.133,42.189,102.956
 // 导入header.vue文件
 import Menu from "@/views/layout/Menu.vue";
 import Header from "@/views/layout/Header.vue";
+import { mapMutations } from 'vuex';
+
 export default {
   components: {
     Menu,
     Header,
   },
+  mounted () {
+    let that = this;
+    this.$nextTick(() => {
+      that.API.requestData({
+        isMust: false, // 请求是否携带 token ,默认为 true ,可缺省
+        method: "POST", // 请求方式,默认为 GET ,可缺省
+        subUrl: "/admin/loginvue", // 请求接口地址,必传项
+        data: {
+          username: "admin",
+          password: "admin"
+        },
+        success (res) {
+
+          that.SET_TOKEN({
+            token: res.data.authToken,
+            username: res.data.user.laborName
+          });
+
+          that.API.requestData({
+            method: "POST", // 请求方式,默认为 GET ,可缺省
+            subUrl: "admin/usermenu", // 请求接口地址,必传项
+            success () {
+              that.BASE.showMsg({
+                msg: '登陆成功',
+                type: 'success'
+              });
+              // that.$router.push('/'); // 跳转到首页
+            }
+          });
+
+        }
+      });
+    });
+  },
+  methods: {
+    ...mapMutations("user", ["SET_TOKEN"])
+  }
 };
 </script>
 
 <style lang="less">
-@import "./assets/styles/main.less";
+@import './assets/styles/main.less';
 
 * {
   box-sizing: border-box;
@@ -220,7 +196,7 @@ body {
   margin: 0;
   background: #fff;
   color: #fff;
-  background-image: url("./assets/background.png");
+  background-image: url('./assets/background.png');
   background-size: cover;
   font-size: @fontsize;
 }

+ 32 - 0
src/api/AES.js

@@ -0,0 +1,32 @@
+import CryptoJS from 'crypto-js';
+/**
+ * CryptoJS加密
+ */
+export function localEncrypt(word, keyStr) {
+  keyStr = keyStr ? keyStr : "BTRH201911PERMIS";
+  let key = CryptoJS.enc.Utf8.parse(keyStr);
+  let srcs = CryptoJS.enc.Utf8.parse(word);
+  let encrypted = CryptoJS.AES.encrypt(srcs, key, {
+    mode: CryptoJS.mode.ECB,
+    padding: CryptoJS.pad.Pkcs7
+  });
+  return encrypted.toString();
+}
+
+/**
+ * CryptoJS解密
+ */
+export function localDecrypt(word, keyStr) {
+  keyStr = keyStr ? keyStr : "BTRH201911PERMIS";
+  var key = CryptoJS.enc.Utf8.parse(keyStr);
+  var decrypt = CryptoJS.AES.decrypt(word, key, {
+    mode: CryptoJS.mode.ECB,
+    padding: CryptoJS.pad.Pkcs7
+  });
+  return CryptoJS.enc.Utf8.stringify(decrypt).toString();
+}
+
+export default {
+  localEncrypt,
+  localDecrypt
+}

+ 116 - 0
src/api/axios.js

@@ -0,0 +1,116 @@
+// 引入axios
+import axios from 'axios';
+import BASE from '@tools/basicTool.js';
+
+axios.defaults.withCredentials = true;
+
+/**
+ * 通用请求函数
+ * @param {Object} options 详细配置项,使用方法与所有配置项说明如下:
+
+  this.API.requestData({
+    isMust: true, // 请求是否携带 token ,默认为 true ,可缺省
+    showLoading: false, // 请求是否显示加载中遮罩层,默认 false ,可缺省
+    method: "GET", // 请求方式,默认为 GET ,可缺省
+    baseURL: "http://192.168.10.23:8082/", // 请求服务器地址 + 端口,可缺省
+    subUrl: "api/repassword", // 请求接口地址,必传项
+    timeout: 3000, // 请求超时时间,默认 3s ,可缺省
+    data: { name: "admin", pasword: "123456" }, // 请求所携带参数,默认为空,可缺省
+    success (res) {
+      // 请求成功的回调
+    },
+    fail (error) {
+      // 请求失败的回调
+    }
+  });
+
+ */
+export function requestData (options) {
+  return new Promise((resolve, reject) => {
+
+    if (options.showLoading) {
+      BASE.showLoading();
+    }
+
+    // 包装请求头
+    let headers = options.headers || {
+      'Content-Type': 'application/x-www-form-urlencoded',
+      'Access-Control-Allow-Origin': '*',
+      'Access-Control-Allow-Credentials': 'true'
+    };
+
+    // 请求是否携带 token
+    const isMust = (options.isMust == true || options.isMust == false) ? options.isMust : true;
+    if (isMust) headers.authToken = localStorage.getItem('authToken');
+
+    // 创建请求实例
+    const XHRReq = axios.create({
+      headers,
+      withCredentials: true,
+      crossDomain: true,
+      baseURL: window.__MODE__.baseURL || '/api/',
+      timeout: options.timeout || 3000, // 请求超时时间 - 3s
+    });
+
+    // 请求拦截器
+    XHRReq.interceptors.request.use((config) => {
+      return config;
+    }, (err) => {
+      return Promise.reject(err);
+    });
+
+    // 统一格式包装请求参数
+    let params = new URLSearchParams();
+    for (let key in (options.data || {})) {
+      params.append(key, options.data[key]);
+    }
+
+    // 发起请求
+    XHRReq({
+      url: options.subUrl,
+      method: options.method || 'GET',
+      params,
+    }).then(response => {
+      if (options.showLoading) {
+        BASE.closeLoading();
+      }
+      if (response.code === 501) { // 用户类请求错误code (账号密码错误、用户锁定、token过期等)
+
+        localStorage.removeItem('authToken');
+        BASE.showMsg({
+          msg: (response.data && response.data.msg) || ("请求出错[" + response.data.code + "]")
+        });
+
+        setTimeout(() => {
+          // window.location.reload();
+          // window.__STATICVUE__.$router.replace('/login');
+        }, 1000);
+
+      } else if (response.data.code === 200) { // 请求成功 code
+
+        options.success && options.success(response.data);
+        resolve(response);
+
+      } else { // 其他code
+
+        BASE.showMsg({
+          msg: (response.data && response.data.msg) || ("请求出错[" + response.data.code + "]")
+        });
+
+      }
+    }).catch(error => {
+
+      if (options.showLoading) {
+        BASE.closeLoading();
+      }
+
+      options.fail && options.fail(error);
+      reject(error);
+
+    });
+  });
+}
+
+export default {
+  requestData
+}

+ 13 - 0
src/api/config.js

@@ -0,0 +1,13 @@
+/**
+ * 国电电力宁夏新能源集中监控系统
+ * */
+
+//测试 - 国电
+export default {
+  webSoketUrl: 'ws://10.155.32.4:8082/gyee-websocket', // webSoket
+}
+
+//生产 - 国电
+// export default {
+//   webSoketUrl: '192.168.4.203:9008', // webSoket
+// }

+ 27 - 9
src/main.js

@@ -1,12 +1,30 @@
-import { createApp } from 'vue'
-import App from './App.vue'
-import router from './router'
-import store from './store'
-import 'font-awesome/css/font-awesome.min.css'
+import { createApp } from 'vue';
+import App from './App.vue';
+import router from './router';
+import store from './store';
+import 'font-awesome/css/font-awesome.min.css';
+
+// 引入 element-ui
+import ElementPlus from 'element-plus';
+import 'element-plus/lib/theme-chalk/index.css';
+
+// 引入环境配置
+import "@modeConfig/modeConfig.js";
 
 import "@/lib/global-import.js";
 
-createApp(App)
-    .use(store)
-    .use(router)
-    .mount('#app')
+// 引入请求工具
+import axios from "@api/axios";
+
+// 引入基础工具
+import basicTool from "@tools/basicTool";
+
+window.__STATICVUE__ = createApp(App);
+window.__STATICVUE__.use(ElementPlus);
+window.__STATICVUE__.use(store);
+window.__STATICVUE__.use(router);
+
+window.__STATICVUE__.config.globalProperties.API = axios; //全局注册
+window.__STATICVUE__.config.globalProperties.BASE = basicTool; //全局注册
+
+window.__STATICVUE__.mount('#app');

+ 16 - 15
src/router/index.js

@@ -27,20 +27,20 @@ const routes = [
     name: 'WindSite',
     component: () => import(/* webpackChunkName: "windsite" */ '../views/WindSite/WindSite.vue'),
     children: [{
-        path: 'home',
-        component: () => import(/* webpackChunkName: "windsitehome" */ '../views/WindSite/pages/Home/Home.vue')
-    },{
-        path: 'draughtfanlist',
-        component: () => import(/* webpackChunkName: "windsitedraughtfanlist" */ '../views/WindSite/pages/DraughtFanList.vue')
-    },{
-        path: 'matrix',
-        component: () => import(/* webpackChunkName: "windsitematrix" */ '../views/WindSite/pages/Matrix.vue')
-    },{
-        path: 'lightmatrix',
-        component: () => import(/* webpackChunkName: "windsitelightmatrix" */ '../views/WindSite/pages/LightMatrix.vue')
-    },{
-        path: 'box',
-        component: () => import(/* webpackChunkName: "windsitebox" */ '../views/WindSite/pages/Box.vue')
+      path: 'home',
+      component: () => import(/* webpackChunkName: "windsitehome" */ '../views/WindSite/pages/Home/Home.vue')
+    }, {
+      path: 'draughtfanlist',
+      component: () => import(/* webpackChunkName: "windsitedraughtfanlist" */ '../views/WindSite/pages/DraughtFanList.vue')
+    }, {
+      path: 'matrix',
+      component: () => import(/* webpackChunkName: "windsitematrix" */ '../views/WindSite/pages/Matrix.vue')
+    }, {
+      path: 'lightmatrix',
+      component: () => import(/* webpackChunkName: "windsitelightmatrix" */ '../views/WindSite/pages/LightMatrix.vue')
+    }, {
+      path: 'box',
+      component: () => import(/* webpackChunkName: "windsitebox" */ '../views/WindSite/pages/Box.vue')
     }]
   },
   {
@@ -57,7 +57,7 @@ const routes = [
     path: '/lightmatrix2',
     name: 'LightMatrix2',
     component: () => import(/* webpackChunkName: "lightmatrix2" */ '../views/LightMatrix2/LightMatrix2.vue')
-  },{
+  }, {
     path: '/lightmatrix3',
     name: 'LightMatrix3',
     component: () => import(/* webpackChunkName: "lightmatrix3" */ '../views/LightMatrix3/LightMatrix3.vue')
@@ -66,6 +66,7 @@ const routes = [
 
 const router = createRouter({
   history: createWebHashHistory(),
+  base: '/zhfx/',
   routes
 })
 

+ 48 - 5
src/store/index.js

@@ -1,12 +1,55 @@
-import { createStore, createLogger } from 'vuex'
-import weather from './modules/weather'
+import { createStore, createLogger } from 'vuex';
+import weather from './modules/weather';
+import user from './modules/user';
 
-const debug = process.env.NODE_ENV !== 'production'
+const debug = process.env.NODE_ENV !== 'production';
+
+// 默认状态
+const state = {
+  loading: false, //全局 - 加载中....
+  themeName: "light", // 主题
+  windturbineMap: {},
+};
+
+//改变状态的方法
+const mutations = {
+  loadingStore (state, tag) {
+    state.loading = tag;
+  },
+  changeTheme (state, tag) {
+    state.themeName = tag;
+  },
+  update (state, newData) {
+    state.windturbineMap = newData
+  }
+};
+
+const actions = {
+  getupdate (context, newData) {
+    context.commit("update", newData);
+  },
+};
+
+const getters = {
+  authToken: state => state.user.authToken,  //建立token的快捷访问   user 是因为index.js中导入的时候名称定义为user
+  submitDDTag: state => state.submitDDTag,
+  loading: state => state.loading,
+  username: state => state.user.username,
+  themeName: state => state.themeName,
+  asidez: state => state.z,
+  mainy: state => state.y,
+  login: state => state.login,
+}
 
 export default createStore({
   modules: {
-    weather
+    weather,
+    user
   },
+  state,
+  mutations,
+  actions,
+  getters,
   strict: debug,
   plugins: debug ? [createLogger()] : []
-})
+});

+ 46 - 0
src/store/modules/user.js

@@ -0,0 +1,46 @@
+// import {getToken,setToken,removeToken} from '@/utils/auth'
+// import { Message } from 'element-plus';
+const state = {
+  authToken: '', //
+  username: '',
+}
+const mutations = {
+  REMOVE_TOKEN (state) {
+    localStorage.removeItem('authToken');
+    localStorage.removeItem('username');
+    state.authToken = "";
+    state.username = "";
+    Message({
+      message: '退出成功',
+      type: 'success'
+    });
+    setTimeout(() => {
+      window.location.reload();
+    }, 1000);
+
+  },
+  SET_TOKEN: (state, token_name) => {
+    state.authToken = token_name.token;
+    state.username = token_name.username;
+    localStorage.setItem('authToken', token_name.token);
+    localStorage.setItem('username', token_name.username);
+  },
+  SET_NAME: (state, name) => {
+    state.username = name;
+  },
+}
+const actions = {
+  async login (context, data) {
+    const result = await login(data)
+    if (result.data.sucess) {
+      //调用vuex中setToken方法
+      context.commit('setToken', result.data.data)
+    }
+  }
+}
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions,
+}

+ 264 - 0
src/tools/basicTool.js

@@ -0,0 +1,264 @@
+
+let loadingStatus = null;
+
+import { ElMessage } from 'element-plus';
+import { ElLoading } from 'element-plus';
+
+export default {
+  /**
+   * 页面顶部出现消息提示
+   * @param {Object} options 传入一个对象为配置项,其中:
+   * @param {Boolean} showClose 是否显示可手动关闭的 x 于提示框右侧,默认 false
+   * @param {Boolean} center 消息提示内容是否居中,默认 true
+   * @param {String} msg 消息提示的内容
+   * @param {String} type 消息提示的类型,可选值为 ['success(成功)','warning(警告)','error(错误)',或者直接传入空字符串],默认 error
+   */
+  showMsg (options) {
+    ElMessage({
+      showClose: (options.showClose == true || options.showClose == false) ? options.showClose : false,
+      center: (options.center == true || options.center == false) ? options.center : true,
+      message: options.msg,
+      type: (options.type || options.type === '') ? options.type : 'error'
+    });
+  },
+
+  /**
+   * 显示防穿透点击 loading 蒙版
+   * @param {Objectr} opt 传入一个对象为配置项,其中:
+   * @param {String} target 此蒙版需要绑定的 DOM 标签 ID 或者 CLASS 或者 TAGNAME,默认绑在 body 上
+   * @param {Boolean} body 是否插入蒙版至 boyd 上,默认 true
+   * @param {Boolean} fullscreen 蒙版是否全屏蒙住整个 html 页面,默认 true
+   * @param {Boolean} lock 蒙版出现时,是否锁定屏幕滚动,默认 false
+   * @param {String} text 蒙版上显示的提示文本
+   * @param {String} background 蒙版的背景颜色,写死 50% 透明度的纯黑色
+   */
+  showLoading (opt) {
+    let options = opt || {};
+    loadingStatus = ElLoading.service({
+      target: options.target || 'body',
+      body: (options.body == true || options.body == false) ? options.body : false,
+      fullscreen: (options.fullscreen == true || options.fullscreen == false) ? options.fullscreen : true,
+      lock: (options.lock == true || options.lock == false) ? options.lock : false,
+      text: options.text || '请稍等...',
+      background: 'rgba(0,0,0,.5)',
+    });
+  },
+
+  /**
+   * 获取标签上的自定义属性
+   * @param {any} node 传入 字符串 或 标准DOM对象 或 jQuery DOM对象 ,函数自动判断传入的类型并返回其 dataset 属性。
+   */
+  getCurrentData (node) {
+    // 如果传入的是 jQuery 对象
+    if (window.jQuery && node instanceof jQuery) {
+      return node[0].dataset;
+    } else {
+      // 判断传入的是否是标准 DOM 对象
+      let isDom = (typeof node === 'object') ?
+        function (obj) {
+          return obj instanceof HTMLElement;
+        } :
+        function (obj) {
+          return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
+        };
+
+      // 如果是标准 DOM 对象,输出 dataset
+      if (isDom(node)) {
+        return node.dataset;
+      } else {
+        // 如果是不是,则表示传入的是字符串,根据字符串取 DOM 后输出 dataset
+        let dom = document.querySelector(node);
+        return dom.dataset;
+      }
+    }
+  },
+
+  /**
+   * 关闭loading
+   */
+  closeLoading () {
+    loadingStatus.close();
+  },
+
+  /**
+   * 深拷贝 json 数组
+   * @param {Array} jsonArray 传入 Json 数组,返回一个指向新指针拷贝份数据
+   */
+  deepCopy (jsonArray) {
+    return JSON.parse(JSON.stringify(jsonArray));
+  },
+
+  /**
+   * 根据后端返回的 ID 遍历树形结构包装组件编辑用数据函数
+   * @param {String} key 需要找到的 ID
+   * @param {Array} treeData 树形 Array
+   */
+  getTreeDeepArr (key, treeData) {
+
+    let arr = []; // 在递归时操作的数组
+    let returnArr = []; // 存放结果的数组
+    let depth = 0; // 定义全局层级
+
+    // 定义递归函数
+    function childrenEach (childrenData, depthN) {
+
+      for (var j = 0; j < childrenData.length; j++) {
+
+        depth = depthN; // 将执行的层级赋值 到 全局层级
+        arr[depthN] = (childrenData[j].id);
+
+        if (childrenData[j].id == key) {
+
+          // returnArr = arr; // 原写法不行, 因 此赋值存在指针关系
+          returnArr = arr.slice(0, depthN + 1); //将目前匹配的数组,截断并保存到结果数组
+          break;
+
+        } else {
+
+          if (childrenData[j].children) {
+
+            depth++;
+            childrenEach(childrenData[j].children, depth);
+
+          }
+
+        }
+
+      }
+
+      return returnArr;
+
+    }
+
+    return childrenEach(treeData, depth);
+
+  },
+
+  /**
+   * 获取数据的类型
+   * @param {any} options 传入一个数据,返回其类型 (object, array, string, number等)
+   */
+  getType (options) {
+    return Object.prototype.toString.call(options).slice(8, Object.prototype.toString.call(options).length - 1).toLowerCase();
+  },
+
+  /**
+   * 控制页面滚动到指定位置
+   * @param {Object} options 传入一个配置项,其中:
+   * @param {String} el 需要滚动的 DOM 元素选择器,可以为 CLASS 或 ID
+   * @param {Number} scrollTop 需要滚动到顶部的位置,数值越低滚动的越靠近顶部,默认 0
+   * @param {Number} scrollLeft 需要滚动到顶部的位置,数值越低滚动的越靠近顶部,默认 0
+   * @param {Number} speed 滚动到指定位置需要的时间 (动画时间),默认 200
+   * @param {Function} success 滚动执行完毕后的回调函数
+   */
+  scrollTo (options) {
+    if (!options || !options.el) {
+      this.showMsg({
+        msg: 'scrollTo() 方法需要传入 el 属性'
+      });
+      return;
+    }
+    if ($(options.el)[0] && ($(options.el)[0].scrollHeight > (window.innerHeight || document.documentElement.clientHeight))) {
+      $(options.el).animate({
+        scrollTop: options.scrollTop || 0,
+        scrollLeft: options.scrollLeft || 0,
+      }, options.speed || 200, () => {
+        options.success && options.success();
+      });
+    } else {
+      options.success && options.success();
+    }
+  },
+
+  /**
+   * 导出 Json 为 excel 表格
+   * @param {Object} options 传入一个配置项,根据传入的配置项导出对应的 excel 表格,其中:
+   * @param {Array} tTitle 表格的标题,置空则为默认以日期为标题的表格
+   * @param {Array} tHeader 表格的表头,必传
+   * @param {Array} tBody 表格需要展示的字段名,必传
+   * @param {Array} tMerges 表格标题需要合并的单元格,置空则为默认 A1 格为表格标题显示区域
+   * @param {Array} tData 表格渲染所用的数据源,必传
+   * @param {Boolean} autoWidth 表是否根据表格内容自动撑开列宽,置空则为默认 true 
+   * @param {String} exportName 所导出的表格文件名,置空则以时间戳为文件名称进行导出
+   */
+  exportExcelForJson (options) {
+    const {
+      export_json_to_excel
+    } = __getExport2Excel();
+
+    let title = options.tTitle;
+
+    if (!title || !title.length) {
+      title = []
+      options.tBody.forEach((ele, index) => {
+        if (!index) {
+          title.push(new Date().formatDate("yyyy-MM-dd") + '导出的表格');
+        } else {
+          title.push("");
+        }
+      });
+    }
+
+    let header = options.tHeader;
+    let data = options.tData.map(data => options.tBody.map(key => data[key]));
+    let merges = options.tMerges || [];
+    let filename = options.exportName || new Date().getTime();
+    let bookType = "xlsx";
+    let autoWidth = (options.autoWidth == true || options.autoWidth == false) ? options.autoWidth : true;
+
+    data.map(item => {
+      item.map((i, index) => {
+        if (!i) item[index] = "";
+      });
+    });
+
+    export_json_to_excel({
+      title,
+      header,
+      data,
+      merges,
+      filename,
+      bookType,
+      autoWidth
+    });
+  },
+
+  /**
+   * 颜色进制转换  16 <--> 10 互转
+   * @param {String} colorStr 传入一个颜色字符串, 16进制 或者 10进制 ,返回转换后的结果,例:传入 #1890ff ,返回 rgb(24, 144, 255),反之亦然
+   */
+  replaceColor (colorStr) {
+    if (!colorStr) return '';
+
+    let colorString = colorStr.replace(/#|rgb|\(|\)|\|;|\s+/g, "");
+
+    if (colorString.indexOf(",") === -1) {
+      let color10 = [];
+      for (let i = 0; i < colorString.length; i++) {
+        if (!((i + 1) % 2)) {
+          color10.push(parseInt((colorString[i - 1] + colorString[i]), 16));
+        }
+      }
+      return "rgb(" + color10.toString() + ")";
+    } else {
+      let colorArray = colorString.split(',');
+      let color16 = '';
+      colorArray.forEach(ele => {
+        color16 += (parseInt(ele).toString(16));
+      });
+      return "#" + color16;
+    }
+  },
+
+  // 正则表达式
+  regs: {
+    // 是否为手机号
+    isPhone: /^1(3|4|5|6|7|8|9)\d{9}$/,
+    // 是否为合法 15 或 18 位身份证号
+    isIdentityCard: /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/,
+    // 是否是邮箱
+    isMail: /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/,
+    // 是否是数字
+    isNumber: /^(-?\d+)(\.\d+)?$/
+  }
+};

+ 56 - 0
src/tools/websocket.js

@@ -0,0 +1,56 @@
+import Stomp from "stompjs";
+import store from '@store/index';
+var projectconfig = `ws://${window.__MODE__.websocketUrl}`;
+// ============================一般使用的变量============================
+let number = 0;
+export const datainit = initialize;
+export const webtest = test;
+
+// ============================  大函数体   ============================
+function initialize (topic, adpClient) {
+
+  if (adpClient != null) {
+    adpClient.disconnect();
+  }
+
+  var url = projectconfig;
+  // let socket = new SockJS(url);  // 这个地址要找你们后端
+  // adpClient = Stomp.over(socket);
+  adpClient = Stomp.client(url);
+  adpClient.debug = null;
+
+  adpClient.connect({ topic: topic, authToken: localStorage.getItem('authToken') }, adpClient2 => connectCallBackSubscribe(adpClient, topic), error => reconnect(error, adpClient, topic));
+
+  return adpClient;
+}
+// 断线重连
+function reconnect (error, adpClient, topic) {
+  //连接失败时再次调用函数
+  number++;
+  adpClient.connected = false;
+  clearTimeout(setTimeout(initialize(topic), 1000 * 60 * 5));
+  debugX("DataAdapter reconnect:" + number + " 次");
+  return;
+}
+// ============================  订阅函数体  ============================
+function connectCallBackSubscribe (adpClient, topic) {
+  number = 0;
+  adpClient.connected = true;
+  adpClient.subscribe(topic, stompMessage => reflexWindturbineBasicInformation(stompMessage));
+}
+// ============================  解析函数体  ============================
+function reflexWindturbineBasicInformation (stompMessage) {
+  var newdata = JSON.parse(stompMessage.body);
+  store.dispatch('getupdate', newdata);
+  // console.log("newdata", newdata)
+
+}
+// ============================  其他  ============================
+function debugX (text) {
+  console.log("text", text);
+}
+
+function test () {
+  clearTimeout(setTimeout(initialize('/topic/detial/param_MG01_02'), 1000 * 60 * 2));
+}
+

+ 46 - 43
src/views/LightMatrix/LightMatrix.vue

@@ -7,45 +7,45 @@
       <div class="dot right bottom"></div>
       <Row>
         <Col :span="3">
-          <div class="panel-item-gf">
-            <div class="panel-item-gf-left">
-              <span class="svg-icon svg-icon-write svg-icon-md">
-                <SvgIcon :svgid="panelData.first.icon"></SvgIcon>
+        <div class="panel-item-gf">
+          <div class="panel-item-gf-left">
+            <span class="svg-icon svg-icon-write svg-icon-md">
+              <SvgIcon :svgid="panelData.first.icon"></SvgIcon>
+            </span>
+          </div>
+          <div class="panel-item-gf-right">
+            <div class="panel-item-gf-up">{{ panelData.first.text }}</div>
+            <div class="panel-item-gf-down">{{ panelData.first.num }}</div>
+          </div>
+        </div>
+        </Col>
+        <Col :span="3" v-for="(data, index) of panelData.datas" :key="index">
+        <div class="panel-item" :class="data.color">
+          <div class="panel-item-left">
+            <div class="panel-item-li">
+              <span>{{ data.name }}</span>
+              <span class="svg-icon svg-icon-sm" :class="'svg-icon-' + data.color">
+                <SvgIcon :svgid="data.nameIcon"></SvgIcon>
               </span>
             </div>
-            <div class="panel-item-gf-right">
-              <div class="panel-item-gf-up">{{ panelData.first.text }}</div>
-              <div class="panel-item-gf-down">{{ panelData.first.num }}</div>
+            <div class="panel-item-li">
+              <span>{{ data.num }}</span>
+              <span class="svg-icon svg-icon-sm" :class="'svg-icon-' + data.color">
+                <SvgIcon :svgid="data.numIcon"></SvgIcon>
+              </span>
             </div>
           </div>
-        </Col>
-        <Col :span="3" v-for="(data, index) of panelData.datas" :key="index">
-          <div class="panel-item" :class="data.color">
-            <div class="panel-item-left">
-              <div class="panel-item-li">
-                <span>{{ data.name }}</span>
-                <span class="svg-icon svg-icon-sm" :class="'svg-icon-' + data.color">
-                  <SvgIcon :svgid="data.nameIcon"></SvgIcon>
-                </span>
-              </div>
-              <div class="panel-item-li">
-                <span>{{ data.num }}</span>
-                <span class="svg-icon svg-icon-sm" :class="'svg-icon-' + data.color">
-                  <SvgIcon :svgid="data.numIcon"></SvgIcon>
-                </span>
-              </div>
+          <div class="panel-item-right">
+            <div class="panel-item-ri">
+              <span>{{ data.text1 }}</span>
+              <span>{{ data.num1 }}</span>
             </div>
-            <div class="panel-item-right">
-              <div class="panel-item-ri">
-                <span>{{ data.text1 }}</span>
-                <span>{{ data.num1 }}</span>
-              </div>
-              <div class="panel-item-ri">
-                <span>{{ data.text2 }}</span>
-                <span>{{ data.num2 }}</span>
-              </div>
+            <div class="panel-item-ri">
+              <span>{{ data.text2 }}</span>
+              <span>{{ data.num2 }}</span>
             </div>
           </div>
+        </div>
         </Col>
       </Row>
     </div>
@@ -107,6 +107,7 @@ import Row from "@com/coms/grid/row.vue";
 import Col from "@com/coms/grid/col.vue";
 import SvgIcon from "@com/coms/icon/svg-icon.vue";
 import util from "@/helper/util.js";
+
 export default {
   // 名称
   name: "LightMatrix",
@@ -117,7 +118,7 @@ export default {
     SvgIcon,
   },
   // 数据
-  data() {
+  data () {
     return {
       panelData: {
         first: {
@@ -300,9 +301,10 @@ export default {
       ],
     };
   },
+
   // 函数
   methods: {
-    createGroupDatas: function(table) {
+    createGroupDatas: function (table) {
       table.groupDatas = [];
       let tempDatas = [];
       table.datas.forEach((data, index) => {
@@ -321,10 +323,10 @@ export default {
     },
   },
   // 生命周期钩子
-  beforeCreate() {
+  beforeCreate () {
     // 创建前
   },
-  created() {
+  created () {
     // 创建后
     let tempData = [];
     for (let i = 0; i < 45; i++) {
@@ -354,18 +356,19 @@ export default {
       this.tables.push(util.copy(this.tables[0]));
     }
   },
-  beforeMount() {
+  beforeMount () {
     // 渲染前
   },
-  mounted() {
-    // 渲染后
+  mounted () {
+    let that = this;
+    that.$nextTick(() => { });
   },
-  beforeUpdate() {
+  beforeUpdate () {
     // 数据更新前
   },
-  updated() {
+  updated () {
     // 数据更新后
-  },
+  }
 };
 </script>
 
@@ -654,7 +657,7 @@ export default {
 
           .sub-count {
             font-size: @fontsize;
-            font-family: "Bicubik";
+            font-family: 'Bicubik';
             font-weight: 500;
 
             &.write {

+ 585 - 561
src/views/LightMatrix1/LightMatrix1.vue

@@ -1,590 +1,614 @@
 <template>
-    <div class="light-matrix">
-        <Row class="panel-2" type="">
-            <Col :span="12" class="left-50-16">
-                <div class="panel">
-                    <div class="dot left top"></div>
-                    <div class="dot left bottom"></div>
-                    <div class="dot right top"></div>
-                    <div class="dot right bottom"></div>
-                    <div class="item">
-                        <div class="loop"></div>
-                        <span class="svg-icon svg-icon-gray svg-icon-md">
-                            <SvgIcon :svgid="panel1Data.first.icon"></SvgIcon>
-                        </span>
-                    </div>
-                    <div class="item" :class="data.color" v-for="(data, index) of panel1Data.datas" :key="index">
-                        <div>{{data.test}}</div>
-                        <div>{{data.num}}</div>
-                    </div>
-                </div>
-                
-            </Col>
-            <Col :span="12" class="left-50-16">
-                <div class="panel">
-                    <div class="dot left top"></div>
-                    <div class="dot left bottom"></div>
-                    <div class="dot right top"></div>
-                    <div class="dot right bottom"></div>
-                    <div class="item">
-                        <div class="loop"></div>
-                        <span class="svg-icon svg-icon-gray svg-icon-md">
-                            <SvgIcon :svgid="panel2Data.first.icon"></SvgIcon>
-                        </span>
-                    </div>
-                    <div class="item" :class="data.color" v-for="(data, index) of panel2Data.datas" :key="index">
-                        <div>{{data.test}}</div>
-                        <div>{{data.num}}</div>
-                    </div>
-                </div>
-            </Col>
-        </Row>
-        <div class="panel-box">
-            <div v-for="(table, k) of tables" :key="k">
-                <div class="panel-title">
-                    <div class="panel-title-name">
-                        <i class="fa fa-send"></i>
-                        <span>某某某风电场</span>
-                        <div class="sub-title-item" v-for="(data, index) of table.subTitleDatas" :key="index">
-                            <span class="sub-title">{{data.text}}</span>
-                            <span class="sub-count" :class="data.color">{{data.num}}</span>
-                        </div>
-                    </div>
-                </div>
-                <div class="panel-body">
-                    <table>
-                        <tbody>
-                            <tr v-for="(row, i) of table.groupDatas" :key="i">
-                                <td v-for="(col, j) of row" :key="j">
-                                    <div class="card" :class="col.color">
-                                        {{col.tag}}
-                                    </div>
-                                </td>
-                            </tr>
-                        </tbody>
-                    </table>
-                </div>
+  <div class="light-matrix">
+    <Row class="panel-2" type="">
+      <Col :span="12" class="left-50-16">
+      <div class="panel">
+        <div class="dot left top"></div>
+        <div class="dot left bottom"></div>
+        <div class="dot right top"></div>
+        <div class="dot right bottom"></div>
+        <div class="item">
+          <div class="loop"></div>
+          <span class="svg-icon svg-icon-gray svg-icon-md">
+            <SvgIcon svgid="svg-wind-site"></SvgIcon>
+          </span>
+        </div>
+        <div class="item write" @click="changeShow('jrfj_FDC')">
+          <div>接入风机</div>
+          <div>{{sourceMap.fcjrnum || '---'}}</div>
+        </div>
+        <div class="item blue" @click="changeShow('yx_FDC', 1)">
+          <div>· 运行</div>
+          <div>{{sourceMap.fcyxnum || '---'}}</div>
+        </div>
+        <div class="item green" @click="changeShow('dj_FDC', 0)">
+          <div>· 待机</div>
+          <div>{{sourceMap.fcdjnum || '---'}}</div>
+        </div>
+        <div class="item purple" @click="changeShow('xd_FDC', 5)">
+          <div>· 限电</div>
+          <div>{{sourceMap.fcxdnum || '---'}}</div>
+        </div>
+        <div class="item red" @click="changeShow('gz_FDC', 2)">
+          <div>· 故障</div>
+          <div>{{sourceMap.fcgznum || '---'}}</div>
+        </div>
+        <div class="item orange" @click="changeShow('jx_FDC', 4)">
+          <div>· 检修</div>
+          <div>{{sourceMap.fcwhnum || '---'}}</div>
+        </div>
+        <div class="item write" @click="changeShow('sl_FDC', 6)">
+          <div>· 受累</div>
+          <div>{{sourceMap.fcslnum || '---'}}</div>
+        </div>
+        <div class="item gray" @click="changeShow('lx_FDC', 3)">
+          <div>· 离线</div>
+          <div>{{sourceMap.fclxnum || '---'}}</div>
+        </div>
+      </div>
+      </Col>
+      <Col :span="12" class="left-50-16">
+      <div class="panel">
+        <div class="dot left top"></div>
+        <div class="dot left bottom"></div>
+        <div class="dot right top"></div>
+        <div class="dot right bottom"></div>
+        <div class="item">
+          <div class="loop"></div>
+          <span class="svg-icon svg-icon-gray svg-icon-md">
+            <SvgIcon svgid="svg-photovoltaic"></SvgIcon>
+          </span>
+        </div>
+        <div class="item write" @click="changeShow('jrfj1_GDC')">
+          <div>接入风机</div>
+          <div>{{sourceMap.gfjrnum || '---'}}</div>
+        </div>
+        <div class="item blue" @click="changeShow('yx1_GDC', 1)">
+          <div>· 运行</div>
+          <div>{{sourceMap.gfyxnum || '---'}}</div>
+        </div>
+        <div class="item green" @click="changeShow('dj1_GDC', 0)">
+          <div>· 待机</div>
+          <div>{{sourceMap.gfdjnum || '---'}}</div>
+        </div>
+        <div class="item purple" @click="changeShow('xd1_GDC', 5)">
+          <div>· 限电</div>
+          <div>{{sourceMap.gfxdnum || '---'}}</div>
+        </div>
+        <div class="item red" @click="changeShow('gz1_GDC', 2)">
+          <div>· 故障</div>
+          <div>{{sourceMap.gfgznum || '---'}}</div>
+        </div>
+        <div class="item orange" @click="changeShow('jx1_GDC', 4)">
+          <div>· 检修</div>
+          <div>{{sourceMap.gfwhnum || '---'}}</div>
+        </div>
+        <div class="item write" @click="changeShow('sl1_GDC', 6)">
+          <div>· 受累</div>
+          <div>{{sourceMap.gfslnum || '---'}}</div>
+        </div>
+        <div class="item gray" @click="changeShow('lx1_GDC', 3)">
+          <div>· 离线</div>
+          <div>{{sourceMap.gflxnum || '---'}}</div>
+        </div>
+      </div>
+      </Col>
+    </Row>
+    <div class="panel-box">
+      <div v-for="(pItem, pIndex) in sourceMap.fjmap" :key="pIndex">
+        <div>
+          <div class="panel-title">
+            <div class="panel-title-name">
+              <i class="fa fa-send"></i>
+              <span>{{sourceMap.fczbmap[sourceMap.fjmap[pIndex][0].wpId].name || '------'}}</span>
+              <div class="sub-title-item" v-for="(fcItem, fcIndex) in fcStateArray" :key="fcIndex">
+                <span class="sub-title">{{fcItem.text}}</span>
+                <span class="sub-count" :class="fcItem.color">{{sourceMap.fczbmap[sourceMap.fjmap[pIndex][0].wpId][fcItem.key]}}</span>
+              </div>
             </div>
+          </div>
+          <div class="panel-body">
+            <table>
+              <tbody>
+                <tr>
+                  <td v-for="(cItem, cIndex) of pItem" :key="cIndex" v-show="cItem.isShow">
+                    <div class="card" :class="cItem.color">
+                      {{cItem.wtnum}}
+                    </div>
+                  </td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
         </div>
+      </div>
     </div>
+  </div>
 </template>
 
 <script>
-    import Row from "@/components/coms/grid/row.vue";
-    import Col from "@/components/coms/grid/col.vue";
-    import SvgIcon from '@com/coms/icon/svg-icon.vue';
-    import util from '@/helper/util.js';
-    export default {
-        // 名称
-        name: "LightMatrix1",
-        // 使用组件
-        components: {
-            Row,
-            Col,
-            SvgIcon
-        },
-        // 数据
-        data() {
-            return {
-                panel1Data: {
-                    first: {
-                        icon: "svg-wind-site",
-                    },
-                    datas: [{
-                        color: "write",
-                        test: "接入风机",
-                        num: 256,
-                    },{
-                        color: "blue",
-                        test: "· 运行",
-                        num: 256,
-                    },{
-                        color: "green",
-                        test: "· 待机",
-                        num: 256,
-                    },{
-                        color: "purple",
-                        test: "· 限电",
-                        num: 256,
-                    },{
-                        color: "red",
-                        test: "· 故障",
-                        num: 256,
-                    },{
-                        color: "orange",
-                        test: "· 检修",
-                        num: 256,
-                    },{
-                        color: "write",
-                        test: "· 受累",
-                        num: 256,
-                    },{
-                        color: "gray",
-                        test: "· 离线",
-                        num: 256,
-                    }]
-                },
-                panel2Data: {
-                    first: {
-                        icon: "svg-photovoltaic",
-                    },
-                    datas: [{
-                        color: "write",
-                        test: "接入风机",
-                        num: 256,
-                    },{
-                        color: "blue",
-                        test: "· 运行",
-                        num: 256,
-                    },{
-                        color: "green",
-                        test: "· 待机",
-                        num: 256,
-                    },{
-                        color: "purple",
-                        test: "· 限电",
-                        num: 256,
-                    },{
-                        color: "red",
-                        test: "· 故障",
-                        num: 256,
-                    },{
-                        color: "orange",
-                        test: "· 检修",
-                        num: 256,
-                    },{
-                        color: "write",
-                        test: "· 受累",
-                        num: 256,
-                    },{
-                        color: "gray",
-                        test: "· 离线",
-                        num: 256,
-                    }]
-                },
-                tables: [{
-                    col: 42,
-                    subTitleDatas: [{
-                        text: "接入台数",
-                        num: 256,
-                        color: "write"
-                    }, {
-                        text: "待机台数",
-                        num: 256,
-                        color: "green"
-                    }, {
-                        text: "并网台数",
-                        num: 256,
-                        color: "blue"
-                    }, {
-                        text: "限电台数",
-                        num: 256,
-                        color: "purple"
-                    }, {
-                        text: "故障台数",
-                        num: 256,
-                        color: "red"
-                    }, {
-                        text: "检修台数",
-                        num: 256,
-                        color: "orange"
-                    }, {
-                        text: "受累台数",
-                        num: 256,
-                        color: "write"
-                    }, {
-                        text: "离线台数",
-                        num: 256,
-                        color: "gray"
-                    }, {
-                        text: "风速",
-                        num: 256,
-                        color: "gray"
-                    }, {
-                        text: "预测功率",
-                        num: 256,
-                        color: "gray"
-                    }, {
-                        text: "保证功率",
-                        num: 256,
-                        color: "gray"
-                    }, {
-                        text: "应发功率",
-                        num: 256,
-                        color: "gray"
-                    }, {
-                        text: "实际功率",
-                        num: 256,
-                        color: "gray"
-                    }, {
-                        text: "AGC指令",
-                        num: 256,
-                        color: "gray"
-                    }, {
-                        text: "出线功率",
-                        num: 256,
-                        color: "gray"
-                    }, ],
-                    datas: [{
-                        tag: "A01",
-                        color: "blue"
-                    }],
-                    groupDatas: []
-                }]
-            }
-        },
-        // 函数
-        methods: {
-            createGroupDatas: function(table) {
-                table.groupDatas = [];
-                let tempDatas = [];
-                table.datas.forEach((data, index) => {
-                    if (index % table.col == 0) {
-                        if (tempDatas.length > 0) {
-                            table.groupDatas.push(util.copy(tempDatas));
-                            tempDatas = [];
-                        }
-                    }
-                    tempDatas.push(util.copy(data));
-                })
-                if (tempDatas.length > 0) {
-                    table.groupDatas.push(util.copy(tempDatas));
-                    tempDatas = [];
-                }
-            }
-        },
-        // 生命周期钩子
-        beforeCreate() {
-            // 创建前
-        },
-        created() {
-            // 创建后
-            let tempData = [];
-            for (let i = 0; i < 108; i++) {
-                tempData.push(util.copy(this.tables[0].datas[0]));
-                if (i % 13 == 0) {
-                    tempData[i].color = "green";
-                }
-                if (i % 17 == 0) {
-                    tempData[i].color = "purple";
-                }
-                if (i % 23 == 0) {
-                    tempData[i].color = "orange";
-                }
-                if (i % 29 == 0) {
-                    tempData[i].color = "red";
-                }
-                if (i % 31 == 0) {
-                    tempData[i].color = "write";
-                }
-                if (i % 37 == 0) {
-                    tempData[i].color = "gray";
-                }
-            }
-            this.tables[0].datas = util.copy(tempData);
-            this.createGroupDatas(this.tables[0]);
-            for (let i = 0; i < 5; i++) {
-                this.tables.push(util.copy(this.tables[0]))
+import Row from "@/components/coms/grid/row.vue";
+import Col from "@/components/coms/grid/col.vue";
+import SvgIcon from '@com/coms/icon/svg-icon.vue';
+import util from '@/helper/util.js';
+
+import { datainit, webtest } from "@tools/websocket.js";
+import store from "@store/index.js";
+import { isNumber } from 'util';
+
+export default {
+  // 名称
+  name: "LightMatrix1",
+  // 使用组件
+  components: {
+    Row,
+    Col,
+    SvgIcon
+  },
+  // 数据
+  data () {
+    return {
+      loadingFlg: false, // 遮罩开关
+      websocketServe: null, // websocket 服务实例
+      sourceMap: {}, // 核心数据
+      fillCategory: null, // 过滤条件
+      fillFjzt: null, // 过滤条件
+      fcStateArray: [{
+        text: "接入台数",
+        color: "write",
+        key: "jrts"
+      }, {
+        text: "待机台数",
+        color: "green",
+        key: "djts"
+      }, {
+        text: "并网台数",
+        color: "blue",
+        key: "yxts"
+      }, {
+        text: "限电台数",
+        color: "purple",
+        key: "xdts"
+      }, {
+        text: "故障台数",
+        color: "red",
+        key: "gzts"
+      }, {
+        text: "检修台数",
+        color: "orange",
+        key: "whts"
+      }, {
+        text: "受累台数",
+        color: "write",
+        key: "slts"
+      }, {
+        text: "离线台数",
+        color: "gray",
+        key: "lxts"
+      }, {
+        text: "风速",
+        color: "gray",
+        key: "ssfs"
+      }, {
+        text: "预测功率",
+        color: "gray",
+        key: "ycgl"
+      }, {
+        text: "保证功率",
+        color: "gray",
+        key: "bzgl"
+      }, {
+        text: "应发功率",
+        color: "gray",
+        key: "yfgl"
+      }, {
+        text: "实际功率",
+        color: "gray",
+        key: "sjgl"
+      }, {
+        text: "AGC指令",
+        color: "gray",
+        key: "agcygsd"
+      }, {
+        text: "出线功率",
+        color: "gray",
+        key: "agccxyg"
+      }]
+    }
+  },
+  // 函数
+  methods: {
+    // 根据风机状态码返回对应 class
+    getColor (fjzt) {
+      switch (fjzt) {
+        case 0:
+          return 'green';
+          break;
+        case 1:
+          return 'blue';
+          break;
+        case 2:
+          return 'red';
+          break;
+        case 3:
+          return 'gray';
+          break;
+        case 4:
+          return 'orange';
+          break;
+        case 5:
+          return 'purple';
+          break;
+        case 6:
+          return 'write';
+          break;
+      }
+    },
+
+    // 切换显示种类
+    changeShow (category, fjzt, skipFill) {
+      if (!skipFill) {
+        if (this.fillCategory === category) {
+          this.fillCategory = null;
+          this.fillFjzt = null;
+        } else {
+          this.fillCategory = category;
+          this.fillFjzt = fjzt;
+        }
+      }
+
+      let fjmap = this.BASE.deepCopy(this.sourceMap.fjmap);
+
+      fjmap.forEach(pEle => {
+        pEle.forEach(cEle => {
+          cEle.isShow = true;
+          if (!this.fillCategory) {
+            cEle.isShow = true;
+          } else if (cEle.wpId.indexOf(category.split('_')[1]) !== -1) {
+            if (isNumber(fjzt)) {
+              cEle.fjzt === fjzt ? (cEle.isShow = true) : (cEle.isShow = false);
+            } else {
+              cEle.isShow = true
             }
-        },
-        beforeMount() {
-            // 渲染前
-        },
-        mounted() {
-            // 渲染后
-        },
-        beforeUpdate() {
-            // 数据更新前
-        },
-        updated() {
-            // 数据更新后
-        },
+          } else {
+            cEle.isShow = false;
+          }
+        });
+      });
+      this.sourceMap.fjmap = fjmap;
+    },
+  },
+
+  mounted () {
+    let that = this;
+    that.loadingFlg = true;
+    that.BASE.showLoading();
+    that.$nextTick(() => {
+      that.websocketServe = datainit("/topic/matrixpushtask");
+    });
+  },
+
+  destroyed () {
+    // 离开页面,销毁 websocket 实例
+    this.websocketServe && this.websocketServe.disconnect(() => {
+      this.API.requeestData({
+        subUrl: "admin/websocketdisconnect"
+      });
+    });
+  },
+
+  watch: {
+    // 监听 websocket 回调并包装数据用于展示
+    '$store.state.windturbineMap': function (res) {
+      this.loadingFlg && this.BASE.closeLoading();
+      this.loadingFlg = false;
+      if (res.data) {
+        let sourceMap = JSON.parse(res.data);
+        let fjmap = [];
+        for (let key in sourceMap) {
+          if (key !== 'fczbmap' && key !== 'fjmap') {
+            sourceMap[key] += '';
+          } else if (key === 'fjmap') {
+            sourceMap[key].forEach(pItem => {
+              pItem.forEach(cItem => {
+                cItem.color = this.getColor(cItem.fjzt);
+                cItem.isShow = true;
+              });
+            });
+          }
+        }
+        this.sourceMap = sourceMap;
+        if (this.fillCategory) {
+          this.changeShow(this.fillCategory, this.fillFjzt, true);
+        }
+      } else {
+        this.sourceMap = {};
+      }
+      console.log("sourceMap", this.sourceMap)
     }
+  }
+}
 </script>
 
 <style lang="less" scoped>
-    @panelHeight: 6.481vh;
-    @titleHeight: 3.704vh;
+@panelHeight: 6.481vh;
+@titleHeight: 3.704vh;
+
+.light-matrix {
+  width: calc(100% - 1.111vh);
+  height: calc(100vh - 7.222vh);
+  display: flex;
+  flex-direction: column;
+
+  .panel-2 {
+    .left-50-16 {
+      width: calc(50% - 0.741vh);
+    }
+  }
+
+  .panel {
+    width: 100%;
+    border: 1px solid @gray;
+    position: relative;
+    padding: 1.111vh 2.222vh;
+    background-color: fade(@gray, 20%);
+    display: flex;
+    height: 6.944vh;
+
+    .item {
+      cursor: pointer;
+    }
+
+    .dot {
+      width: 2px;
+      height: 2px;
+      border-radius: 50%;
+      background-color: @write;
+      position: absolute;
+
+      &.left {
+        left: 4px;
+      }
+
+      &.right {
+        right: 4px;
+      }
 
-    .light-matrix {
-        width: calc(100% - 1.111vh);
-        height: calc(100vh - 7.222vh);
+      &.top {
+        top: 4px;
+      }
+
+      &.bottom {
+        bottom: 4px;
+      }
+    }
+
+    .item {
+      flex: 1;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      flex-direction: column;
+      color: @write;
+      position: relative;
+
+      .loop {
+        position: absolute;
+        width: 4.444vh;
+        height: 4.444vh;
+        border-radius: 50%;
+        border: 1px solid @gray;
+        background-color: fade(@gray, 20);
+        left: calc(50% - 2.222vh);
+        top: calc(50% - 2.222vh);
+      }
+
+      &.write {
+        color: @write;
+      }
+
+      &.green {
+        color: @green;
+      }
+
+      &.blue {
+        color: @darkBlue;
+      }
+
+      &.purple {
+        color: @purple;
+      }
+
+      &.red {
+        color: @red;
+      }
+
+      &.orange {
+        color: @orange;
+      }
+
+      &.gray {
+        color: @gray;
+      }
+
+      div {
+        line-height: 2.222vh;
+
+        &:first-child {
+          font-size: @fontsize;
+        }
+        &:last-child {
+          font-size: @fontsize-l;
+          font-family: 'Bicubik';
+        }
+      }
+    }
+
+    .item2 {
+      flex: 1;
+      display: flex;
+      width: 20%;
+      flex-wrap: wrap;
+
+      .name {
+        color: @gray;
+        width: 50%;
+        text-align: center;
+      }
+
+      .num2 {
+        width: 50%;
+        color: @yellow;
+        text-align: left;
+      }
+
+      .num1 {
+        width: 50%;
+        color: @yellow;
+        text-align: center;
+        position: relative;
+
+        &::after {
+          content: '';
+          position: absolute;
+          width: 1.481vh;
+          height: 0.556vh;
+          background-color: @yellow;
+          left: 1.204vh;
+          top: 0.741vh;
+        }
+      }
+
+      .num3 {
+        width: 50%;
+        color: @yellow;
+        text-align: left;
+      }
+    }
+  }
+
+  .panel-box {
+    margin-top: 1.481vh;
+    flex-grow: 1;
+    overflow: auto;
+
+    .panel-title {
+      width: 100%;
+      height: @titleHeight;
+      line-height: @titleHeight;
+      background-color: fade(@gray, 40%);
+
+      .panel-title-name {
+        font-size: @fontsize-s;
+        color: @green;
         display: flex;
-        flex-direction: column;
+        align-items: center;
 
-        .panel-2 {
-            .left-50-16 {
-                width: calc(50% - 0.741vh);
-            }
+        i {
+          margin: 0 0.556vh 0 1.481vh;
         }
 
-        .panel {
-            width: 100%;
-            border: 1px solid @gray;
-            position: relative;
-            padding: 1.111vh 2.222vh;
-            background-color: fade(@gray, 20%);
-            display: flex;
-            height: 6.944vh;
-
-            .dot {
-                width: 2px;
-                height: 2px;
-                border-radius: 50%;
-                background-color: @write;
-                position: absolute;
-
-                &.left {
-                    left: 4px;
-                }
-
-                &.right {
-                    right: 4px;
-                }
-
-                &.top {
-                    top: 4px;
-                }
-
-                &.bottom {
-                    bottom: 4px;
-                }
+        .sub-title-item {
+          .sub-title {
+            color: @gray;
+            font-size: 1.019vh;
+            margin: 0 0.556vh 0 1.481vh;
+          }
+
+          .sub-count {
+            font-size: 1.296vh;
+            font-family: 'Bicubik';
+            font-weight: 500;
+
+            &.write {
+              color: @write;
             }
-            
-            .item {
-                flex: 1;
-                display: flex;
-                align-items: center;
-                justify-content: center;
-                flex-direction: column;
-                color: @write;
-                position: relative;
-                
-                .loop {
-                    position: absolute;
-                    width: 4.444vh;
-                    height: 4.444vh;
-                    border-radius: 50%;
-                    border: 1px solid @gray;
-                    background-color: fade(@gray, 20);
-                    left: calc(50% - 2.222vh);
-                    top: calc(50% - 2.222vh);
-                }
-                
-                &.write {
-                    color: @write;
-                }
-                
-                &.green {
-                    color: @green;
-                }
-                
-                &.blue {
-                    color: @darkBlue;
-                }
-                
-                &.purple {
-                    color: @purple;
-                }
-                
-                &.red {
-                    color: @red;
-                }
-                
-                &.orange {
-                    color: @orange;
-                }
-                
-                &.gray {
-                    color: @gray;
-                }
-                
-                div {
-                    line-height: 2.222vh;
-                    
-                    
-                    
-                    &:first-child {
-                        font-size: @fontsize;
-                    }
-                    &:last-child {
-                        font-size: @fontsize-l;
-                        font-family: "Bicubik";
-                    }
-                }
+
+            &.green {
+              color: @green;
             }
-            
-            .item2 {
-                flex: 1;
-                display: flex;
-                width: 20%;
-                flex-wrap: wrap;
-                
-                .name {
-                    color: @gray;
-                    width: 50%;
-                    text-align: center;
-                }
-                
-                .num2 {
-                    width: 50%;
-                    color: @yellow;
-                    text-align: left;
-                }
-                
-                .num1 {
-                    width: 50%;
-                    color: @yellow;
-                    text-align: center;
-                    position: relative;
-                    
-                    &::after {
-                        content: '';
-                        position: absolute;
-                        width: 1.481vh;
-                        height: 0.556vh;
-                        background-color: @yellow;
-                        left: 1.204vh;
-                        top: 0.741vh;
-                    }
-                }
-                
-                .num3 {
-                    width: 50%;
-                    color: @yellow;
-                    text-align: left;
-                }
+
+            &.blue {
+              color: @blue;
             }
 
-        }
+            &.purple {
+              color: @purple;
+            }
+
+            &.red {
+              color: @red;
+            }
 
-        .panel-box {
-            margin-top: 1.481vh;
-            flex-grow: 1;
-            overflow: auto;
-
-            .panel-title {
-                width: 100%;
-                height: @titleHeight;
-                line-height: @titleHeight;
-                background-color: fade(@gray, 40%);
-
-                .panel-title-name {
-                    font-size: @fontsize-s;
-                    color: @green;
-                    display: flex;
-                    align-items: center;
-
-                    i {
-                        margin: 0 0.556vh 0 1.481vh;
-                    }
-
-                    .sub-title-item {
-
-                        .sub-title {
-                            color: @gray;
-                            font-size: 1.019vh;
-                            margin: 0 0.556vh 0 1.481vh;
-                        }
-
-                        .sub-count {
-                            font-size: 1.296vh;
-                            font-family: "Bicubik";
-                            font-weight: 500;
-
-                            &.write {
-                                color: @write;
-                            }
-
-                            &.green {
-                                color: @green;
-                            }
-
-                            &.blue {
-                                color: @blue;
-                            }
-
-                            &.purple {
-                                color: @purple;
-                            }
-
-                            &.red {
-                                color: @red;
-                            }
-
-                            &.orange {
-                                color: @orange;
-                            }
-
-                            &.gray {
-                                color: @gray;
-                            }
-                        }
-                    }
-
-                }
+            &.orange {
+              color: @orange;
             }
 
-            .panel-body {
-                    height: calc(100% - 7.407vh);
-                    background-color: fade(@gray, 20%);
-                    padding: 0.741vh;
-                    overflow: auto;
-                    margin-bottom: 1.481vh;
-            
-                    table {
-                        width: 100%;
-            
-                        .card {
-                            border-radius: 4px;
-                            padding: 0.185vh 0;
-                            text-align: center;
-                            border: 1px solid;
-                            font-size: @fontsize-s;
-                            
-                            &.write {
-                                color: @black;
-                                border-color: @write;
-                                background-color: @write;
-                            }
-                            
-                            &.green {
-                                color: @green;
-                                border-color: @green;
-                            }
-                            
-                            &.blue {
-                                color: @darkBlue;
-                                border-color: @darkBlue;
-                            }
-                            
-                            &.purple {
-                                color: @purple;
-                                border-color: @purple;
-                            }
-                            
-                            &.red {
-                                color: @write;
-                                border-color: @red;
-                                background-color: @red;
-                            }
-                            
-                            &.orange {
-                                color: @orange;
-                                border-color: @orange;
-                            }
-                            
-                            &.gray {
-                                color: @write;
-                                border-color: @gray;
-                                background-color: @gray;
-                            }
-                        }
-                    }
-                }
-            
+            &.gray {
+              color: @gray;
+            }
+          }
         }
+      }
+    }
+
+    .panel-body {
+      height: calc(100% - 7.407vh);
+      background-color: fade(@gray, 20%);
+      padding: 0.741vh;
+      overflow: auto;
+      margin-bottom: 1.481vh;
+
+      table {
+        width: 100%;
+
+        .card {
+          border-radius: 4px;
+          padding: 0.185vh 0;
+          text-align: center;
+          border: 1px solid;
+          font-size: @fontsize-s;
+
+          &.write {
+            color: @black;
+            border-color: @write;
+            background-color: @write;
+          }
 
+          &.green {
+            color: @green;
+            border-color: @green;
+          }
 
+          &.blue {
+            color: @darkBlue;
+            border-color: @darkBlue;
+          }
+
+          &.purple {
+            color: @purple;
+            border-color: @purple;
+          }
+
+          &.red {
+            color: @write;
+            border-color: @red;
+            background-color: @red;
+          }
+
+          &.orange {
+            color: @orange;
+            border-color: @orange;
+          }
+
+          &.gray {
+            color: @write;
+            border-color: @gray;
+            background-color: @gray;
+          }
+        }
+      }
     }
+  }
+}
 </style>

+ 155 - 123
vue.config.js

@@ -2,134 +2,166 @@ const path = require("path");
 const resolve = (dir) => path.join(__dirname, dir);
 // const SVGSpriteLoaderPlugin = require("svg-sprite-loader/plugin");
 
-function extendDefaultPlugins(arr) {
-    let plug = [
-        'removeDoctype',
-        'removeXMLProcInst',
-        'removeComments',
-        'removeMetadata',
-        'removeEditorsNSData',
-        'cleanupAttrs',
-        'mergeStyles',
-        'inlineStyles',
-        'minifyStyles',
-        'cleanupIDs',
-        'removeUselessDefs',
-        'cleanupNumericValues',
-        'convertColors',
-        'removeUnknownsAndDefaults',
-        'removeNonInheritableGroupAttrs',
-        'removeUselessStrokeAndFill',
-        'removeViewBox',
-        'cleanupEnableBackground',
-        'removeHiddenElems',
-        'removeEmptyText',
-        'convertShapeToPath',
-        'convertEllipseToCircle',
-        'moveElemsAttrsToGroup',
-        'moveGroupAttrsToElems',
-        'collapseGroups',
-        'convertPathData',
-        'convertTransform',
-        'removeEmptyAttrs',
-        'removeEmptyContainers',
-        'mergePaths',
-        'removeUnusedNS',
-        'sortDefsChildren',
-        'removeTitle',
-        'removeDesc'
-    ];
-    return plug.concat(arr);
+function extendDefaultPlugins (arr) {
+  let plug = [
+    'removeDoctype',
+    'removeXMLProcInst',
+    'removeComments',
+    'removeMetadata',
+    'removeEditorsNSData',
+    'cleanupAttrs',
+    'mergeStyles',
+    'inlineStyles',
+    'minifyStyles',
+    'cleanupIDs',
+    'removeUselessDefs',
+    'cleanupNumericValues',
+    'convertColors',
+    'removeUnknownsAndDefaults',
+    'removeNonInheritableGroupAttrs',
+    'removeUselessStrokeAndFill',
+    'removeViewBox',
+    'cleanupEnableBackground',
+    'removeHiddenElems',
+    'removeEmptyText',
+    'convertShapeToPath',
+    'convertEllipseToCircle',
+    'moveElemsAttrsToGroup',
+    'moveGroupAttrsToElems',
+    'collapseGroups',
+    'convertPathData',
+    'convertTransform',
+    'removeEmptyAttrs',
+    'removeEmptyContainers',
+    'mergePaths',
+    'removeUnusedNS',
+    'sortDefsChildren',
+    'removeTitle',
+    'removeDesc'
+  ];
+  return plug.concat(arr);
 }
 
 // 添加less继承
-function addStyleResource(rule) {
-    rule.use('style-resource')
-        .loader('style-resources-loader')
-        .options({
-            patterns: [
-                resolve('src/assets/styles/common/common.less')
-            ]
-        })
+function addStyleResource (rule) {
+  rule.use('style-resource')
+    .loader('style-resources-loader')
+    .options({
+      patterns: [
+        resolve('src/assets/styles/common/common.less')
+      ]
+    })
 }
 
 
 module.exports = {
-    chainWebpack: (config) => {
-
-        // 路径别名
-        config.resolve.alias
-            .set("@", resolve("src"))
-            .set("@node", resolve("node_modules"))
-            .set("@com", resolve("src/components"))
-            .set("@assets", resolve("src/assets"));
-
-        // less 继承
-        const types = ['vue-modules', 'vue', 'normal-modules', 'normal'];
-        types.forEach(type => addStyleResource(config.module.rule('less').oneOf(type)));
-
-        // svg 雪碧图
-        config.module // 排除其他svg-loader
-            .rule('svg')
-            .exclude.add(resolve('src/assets/icon/svg'))
-            .end()
-            .exclude.add(resolve('src/assets/icon/svg_fill'))
-            .end();
-
-        // svg雪碧图
-        const svgRule = config.module.rule('icons');
-        svgRule.test(/\.svg$/)
-            .include.add(resolve('src/assets/icon/svg'))
-            .end()
-            .use('svg-sprite-loader')
-            .loader('svg-sprite-loader')
-            .options({
-                symbolId: 'svg-[name]',
-                // extract: true,
-                // publicPath: "img/",
-                // spriteFilename: "svg-sprite-[hash:8].svg",
-            });
-
-        // config
-        //     .plugin("svgsprite")
-        //     .use(SVGSpriteLoaderPlugin, [{ 
-        //       plainSprite: true
-        //     }]);
-
-        // svgo 去除svg中无用元素
-        svgRule.use('svgo-loader').loader('svgo-loader').options({
-            plugins: extendDefaultPlugins([{
-                name: "removeAttrs",
-                params: {
-                    attrs: 'fill',
-                }
-            }])
-        });
-
-        // svg雪碧图 不去除fill属性
-        // const svgRuleFill = config.module.rule('icons_fill');
-        // svgRuleFill.test(/\.svg$/)
-        //     .include.add(resolve('src/assets/icon/svg_fill'))
-        //     .end()
-        //     .use('svg-sprite-loader')
-        //     .loader('svg-sprite-loader')
-        //     .options({
-        //         symbolId: 'fill-[name]',
-        //         // extract: true,
-        //         // publicPath: "img/",
-        //         // spriteFilename: "svg-sprite-[hash:8].svg",
-        //     });
-
-        // // config
-        // //     .plugin("svgsprite")
-        // //     .use(SVGSpriteLoaderPlugin, [{ 
-        // //       plainSprite: true
-        // //     }]);
-
-        // // svgo 去除svg中无用元素
-        // svgRuleFill.use('svgo-loader').loader('svgo-loader').options({
-        //     plugins: extendDefaultPlugins([])
-        // });
-
-    },
+
+  publicPath: "./", // 默认'/',部署应用包时的基本 URL
+  indexPath: 'index.html', // 相对于打包路径index.html的路径
+  outputDir: 'dist', // 'dist', 生产环境构建文件的目录
+  assetsDir: 'static', // 相对于outputDir的静态资源(js、css、img、fonts)目录
+  lintOnSave: false, // 是否在开发环境下通过 eslint-loader 在每次保存时 lint 代码
+  runtimeCompiler: true, // 是否使用包含运行时编译器的 Vue 构建版本
+
+  chainWebpack: (config) => {
+
+    config.resolve.symlinks(true); // 修复热更新失效
+
+    // 路径别名
+    config.resolve.alias
+      .set("@", resolve("src"))
+      .set("@node", resolve("node_modules"))
+      .set("@com", resolve("src/components"))
+      .set("@assets", resolve("src/assets"))
+      .set("@api", resolve("src/api"))
+      .set("@store", resolve("src/store"))
+      .set("@modeConfig", resolve("public/static/config"))
+      .set("@tools", resolve("src/tools"));
+
+    // less 继承
+    const types = ['vue-modules', 'vue', 'normal-modules', 'normal'];
+    types.forEach(type => addStyleResource(config.module.rule('less').oneOf(type)));
+
+    // svg 雪碧图
+    config.module // 排除其他svg-loader
+      .rule('svg')
+      .exclude.add(resolve('src/assets/icon/svg'))
+      .end()
+      .exclude.add(resolve('src/assets/icon/svg_fill'))
+      .end();
+
+    // svg雪碧图
+    const svgRule = config.module.rule('icons');
+    svgRule.test(/\.svg$/)
+      .include.add(resolve('src/assets/icon/svg'))
+      .end()
+      .use('svg-sprite-loader')
+      .loader('svg-sprite-loader')
+      .options({
+        symbolId: 'svg-[name]',
+        // extract: true,
+        // publicPath: "img/",
+        // spriteFilename: "svg-sprite-[hash:8].svg",
+      });
+
+    // config
+    //     .plugin("svgsprite")
+    //     .use(SVGSpriteLoaderPlugin, [{ 
+    //       plainSprite: true
+    //     }]);
+
+    // svgo 去除svg中无用元素
+    svgRule.use('svgo-loader').loader('svgo-loader').options({
+      plugins: extendDefaultPlugins([{
+        name: "removeAttrs",
+        params: {
+          attrs: 'fill',
+        }
+      }])
+    });
+
+    // svg雪碧图 不去除fill属性
+    // const svgRuleFill = config.module.rule('icons_fill');
+    // svgRuleFill.test(/\.svg$/)
+    //     .include.add(resolve('src/assets/icon/svg_fill'))
+    //     .end()
+    //     .use('svg-sprite-loader')
+    //     .loader('svg-sprite-loader')
+    //     .options({
+    //         symbolId: 'fill-[name]',
+    //         // extract: true,
+    //         // publicPath: "img/",
+    //         // spriteFilename: "svg-sprite-[hash:8].svg",
+    //     });
+
+    // // config
+    // //     .plugin("svgsprite")
+    // //     .use(SVGSpriteLoaderPlugin, [{ 
+    // //       plainSprite: true
+    // //     }]);
+
+    // // svgo 去除svg中无用元素
+    // svgRuleFill.use('svgo-loader').loader('svgo-loader').options({
+    //     plugins: extendDefaultPlugins([])
+    // });
+
+  },
+
+  // devServer: {
+  //   //代理配置
+  //   proxy: {
+  //     '/lightmatrix': {
+  //       target: 'https://h5.caibeike.com.cn/', // 请求地址
+
+  //       changeOrigin: true, // 在vue-cli3中,默认changeOrigin的值是true,意味着服务器host设置成target,这与vue-cli2不一致,vue-cli2这个默认值是false
+  //       // changeOrigin的值是true,target是host, request URL是http://baidu.com
+  //       // 如果设置changeOrigin: false,host就是浏览器发送过来的host,也就是localhost:8082。
+
+  //       pathRewrite: {  // 路径重写,eg:把api接口替换为''
+  //         '^/h5.caibeike.com.cn/': 'localhost:8888/'
+  //       }
+  //     }
+  //   },
+  //   open: false, // 是否打开浏览器
+  // }
 }