Bläddra i källkod

网络结构图

“yueshang” 1 år sedan
förälder
incheckning
49b6877613

+ 62 - 1
package-lock.json

@@ -19,6 +19,7 @@
         "jsplumb": "^2.15.6",
         "less": "^4.2.0",
         "less-loader": "^11.1.3",
+        "moment": "^2.29.4",
         "uuid": "^9.0.1",
         "vue": "^3.2.13",
         "vue-draggable-next": "^2.2.1",
@@ -26,7 +27,8 @@
       },
       "devDependencies": {
         "@babel/core": "^7.12.16",
-        "@vue/cli-service": "~5.0.0"
+        "@vue/cli-service": "~5.0.0",
+        "sass-loader": "^13.3.2"
       }
     },
     "node_modules/@achrinza/node-ipc": {
@@ -5380,6 +5382,14 @@
       "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==",
       "dev": true
     },
+    "node_modules/moment": {
+      "version": "2.29.4",
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
+      "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
+      "engines": {
+        "node": "*"
+      }
+    },
     "node_modules/mrmime": {
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/mrmime/-/mrmime-1.0.1.tgz",
@@ -6977,6 +6987,43 @@
       "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz",
       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
     },
+    "node_modules/sass-loader": {
+      "version": "13.3.2",
+      "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.2.tgz",
+      "integrity": "sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg==",
+      "dev": true,
+      "dependencies": {
+        "neo-async": "^2.6.2"
+      },
+      "engines": {
+        "node": ">= 14.15.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependencies": {
+        "fibers": ">= 3.1.0",
+        "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0",
+        "sass": "^1.3.0",
+        "sass-embedded": "*",
+        "webpack": "^5.0.0"
+      },
+      "peerDependenciesMeta": {
+        "fibers": {
+          "optional": true
+        },
+        "node-sass": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "sass-embedded": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/sax": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz",
@@ -12917,6 +12964,11 @@
       "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==",
       "dev": true
     },
+    "moment": {
+      "version": "2.29.4",
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
+      "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
+    },
     "mrmime": {
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/mrmime/-/mrmime-1.0.1.tgz",
@@ -14119,6 +14171,15 @@
       "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz",
       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
     },
+    "sass-loader": {
+      "version": "13.3.2",
+      "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.2.tgz",
+      "integrity": "sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg==",
+      "dev": true,
+      "requires": {
+        "neo-async": "^2.6.2"
+      }
+    },
     "sax": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz",

+ 2 - 1
package.json

@@ -27,7 +27,8 @@
   },
   "devDependencies": {
     "@babel/core": "^7.12.16",
-    "@vue/cli-service": "~5.0.0"
+    "@vue/cli-service": "~5.0.0",
+    "sass-loader": "^13.3.2"
   },
   "eslintConfig": {
     "root": true,

+ 24 - 0
src/api/iedNetwork/index.js

@@ -0,0 +1,24 @@
+import request from '@/utils/request'
+//获取scd列表
+export function nodeList(query) {
+  return request({
+    url: '/screen/scd/node/list',
+    method: 'get',
+    params: query
+  })
+}
+  //获取SCD中配置的所有设备网络地址
+export function iedRelation(query) {
+  return request({
+    url: '/screen/scd/ied/relation',
+    method: 'get',
+    params: query
+  })
+ }  //获取SCD中配置的所有设备网络地址
+ export function iedNetaddr(query) {
+   return request({
+     url: '/screen/scd/ied/netaddr',
+     method: 'get',
+     params: query
+   })
+}

BIN
src/assets/image/instruct/navtop.png


BIN
src/assets/image/instruct/navtop_active.png


BIN
src/assets/image/instruct/network_default.png


BIN
src/assets/image/instruct/network_hub.png


BIN
src/assets/image/instruct/network_slices.png


+ 1 - 0
src/main.js

@@ -5,6 +5,7 @@ import 'element-plus/dist/index.css'
 import * as ElementPlusIconsVue from '@element-plus/icons-vue'
 import App from './App.vue'
 import zhCn from 'element-plus/es/locale/lang/zh-cn';//引入中文
+import '@/styles/index.scss'
 const app = createApp(App)
 for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
     app.component(key, component)

+ 1 - 1
src/pages/login/LoginNow.vue

@@ -79,7 +79,7 @@ export default {
                         message: '登陆成功!',
                         type: "success"
                     })
-                    // windowEx.Size(1920, 1040)
+                    windowEx.Size(1920, 1040)
                     // windowEx.Position('center')
                 } else {
                     ElMessage({

+ 175 - 154
src/pages/mission/components/HaveMis.vue

@@ -1,218 +1,239 @@
 <template>
-    <div>
-        <div class="bigBox">
-            <!-- 点击开始检测盒子 -->
-            <div class="startBox">
-                <p class="nowIn">正在检测的任务名称</p>
-                <p class="createDate">创建日期:2000-00-00</p>
-                <img src="../../../assets/image/start_btn.png" alt="">
-                <p class="nowModel">当前模型:<em class="nowEm">110kv线路保护<img src="../../../assets/icon/pencil.png" alt=""></em>
-                </p>
+  <div>
+    <div class="bigBox">
+      <!-- 点击开始检测盒子 -->
+      <div class="startBox">
+        <p class="nowIn">正在检测的任务名称</p>
+        <p class="createDate">创建日期:2000-00-00</p>
+        <img src="../../../assets/image/start_btn.png" alt="" />
+        <p class="nowModel">
+          当前模型:<em class="nowEm"
+            >110kv线路保护<img src="../../../assets/icon/pencil.png" alt=""
+          /></em>
+        </p>
+      </div>
+      <!-- 待检测任务 -->
+      <div class="noReportBox">
+        <div>
+          <p class="norep">待检测任务</p>
+        </div>
+        <div>
+          <!-- <template> -->
+          <div
+            class="intBox"
+            :style="{ 'background-image': `url(${imgBack})` }"
+          >
+            <div class="intBoxOne">
+              <p class="intOne">
+                <span>检测任务名称</span>
+                <span>详情→</span>
+              </p>
+              <p>
+                <img src="../../../assets/icon/white_flash.png" alt="" />
+                <span class="commonSpan">某个变电站</span>
+              </p>
+              <p>
+                <img src="../../../assets/icon//white_clock.png" alt="" />
+                <span class="commonSpan">2000-00-00</span>
+              </p>
+            </div>
+            <!-- 点击检测 -->
+            <div class="setNow">
+              <span class="setnowspan" @click="startNow">立即检测</span>
             </div>
-            <!-- 待检测任务 -->
-            <div class="noReportBox">
-                <div>
-                    <p class="norep">待检测任务</p>
-                </div>
-                <div>
-                    <!-- <template> -->
-                    <div class="intBox" :style="{ 'background-image': `url(${imgBack})` }">
-                        <div class="intBoxOne">
-                            <p class="intOne">
-                                <span>检测任务名称</span>
-                                <span>详情→</span>
-                            </p>
-                            <p>
-                                <img src="../../../assets/icon/white_flash.png" alt="">
-                                <span class="commonSpan">某个变电站</span>
-                            </p>
-                            <p>
-                                <img src="../../../assets/icon//white_clock.png" alt="">
-                                <span class="commonSpan">2000-00-00</span>
-                            </p>
-                        </div>
-                        <!-- 点击检测 -->
-                        <div class="setNow">
-                            <span class="setnowspan" @click="startNow">立即检测</span>
-                        </div>
-                    </div>
-                    <!-- </template> -->
-                </div>
+          </div>
+          <!-- </template> -->
+        </div>
+      </div>
+      <!-- 已完成 -->
+      <div class="noReportBox">
+        <div>
+          <p class="norep">最近检测任务-已完成</p>
+        </div>
+        <div>
+          <!-- <template> -->
+          <div
+            class="intBox"
+            :style="{ 'background-image': `url(${imgBack})` }"
+          >
+            <div class="intBoxOne">
+              <p class="intOne">
+                <span>检测任务名称</span>
+                <span>详情→</span>
+              </p>
+              <p>
+                <img src="../../../assets/icon/white_flash.png" alt="" />
+                <span class="commonSpan">某个变电站</span>
+              </p>
+              <p>
+                <img src="../../../assets/icon//white_clock.png" alt="" />
+                <span class="commonSpan">2000-00-00</span>
+              </p>
             </div>
-            <!-- 已完成 -->
-            <div class="noReportBox">
-                <div>
-                    <p class="norep">最近检测任务-已完成</p>
-                </div>
-                <div>
-                    <!-- <template> -->
-                    <div class="intBox" :style="{ 'background-image': `url(${imgBack})` }">
-                        <div class="intBoxOne">
-                            <p class="intOne">
-                                <span>检测任务名称</span>
-                                <span>详情→</span>
-                            </p>
-                            <p>
-                                <img src="../../../assets/icon/white_flash.png" alt="">
-                                <span class="commonSpan">某个变电站</span>
-                            </p>
-                            <p>
-                                <img src="../../../assets/icon//white_clock.png" alt="">
-                                <span class="commonSpan">2000-00-00</span>
-                            </p>
-                        </div>
-                        <!-- 点击检测 -->
-                        <div class="setNow">
-                            <span class="setnowspan" @click="scdLink">scd可视化</span>
-                            <span class="setnowspan">|</span>
-                            <span class="setnowspan">检测结果</span>
-                        </div>
-                    </div>
-                    <!-- </template> -->
-                </div>
+            <!-- 点击检测 -->
+            <div class="setNow">
+              <span class="setnowspan" @click="goNetStructPicture"
+                >scd可视化</span
+              >
+              <span class="setnowspan">|</span>
+              <span class="setnowspan">检测结果</span>
             </div>
+          </div>
+          <!-- </template> -->
         </div>
+      </div>
     </div>
+  </div>
 </template>
 
 <script>
-import { ref, onMounted, computed, toRefs } from 'vue';
-import { useRouter } from 'vue-router';
-import imgs from '../jscom/img'
+import { ref, onMounted, computed, toRefs } from "vue";
+import { useRouter } from "vue-router";
+import imgs from "../jscom/img";
 export default {
-    setup(props, { emit }) {
-        let { startNow } = toRefs(props)
-        let imgBack = ref(require('@/assets/image/card_blue.png'))
-        let router = useRouter()
-        let sizeNum = ref(1)
-        function scdLink() {
-            router.push("/home/scdMap")
-        }
-        function getStart() {
-            sizeNum.value = 1
-            emit("hmBack", sizeNum.value)
-        }
-        return {
-            imgBack,
-            scdLink,
-            startNow: getStart,
-            sizeNum,
-        }
+  setup(props, { emit }) {
+    let { startNow } = toRefs(props);
+    let imgBack = ref(require("@/assets/image/card_blue.png"));
+    let router = useRouter();
+    let sizeNum = ref(1);
+    function scdLink() {
+      router.push("/home/scdMap");
     }
-}
+    function getStart() {
+      sizeNum.value = 1;
+      emit("hmBack", sizeNum.value);
+    }
+    function goNetStructPicture() {
+      router.push({
+        path: "/home/netStructPicture",
+        query: {
+          id: 4000002,
+          name: 'UnitTest_检测任务',
+        },
+      });
+    }
+    return {
+      imgBack,
+      scdLink,
+      startNow: getStart,
+      sizeNum,
+      goNetStructPicture,
+    };
+  },
+};
 </script>
 
 <style scoped>
 p {
-    margin: 0;
-    padding: 0;
+  margin: 0;
+  padding: 0;
 }
 
 .bigBox {
-    width: 99%;
-    height: 100%;
-    /* border: 1px solid saddlebrown; */
+  width: 99%;
+  height: 100%;
+  /* border: 1px solid saddlebrown; */
 }
 
 .startBox {
-    width: 320px;
-    height: 335px;
-    margin: 0 auto;
-    /* border: 1px solid black; */
-    text-align: center;
-    line-height: 25px;
+  width: 320px;
+  height: 335px;
+  margin: 0 auto;
+  /* border: 1px solid black; */
+  text-align: center;
+  line-height: 25px;
 }
 
 .nowIn {
-    /* width: 180px;
+  /* width: 180px;
     height: 28px; */
-    font-size: 20px;
-    font-family: Source Han Sans CN-Bold, Source Han Sans CN;
-    font-weight: bold;
-    color: #1A2447;
-    /* line-height: 28px; */
+  font-size: 20px;
+  font-family: Source Han Sans CN-Bold, Source Han Sans CN;
+  font-weight: bold;
+  color: #1a2447;
+  /* line-height: 28px; */
 }
 
 .createDate {
-    /* width: 168px;
+  /* width: 168px;
     height: 22px; */
-    font-size: 16px;
-    font-family: Source Han Sans CN-Regular, Source Han Sans CN;
-    font-weight: 400;
-    color: #7484AB;
-    /* line-height: 22px; */
+  font-size: 16px;
+  font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+  font-weight: 400;
+  color: #7484ab;
+  /* line-height: 22px; */
 }
 
 .nowModel {
-    font-size: 18px;
-    font-family: Source Han Sans CN-Regular, Source Han Sans CN;
-    font-weight: 400;
-    color: #1A2447;
+  font-size: 18px;
+  font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+  font-weight: 400;
+  color: #1a2447;
 }
 
 .nowEm {
-    font-style: normal;
-    font-size: 18px;
-    font-family: Source Han Sans CN-Medium, Source Han Sans CN;
-    font-weight: 500;
-    color: #255CE7;
-    line-height: 24px;
-    border-bottom: 1px solid #255CE7;
+  font-style: normal;
+  font-size: 18px;
+  font-family: Source Han Sans CN-Medium, Source Han Sans CN;
+  font-weight: 500;
+  color: #255ce7;
+  line-height: 24px;
+  border-bottom: 1px solid #255ce7;
 }
 
 .noReportBox {
-    width: 99%;
-    height: 100%;
-    margin-left: 8px;
-    /* border: 1px solid salmon; */
+  width: 99%;
+  height: 100%;
+  margin-left: 8px;
+  /* border: 1px solid salmon; */
 }
 
 .norep {
-    font-size: 16px;
-    font-family: Source Han Sans CN-Regular, Source Han Sans CN;
-    font-weight: 400;
-    color: #7484AB;
+  font-size: 16px;
+  font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+  font-weight: 400;
+  color: #7484ab;
 }
 
 .intBox {
-    width: 269px;
-    height: 116px;
-    line-height: 20px;
-    background-repeat: no-repeat;
-    background-size: 100% 100%;
-    /* border: 1px solid brown; */
-    /* background-image: url(../../../assets/image/card_blue.png); */
+  width: 269px;
+  height: 116px;
+  line-height: 20px;
+  background-repeat: no-repeat;
+  background-size: 100% 100%;
+  /* border: 1px solid brown; */
+  /* background-image: url(../../../assets/image/card_blue.png); */
 }
 
 .intBoxOne {
-    padding-top: 5px;
+  padding-top: 5px;
 }
 
 .intOne span:nth-child(2) {
-    margin-left: 100px;
-    font-size: 14px;
-    color: white;
+  margin-left: 100px;
+  font-size: 14px;
+  color: white;
 }
 
 .intOne span:nth-child(1) {
-    margin-left: 5px;
-    font-size: 18px;
-    color: white;
+  margin-left: 5px;
+  font-size: 18px;
+  color: white;
 }
 
 .commonSpan {
-    font-size: 14px;
-    color: white;
+  font-size: 14px;
+  color: white;
 }
 
 .setNow {
-    text-align: center;
-    margin-top: 10px;
+  text-align: center;
+  margin-top: 10px;
 }
 
 .setnowspan {
-    color: white;
-    font-size: 17px;
-    cursor: pointer;
+  color: white;
+  font-size: 17px;
+  cursor: pointer;
 }
 </style>

+ 694 - 0
src/pages/netStructPicture/components/netWork.vue

@@ -0,0 +1,694 @@
+<template>
+  <div class="container-bg">
+    <el-container class="main-layout">
+      <el-container class="right-plate">
+        <el-main class="main-cont">
+          <div class="network-wrap">
+            <!-- 父网络列表   上方的大类图标及小竖线 -->
+            <section class="layout">
+              <div class="mainNetwork">
+                <div
+                  class="networkItem"
+                  v-for="(item, index) in nodeInfoData"
+                  :key="index"
+                  :class="{ active: current == index }"
+                  @click="() => onChangeMain(index, item)"
+                >
+                  <!-- 图片及图片上的名字 -->
+                  <div class="topCont">
+                    <div class="title">{{ item.attr_desc }}</div>
+                    <span class="subtitle">{{ item.attr_name }}</span>
+                  </div>
+                  <!-- 小竖线 -->
+                  <div class="lineWrap" v-if="current == index">
+                    <div
+                      class="line"
+                      v-for="(item, index) in lineList"
+                      :style="{
+                        background: item.bgcolor,
+                        left: 45 + index * 13 + '%',
+                        height: 17 * index + 35 + 'px',
+                      }"
+                      :key="index"
+                    ></div>
+                  </div>
+                </div>
+              </div>
+            </section>
+            <!-- 子网络列表 -->
+            <section class="layout">
+              <div class="subNetwork">
+                <div
+                  class="subNetworkItem"
+                  v-for="(item, index) in handleAllAp"
+                  :key="index"
+                >
+                  <span
+                    class="subNetworkLine"
+                    v-show="item.show"
+                    :style="item.inlineStyle"
+                  ></span>
+                  <div class="subNetworkMask" v-show="!item.show"></div>
+                  <div class="subNetworkInfo">
+                    <div class="subNetworkImg">
+                      <img :src="tupian" alt="" />
+                    </div>
+                    <div class="subNetworkName">{{ item.attr_ied_name }}</div>
+                    <div
+                      class="subNetworkID"
+                      v-for="(value, key) in item"
+                      :key="key"
+                    >
+                      <span v-if="key.startsWith('node_value')">{{
+                        value
+                      }}</span>
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </section>
+
+            <!-- 线条 -->
+            <div class="networkLine">
+              <div
+                class="mainLine"
+                v-for="(item, index) in lineList"
+                :key="index"
+              >
+                <span
+                  class="lineTag"
+                  :style="{ background: item.bgcolor, color: item.txtcolor }"
+                  @click="() => onChangeline(item.name)"
+                  >{{ item.name }}</span
+                >
+                <p
+                  class="line"
+                  :style="{ background: item.bgcolor }"
+                  @click="() => onChangeline(item.name)"
+                ></p>
+              </div>
+            </div>
+          </div>
+        </el-main>
+      </el-container>
+    </el-container>
+  </div>
+</template>
+    
+  
+  <script setup>
+import { onMounted, reactive, ref } from "vue";
+import { nodeList, iedNetaddr } from "@/api/iedNetwork";
+import { useRoute } from "vue-router";
+const route = useRoute();
+const flog = ref(false);
+const current = ref(0);
+const currentCat = ref("");
+const arr = ref([
+  {
+    attr_desc: "110KV过程层SMV子网",
+    attr_name: "SMV",
+    attr_type: "SMV",
+    node_id: 84001387,
+    node_name: "SubNetwork",
+    node_value: "",
+    parent_node_id: 84000135,
+  },
+  {
+    attr_desc: "MMS网",
+    attr_name: "MMS",
+    attr_type: "8-MMS",
+    node_id: 84001387,
+    node_name: "SubNetwork",
+    node_value: "",
+    parent_node_id: 84000135,
+  },
+  {
+    attr_desc: "110KV过程层GOOSE子网",
+    attr_name: "GOOSE",
+    attr_type: "IECGOOSE",
+    node_id: 84003131,
+    node_name: "SubNetwork",
+    node_value: "",
+    parent_node_id: 84000135,
+  },
+]); //父网络数据
+const nodeInfoData = ref(null);
+const arr2 = ref([
+  {
+    attr_ap_name: "S1",
+    attr_desc: "",
+    attr_ied_name: "IL1101",
+    node_id: 84003204,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84003131,
+  },
+  {
+    attr_ap_name: "S1",
+    attr_desc: "",
+    attr_ied_name: "IL1301",
+    node_id: 8400204,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84003131,
+  },
+  {
+    attr_ap_name: "S1",
+    attr_desc: "",
+    attr_ied_name: "IL4101",
+    node_id: 84002204,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84003131,
+  },
+  {
+    attr_ap_name: "S1",
+    attr_desc: "",
+    attr_ied_name: "PL1131",
+    node_id: 84003264,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84003131,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "IL11031",
+    node_id: 84007214,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84003131,
+  },
+  {
+    attr_ap_name: "S1",
+    attr_desc: "",
+    attr_ied_name: "IL11011",
+    node_id: 84003304,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84003131,
+  },
+  {
+    attr_ap_name: "S1",
+    attr_desc: "",
+    attr_ied_name: "IL13101",
+    node_id: 84003205,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84003131,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84003131,
+  },
+  {
+    attr_ap_name: "K1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "K1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "K1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "K1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "G1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+  {
+    attr_ap_name: "K1",
+    attr_desc: "",
+    attr_ied_name: "CM13101",
+    node_id: 84003295,
+    node_name: "ConnectedAP",
+    node_value: "",
+    parent_node_id: 84001387,
+  },
+]);
+const lineList = ref([]);
+const listCat = ref([]);
+const colorList2 = ref([
+  {
+    S1: "#3BE078",
+    S2: "#3AAFF0",
+    S3: "#FF8531",
+    G1: "#3259E0",
+    G2: "#38FFFF",
+    G3: "#3FA3FF",
+    G4: "#7368F1",
+    G5: "#84D7FF",
+    M1: "#FB3E3E",
+    M2: "#FF039A",
+    M3: "#FF1BE8",
+    M4: "#FF929D",
+    M5: "#FF9AF5",
+  },
+]);
+const colorList = ["#3BE078", "#3AAFF0", "#4B6DE3", "#aa00ff"];
+const tupian = require("@/assets/image/instruct/network_slices.png");
+let nodeTreeInfo = null;
+let loading = false;
+//获取网络图的顶部列表
+const getNetWork = async () => {
+  loading = false;
+  const infoRes = await nodeList({
+    scd_id: 52000015,
+    pagesize: 10000,
+    name: "SubNetwork",
+  });
+  nodeInfoData.value = infoRes.data;
+  loading = true;
+};
+//获取SCD中配置的所有设备网络地址ConnectedAP
+const allNetaddrData = ref({});
+const allApData = ref({});
+const initLoad = async () => {
+  allApData.value = {};
+  getNetWork();
+  const allAP = await nodeList({
+    scd_id: 52000015,
+    pagesize: 10000,
+    name: "ConnectedAP",
+  });
+  if (allAP == null || allAP.data == null) {
+    //
+    return;
+  }
+  let tmp = {};
+  for (let i = 0; i < allAP.data.length; i++) {
+    let item = allAP.data[i];
+    const key = item.parent_node_id + "." + item.attr_ap_name;
+    if (allApData.value[key] == null) {
+      allApData.value[key] = {
+        node_type: "ap",
+        name: key,
+        list: [item],
+      };
+    } else {
+      allApData.value[key].list.push(item);
+    }
+  }
+  //   allNetaddrData.value = allAP.data;
+  const allNetaddr2 = await iedNetaddr({ scd_id: 44000013 });
+  //   processAllNetData(allNetaddr.data);
+  //   allNetaddrData.value = allNetaddr.data;
+  getlist();
+};
+const processAllNetData = (arr) => {
+  const attrIedNamesMap = new Map();
+  for (let i = 0; i < arr.length; i++) {
+    const item = arr[i];
+    const attrIedName = item.attr_ied_name;
+    // 如果attr_ied_name已经存在于attrIedNamesMap中,则将node_value赋值给已存在的对象的新属性
+    if (attrIedNamesMap.has(attrIedName)) {
+      const existingItem = attrIedNamesMap.get(attrIedName);
+      const newNodeValueKey = `node_value${existingItem.count + 2}`;
+      // 设置新属性值
+      existingItem.item[newNodeValueKey] = item.node_value;
+      // 递增count,表示已处理的相同attr_ied_name的个数
+      existingItem.count++;
+      // 删除赋值的对象
+      arr.splice(i, 1);
+      // 因为删除了一个元素,所以需要更新索引
+      i--;
+    } else {
+      // 如果attr_ied_name不存在于attrIedNamesMap中,则将当前item加入attrIedNamesMap
+      attrIedNamesMap.set(attrIedName, {
+        item,
+        count: 0,
+      });
+    }
+  }
+};
+const handleAllAp = ref([]); //处理后后的单个network的子数据
+const clickAllAp = ref(null);
+const lineNum = ref([]);
+// const arrname = ref([]);
+const onChangeMain = (index, clickItem) => {
+  handleAllAp.value = [];
+  //
+  Object.keys(allApData.value).forEach((item) => {
+    if (item.includes(clickItem.node_id)) {
+      handleAllAp.value = [...handleAllAp.value, ...allApData.value[item].list];
+    }
+  });
+ //  如果有重复的attr_ied_name删除
+  lineNum.value = Array.from(
+    new Set(handleAllAp.value.map((item) => item.attr_ap_name))
+  );
+
+  //去重
+  handleAllAp.value =  handleAllAp.value.filter((item, index, self) => {
+    return (
+      index ===
+      self.findIndex((obj) => obj.attr_ied_name === item.attr_ied_name && obj.attr_ap_name === item.attr_ap_name || obj.attr_ied_name === item.attr_ied_name)
+    );
+  });
+
+  clickAllAp.value = clickItem;
+
+  current.value = index;
+  flog.value = true;
+  currentCat.value = "";
+  listCat.value = [];
+  lineNum.value =[]
+  lineList.value = [];
+  onChangeline("");
+  getlist();
+};
+const getClickList = (dataId) => {};
+const getlist = () => {
+  if (!clickAllAp.value) {
+    handleAllAp.value = [];
+    //匹配的所有数据的key值,进行筛选对应的数据
+    Object.keys(allApData.value).forEach((item) => {
+      if (item.includes(nodeInfoData.value[0].node_id)) {
+        //默认展示第一个
+        handleAllAp.value = [
+          ...handleAllAp.value,
+          ...allApData.value[item].list,
+        ];
+      }
+    });
+  }
+  handleAllAp.value =  handleAllAp.value.filter((item, index, self) => {
+    return (
+      index ===
+      self.findIndex((obj) => obj.attr_ied_name === item.attr_ied_name && obj.attr_ap_name === item.attr_ap_name || obj.attr_ied_name === item.attr_ied_name)
+    );
+  });
+  var index = 0;
+  handleAllAp.value.forEach((item, subindex) => {
+    if (!listCat.value.includes(item.attr_ap_name)) {
+      listCat.value.push(item.attr_ap_name);
+      //   let colorObj = "";
+      //   colorList2.value.find((color) => {
+      //     colorObj = color[item.attr_ap_name];
+      //   });
+      lineList.value.push({
+        name: item.attr_ap_name,
+        bgcolor: colorList[index],
+        txtcolor: "#fff",
+        position: 70 + index * 10,
+      });
+      index++;
+    }
+  });
+  setinlineStyle(handleAllAp.value, listCat.value);
+};
+onMounted(() => {
+  initLoad();
+});
+
+const setinlineStyle = (data, dataCat) => {
+  let adjustment = 0; // 初始化调整值为0
+  const length = lineList.value.length; // 获取数组长度
+  // 根据数组长度动态计算调整值
+  if (length === 1) {
+    adjustment = 32; // 数组长度为1,则加32
+  } else if (length === 2) {
+    adjustment = 16; // 数组长度为2,则加16
+  } else if (length > 2) {
+    // 数组长度大于2,开始递减
+    adjustment = (length - 3) * 16; // 每增加一个元素,减16px
+    if (length > 3) adjustment = 0; // 当长度大于3时,不再递减,保持0
+  }
+  //data全部数组
+  // dataCat:{0: 'S1', 1: 'G1', 2: 'K1'}
+  let newData = [];
+  // 进行分组处理 都为浅拷贝 修改的源数据
+  for (var i = 0; i < data.length; i += 9) {
+    newData.push(data.slice(i, i + 9));
+  }
+
+  // 添加行类样式属性
+  for (let i = 0; i < data.length; i++) {
+    data[i]["inlineStyle"] = {};
+    for (let j = 0; j < dataCat.length; j++) {
+      if (data[i].attr_ap_name == dataCat[j]) {
+        data[i]["inlineStyle"]["borderColor"] = colorList[j];
+        data[i]["inlineStyle"]["left"] = j * 5 + "px";
+        data[i]["inlineStyle"]["zIndex"] = j;
+        data[i]["show"] = true;
+      }
+    }
+  }
+  // 根据行数计算高度
+  newData.forEach((item, index) => {
+    for (let i = 0; i < item.length; i++) {
+      let num = listCat.value.indexOf(item[i].attr_ap_name) + 1;
+      item[i]["inlineStyle"]["height"] =
+        120 * index +
+        54 +
+        (listCat.value.length - num) * 17 +
+        adjustment +
+        "px";
+    }
+  });
+};
+//线条的点击事件
+const onChangeline = (val) => {
+  if (flog.value && val == currentCat.value) {
+    handleAllAp.value.forEach((item) => (item.show = true));
+    currentCat.value = "";
+    flog.value = false;
+  } else {
+    handleAllAp.value.forEach((item) => {
+      item.show = item.attr_ap_name == val ? true : false;
+    });
+    flog.value = true;
+    currentCat.value = val;
+  }
+};
+</script>
+  
+  <style scoped lang="scss">
+@import "~@/styles/home.scss";
+@import "~@/styles/struct.scss";
+</style>

+ 86 - 0
src/pages/netStructPicture/index.vue

@@ -0,0 +1,86 @@
+<template>
+  <div>
+    <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
+      <div class="nav">
+        <div v-for="(item, index) in navtopData" :key="index" :class="{'nav-item-active':activeNav==index}" @click="clickNav(index)" class="nav-item">
+          {{ item.name }}
+        </div>
+      </div>
+      <el-tab-pane label="网络结构图" name="first">
+        <net-work></net-work>
+      </el-tab-pane>
+      <el-tab-pane label="SCD可视化" name="second">Config</el-tab-pane>
+    </el-tabs>
+  </div>
+</template>
+  
+
+<script setup>
+import { ref } from "vue";
+import netWork from "./components/netWork";
+import { useRoute } from 'vue-router';
+const activeName = ref("first");//默认展示网络结构图
+const navtopData = ref([
+  { name: "CID一致性校核" },
+  { name: "SCD文件一致性校核" },
+  { name: "SCL文件校核" },
+  { name: "CRC校核" },
+  { name: "虚端子关系图" },
+]);
+const activeNav = ref(null);
+const clickNav = (navIndex) => {  //点击导航栏事件
+  activeNav.value = navIndex; 
+}
+</script>
+
+<style scoped lang="scss">
+$height:40px;
+@mixin mid-center{
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+:deep(.el-tabs__item) {
+  margin: 16px 0 0 32px;
+  font-size: 18px;
+}
+:deep(.el-tabs__item:last-child) {
+  margin-left: 0;
+}
+:deep(.el-tabs__nav-wrap::after) {
+  --el-border-color-light: none;
+}
+:deep(.el-tabs__item.is-active),
+:deep(.el-tabs__active-bar) {
+  color: #255ce7;
+}
+:deep(.el-tabs__active-bar) {
+  background-color: #255ce7;
+}
+//设置导航栏样式
+ .nav {
+  @include mid-center;
+  .nav-item {
+    width: 144px;
+    height: $height;
+    @include mid-center;
+    margin-right: 8px;
+    cursor: pointer;
+    background: #fff url("~@/assets/image/instruct/navtop.png") no-repeat center;
+    background-size: 144px $height;
+  }
+  .nav-item-active{
+    background: #fff url("~@/assets/image/instruct/navtop_active.png") no-repeat center;
+    background-size: 144px $height;
+  }
+}
+//最外层的滚动条不要
+:deep(.el-main) {
+  overflow: hidden;
+}
+//ied的高度
+:deep(.network-wrap) {
+height: 70vh;
+overflow: auto;
+}
+</style>

+ 7 - 0
src/router/index.js

@@ -69,6 +69,13 @@ const routes = [
                 meta:{
                     name:"system"
                 }
+            },
+            {
+                path:"/home/netStructPicture",
+                component:()=>import("@/pages/netStructPicture"),
+                meta:{
+                    name:"netStructPicture"
+                }
             }
         ]
     }

+ 30 - 0
src/styles/home.scss

@@ -0,0 +1,30 @@
+// .container-bg{
+//     background: #fff;
+//     width: 100%;
+//     position: relative;
+// }
+// .main-layout.el-container{
+//     width: 96%;
+//     height: 90vh;
+//     margin-top: 20px;
+// }
+// .right-plate{
+//     // width: 77%;
+//     margin-left: 2%;
+//     .main-top{
+//         height: 110px;
+//         background-color: #fff;
+//     }
+//     .main-cont{
+//         margin-top: 15px;
+//         background-color: #fff;
+//     }
+// }
+// .left-plate{
+//     background: #FFF;
+
+//     margin-left: 20px;
+// }
+// ::v-deep .left-plate.el-aside{
+//     width: 18% !important;
+// }

+ 20 - 0
src/styles/index.scss

@@ -0,0 +1,20 @@
+/* 滚动条样式 */
+::-webkit-scrollbar {
+    width: 12px;
+    height: 12px;
+  }
+  ::-webkit-scrollbar-thumb {
+    border-radius: 6px;
+    border: 2px solid transparent;
+    background-color: #d9d9d9;
+    background-clip: padding-box;
+  }
+  ::-webkit-scrollbar-thumb:hover {
+    background-color: #bfbfbf;
+  }
+  ::-webkit-scrollbar-track {
+    background: #f0f2f5;
+  }
+  ::-webkit-scrollbar-corner {
+    background: transparent;
+  }

+ 182 - 0
src/styles/struct.scss

@@ -0,0 +1,182 @@
+
+.network-wrap .layout{
+	padding: 0 50px;
+}
+/* 父网络 */
+.network-wrap{
+	position: relative;
+	width: 100%;
+	height: 50vh;
+}
+.mainNetwork{
+	height: 120px;
+	display: flex;
+	justify-content: space-evenly;
+	// align-items: center;
+    align-items: flex-start;
+}
+.networkItem{
+	position: relative;
+	width: 130px;
+	height: 112px;
+	text-align: center;
+	font-weight: 400;
+	cursor: pointer;
+}
+
+.networkItem .topMask{
+	position: absolute;
+	top: 0;
+	left: 0;
+	height: 100%;
+	width: 100%;
+	background: rgb(255 255 255 / 50%);
+}
+//点击时的大类背景色
+.networkItem.active .topMask{
+    // background: linear-gradient(to top,#4f50b95c,#fff9f900);
+	// border-bottom: 1px solid #00c;
+}
+
+.networkItem .topCont{
+	height: 100%;
+	width: 100%;
+	display: flex;
+	align-items: stretch;
+	flex-direction: column;
+	justify-content: center;
+	background: #fff url('~@/assets/image/instruct/network_default.png') no-repeat center;
+	background-size:  126px 112px;
+    color: #7484AB;
+}
+.networkItem.active .topCont{
+    background: #fff url('~@/assets/image/instruct/network_hub.png') no-repeat center;
+    background-size: 126px 112px;
+}
+.networkItem .topCont .subtitle{
+	display: block;
+    font-size: 16px;
+	color: #7484AB;
+}
+
+.networkItem .title{
+	position: absolute;
+	top: 0;
+	left: 50%;
+	transform: translateX(-50%);
+	white-space: nowrap;
+	z-index: 1;
+    font-size: 18px;
+    color: #7484AB;
+}
+.networkItem.active .title{
+	opacity: 1;
+    color: #255CE7;
+}
+
+.networkItem.active .topCont,.networkItem.active .topDesc {
+	color: #255CE7;
+    font-size: 18px;
+}
+.networkItem.active .topCont .subtitle{
+    color: #FFCB11;
+    font-size: 16px;
+}
+.networkItem .line{
+	width: 3px;
+	height: 20px;
+	position: absolute;
+	top: 100%;
+	transform: translateY(1px);
+	z-index: 2;
+}
+.networkItem .line.green{
+	background-color: green;
+}
+
+/* 子网格 */
+.subNetwork{
+	margin-top: 62px;
+	display: flex;
+	justify-content: flex-start;
+	align-items: center;
+	flex-wrap: wrap;
+}
+.subNetworkItem{
+	position: relative;
+	font-size: 12px;
+	text-align: center;
+	flex-basis: 11%;
+	height: 120px;
+	/* margin-bottom: 20px; */
+}
+.subNetworkItem .subNetworkLine{
+	width: 20px;
+	display: block;
+	position: absolute;
+	bottom: 65px;
+	border-width: 3px;
+	border-style: solid;
+	border-top: none;
+	border-right: none;
+}
+.subNetworkItem .subNetworkMask{
+	width: 100%;
+	height: 100%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	background: rgb(255 255 255 / 50%);
+	z-index: 1;
+}
+.subNetworkItem .subNetworkImg{
+	// width: 50px;
+	position: relative;
+	left: 45%;
+	transform: translateX(-50%);
+}
+.subNetworkInfo{
+	transform: scale(.9);
+}
+.subNetworkItem .subNetworkName{
+	font-weight: bold;
+}
+.subNetworkItem .subNetworkID{
+	color: #999;
+}
+.subNetworkItem .subNetworkImg img{
+	width: 80px;
+    height: 80px;
+    // width: 100%;
+}
+
+/* 线条 */
+.networkLine{
+	position: absolute;
+	top: 139px;
+	left: 0;
+	width: 100%;
+	height: auto;
+}
+.networkLine .mainLine{
+	display: flex;
+	justify-content: flex-start;
+	align-items: center;
+	flex-wrap: nowrap;
+	cursor: pointer;
+}
+.mainLine .lineTag{
+	width: 25px;
+	text-align: center;
+	font-size: 13px;
+	transform: scale(0.9);
+	font-weight: bold;
+}
+.mainLine .line{
+	margin: 0;
+	width: 100%;
+	height: 3px;
+	margin-left: -5px;
+}
+
+

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 245 - 259
yarn.lock


Vissa filer visades inte eftersom för många filer har ändrats