Browse Source

Merge branch 'liyangzheng' of http://94.191.59.107:3000/houwenfeng/scd_tools_ui

liling 1 năm trước cách đây
mục cha
commit
f677a5a088

+ 1 - 0
src/api/cid/cid.js

@@ -29,6 +29,7 @@ function fileUpload(data) {
         headers: {
             'content-Type': 'multipart/form-data',
         },
+        timeout:500000,
     })
 }
 function saveMap(data){

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

@@ -106,6 +106,31 @@ export function gooseReceivefcdalist(query) {
     params: query
   })
 }
+//虚端子关系
+//中间列表数据
+export function getMiddleinputs(query) {
+  return request({
+    url: 'screen/scd/ied/inputs',
+    method: 'get',
+    params: query
+  })
+}
+//定值条目
+export function getDingzhis(query) {
+  return request({
+    url: 'screen/scd/ied/dingzhi',
+    method: 'get',
+    params: query
+  })
+}
+//信息点表
+export function getPointtable(query) {
+  return request({
+    url: 'screen/scd/ied/pointtable',
+    method: 'get',
+    params: query
+  })
+}
 
 
 

+ 8 - 0
src/api/task.js

@@ -38,10 +38,18 @@ function delTask(data){
         data
     })
 }
+function lookStep(data){
+    return request({
+        url:`/task/check/step_info`,
+        method:"get",
+        params:data,
+    })
+}
 export default {
     getTask,
     tackStart,
     createTask,
     stopTask,
     delTask,
+    lookStep,
 }

BIN
src/assets/icon/clock_darkBlue.png


BIN
src/assets/icon/flash_darkBlue.png


+ 15 - 10
src/pages/mission/components/CreateMis.vue

@@ -193,12 +193,16 @@ export default {
         function searchAllFlash() {
             flashPower.getAllArea({}).then(res => {
                 flashPower.getAllFlashPower({ pid: res.data[0].pid }).then(res => {
-                    flashList.value = res.data.map(item => {
-                        return {
-                            label: item.area_name,
-                            value: item.id
-                        }
-                    })
+                    if (res.data == null) {
+                        return
+                    } else {
+                        flashList.value = res.data.map(item => {
+                            return {
+                                label: item.area_name,
+                                value: item.id
+                            }
+                        })
+                    }
                 })
             })
             report.getReport({}).then(res => {
@@ -316,9 +320,9 @@ export default {
             })
         }
         function tagClose(row, num) {
-           mx.value.splice(mx.value.indexOf(row), 1)
-           iedName.value = mx.value.map(item => item.ied_name).join(', ');
-           console.log(iedName,'iedname');
+            mx.value.splice(mx.value.indexOf(row), 1)
+            iedName.value = mx.value.map(item => item.ied_name).join(', ');
+            console.log(iedName, 'iedname');
         }
         function checkTime() {
             iedModal.value = true
@@ -487,7 +491,8 @@ em {
     text-align: center;
     line-height: 30px;
 }
-.mx-1{
+
+.mx-1 {
     margin-right: 10px;
     border: 1px solid #5779D7;
 }

+ 111 - 38
src/pages/mission/components/HaveMis.vue

@@ -3,11 +3,12 @@
     <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="nowIn">{{ nowRunList.name ? nowRunList.name : "暂无待检测任务" }}</p>
+        <p class="createDate">创建日期:{{ nowRunList.ct ? nowRunList.ct : "暂无时间" }}</p>
+        <img src="../../../assets/image/start_btn.png" alt="" style="cursor: pointer;" @click="startNow(nowRunList)" />
         <p class="nowModel">
-          当前模型:<em class="nowEm">110kv线路保护<img src="../../../assets/icon/pencil.png" alt="" /></em>
+          当前模型:<em class="nowEm">{{ nowRunList.voltage_name ? nowRunList.voltage_name + '线路保护' : "暂无数据" }}<img
+              v-if="nowRunList.voltage_name" src="../../../assets/icon/pencil.png" alt="" /></em>
         </p>
       </div>
       <!-- 待检测任务 -->
@@ -16,28 +17,46 @@
           <p class="norep">待检测任务</p>
         </div>
         <div style="display: flex;justify-content: flex-start;align-items: center;overflow-x: auto;">
-          <!-- <template> -->
-          <div class="intBox" v-for="(item,index) in misList">
-            <div class="intBoxOne"> 
+          <div class="intBox" v-if="nowRunList.name" :style="setImg(nowRunList)">
+            <div class="intBoxOne">
+              <p class="intOne">
+                <span style="font-size: 18px;color: #1A2447;">{{ nowRunList.name }}</span>
+                <span style="font-size: 12px;" @click="deldel(nowRunList)">删除</span>
+              </p>
+              <p>
+                <img style="width: 15px;height: 15px;" src="../../../assets/icon/flash_darkBlue.png" alt="" />
+                <span style="font-size: 12px;color:#7484AB" class="commonSpan">{{ nowRunList.station_name }}</span>
+              </p>
+              <p>
+                <img style="width: 15px;height: 15px;" src="../../../assets/icon/clock_darkBlue.png" alt="" />
+                <span style="font-size: 12px;color:#7484AB" class="commonSpan">{{ nowRunList.ct }}</span>
+              </p>
+            </div>
+            <!-- 点击检测 -->
+            <div class="setNow">
+              <span style="font-size: 16px;color:green" class="setnowspan" @click="startNow(nowRunList)">正在检测中<em v-loading="emLoading"></em></span>
+            </div>
+          </div>
+          <div class="intBox" v-for="(item, index) in misList" :style="setImg(item, index)">
+            <div class="intBoxOne">
               <p class="intOne">
                 <span style="font-size: 18px;color: #1A2447;">{{ item.name }}</span>
-                <span style="font-size: 12px;" @click="deldel(item,index)">删除</span>
+                <span style="font-size: 12px;" @click="deldel(item, index)">删除</span>
               </p>
               <p>
-                <!-- <img src="../../../assets/icon/white_flash.png" alt="" /> -->
+                <img style="width: 15px;height: 15px;" src="../../../assets/icon/flash_darkBlue.png" alt="" />
                 <span style="font-size: 12px;color:#7484AB" class="commonSpan">{{ item.station_name }}</span>
               </p>
               <p>
-                <!-- <img src="../../../assets/icon//white_clock.png" alt="" /> -->
+                <img style="width: 15px;height: 15px;" src="../../../assets/icon/clock_darkBlue.png" alt="" />
                 <span style="font-size: 12px;color:#7484AB" class="commonSpan">{{ item.ut }}</span>
               </p>
             </div>
             <!-- 点击检测 -->
             <div class="setNow">
-              <span style="font-size: 16px;color:blue" class="setnowspan" @click="startNow(item,index)">立即检测</span>
+              <span style="font-size: 16px;color:blue" class="setnowspan" @click="startNow(item, index)">立即检测</span>
             </div>
           </div>
-          <!-- </template> -->
         </div>
       </div>
       <!-- 已完成 -->
@@ -45,21 +64,20 @@
         <div>
           <p class="norep">最近检测任务-已完成</p>
         </div>
-        <div>
-          <!-- <template> -->
-          <div class="intBox" :style="{ 'background-image': `url(${imgBack})` }">
+        <div style="display: flex;justify-content: flex-start;align-items: center;overflow-x: auto;">
+          <div class="intBox" v-for="(item, index) in passList">
             <div class="intBoxOne">
               <p class="intOne">
-                <span>检测任务名称</span>
+                <span>{{ item.name }}</span>
                 <span>详情→</span>
               </p>
               <p>
                 <img src="../../../assets/icon/white_flash.png" alt="" />
-                <span class="commonSpan">某个变电站</span>
+                <span style="font-size: 12px;color:#7484AB" class="commonSpan">{{ item.station_name }}</span>
               </p>
               <p>
                 <img src="../../../assets/icon//white_clock.png" alt="" />
-                <span class="commonSpan">2000-00-00</span>
+                <span style="font-size: 12px;color:#7484AB" class="commonSpan">{{ item.ct }}</span>
               </p>
             </div>
             <!-- 点击检测 -->
@@ -69,7 +87,6 @@
               <span class="setnowspan">检测结果</span>
             </div>
           </div>
-          <!-- </template> -->
         </div>
       </div>
     </div>
@@ -81,18 +98,29 @@ import { ref, onMounted, computed, toRefs } from "vue";
 import { useRouter } from "vue-router";
 import task from "@/api/task"
 import imgs from "../jscom/img";
+import { ElLoading, ElMessage } from "element-plus";
 export default {
   setup(props, { emit }) {
     let imgBack = ref(require("@/assets/image/card_blue.png"));
     let router = useRouter();
     let sizeNum = ref(1);
-    let misList = ref([])//任务列表
+    let misList = ref([])//待检测任务列表
+    let nowRunList = ref({})//正在检测任务列表
+    let passList = ref([])//已完成检测任务列表
+    let emLoading = ref(true)
     function scdLink() {
       router.push("/home/scdMap");
     }
-    function startNow(row,num) {
-      sizeNum.value = 1;
-      emit("hmBack", sizeNum.value,row);
+    function startNow(row, num) {
+      if (row.name == null || row.name == '' || row.name == undefined) {
+        ElMessage({
+          message:"暂无检测任务",
+          type:"info"
+        })
+      } else {
+        sizeNum.value = 1;
+        emit("hmBack", sizeNum.value, row);
+      }
     }
     function goNetStructPicture() {
       router.push({
@@ -103,29 +131,68 @@ export default {
         },
       });
     }
-    function getList(){
+    function getList() {
+      const loading = ElLoading.service({
+        lock: true,
+        text: '正在查询数据',
+        background: 'rgba(0, 0, 0, 0.7)',
+      })
       // 0为待检测
-      task.getTask({pageno:1,pagesize:10,state:0}).then(res=>{
-        misList.value = res.data
-        emit("haveBack",misList.value)
+      task.getTask({ pageno: 1, pagesize: 10, state: 0 }).then(res => {
+        if (res.data == null) {
+          loading.close()
+          misList.value = []
+          return
+        } else {
+          const sortedList = res.data.sort((a, b) => {
+            // 将 state 为 0 的对象排在前面
+            if (a.state === 1 && b.state !== 1) {
+              return -1; // a排在b前面
+            } else if (a.state !== 1 && b.state === 1) {
+              return 1; // b排在a前面
+            } else {
+              return 0; // 不需要交换位置
+            }
+          });
+          misList.value = sortedList;
+          emit("haveBack", misList.value);
+          loading.close()
+        }
       })
       // 2为完成检测
-      task.getTask({pageno:1,pagesize:10,state:2}).then(res=>{
-        // misList.value = res.data
-        console.log(res,'完成');
+      task.getTask({ pageno: 1, pagesize: 10, state: 2 }).then(res => {
+        if (res.data == null) {
+          passList.value = []
+          return
+        } else {
+          passList.value = res.data
+        }
       })
       // 1为正在检测
-      task.getTask({pageno:1,pagesize:10,state:1}).then(res=>{
-        // misList.value = res.data
-        console.log(res,'正在');
+      task.getTask({ pageno: 1, pagesize: 10, state: 1 }).then(res => {
+        if (res.data == null) {
+          nowRunList.value = {}
+          return
+        } else {
+          nowRunList.value = res.data[0]
+          console.log(res.data, 'res.data');
+          console.log(nowRunList.value, 'now');
+        }
       })
     }
-    function deldel(row){
-      task.delTask({id:row.id}).then(res=>{
+    function deldel(row) {
+      task.delTask({ id: row.id }).then(res => {
         getList()
       })
     }
-    onMounted(()=>{
+    function setImg(row, num) {
+      if (row.state == "1") {
+        return { 'background-image': `url(${imgBack})` }
+      } else {
+        return {}
+      }
+    }
+    onMounted(() => {
       getList()
     })
     return {
@@ -135,8 +202,12 @@ export default {
       sizeNum,
       goNetStructPicture,
       getList,
-      misList,
+      misList,//待检测任务列表
       deldel,
+      nowRunList,//正在检测任务列表
+      setImg,
+      passList,//已完成列表
+      emLoading
     };
   },
 };
@@ -232,9 +303,11 @@ p {
 .intBoxOne {
   padding-top: 5px;
 }
-.intOne{
+
+.intOne {
   position: relative;
 }
+
 .intOne span:nth-child(2) {
   /* margin-left: 70px; */
   font-size: 14px;

+ 35 - 16
src/pages/mission/components/StartMission.vue

@@ -13,7 +13,7 @@
             <div class="stepAndEnd">
                 <!-- 步骤条 -->
                 <div class="stepBox">
-                    <StepMethod></StepMethod>
+                    <StepMethod :stepList="stepList"></StepMethod>
                 </div>
                 <!-- 结果 -->
                 <div class="endBox">
@@ -25,42 +25,60 @@
 </template>
 
 <script>
-import { ref, onMounted, toRefs,watch } from 'vue';
+import { ref, onMounted, toRefs, watch } from 'vue';
 import StepMethod from './StepMethod.vue';
 import task from '@/api/task';
 import { ElMessage } from 'element-plus';
 export default {
-    props:{
-        startMis:{
-            type:Object,
-            required:true
+    props: {
+        startMis: {
+            type: Object,
+            required: true
         }
     },
     setup(props, { emit }) {
         let arrow = ref(0)
         let loadingMis = ref({})
-        watch(()=>props.startMis,(newVal)=>{
+        let stepList = ref([])
+        watch(() => props.startMis, (newVal) => {
             loadingMis.value = newVal
-            console.log(loadingMis.value,'watch');
+            console.log(loadingMis.value, 'watch');
         })
         function misDown() {
-            task.stopTask({id:loadingMis.value.id}).then(res=>{
-                if(res.code == 0){
+            task.stopTask({ id: loadingMis.value.id }).then(res => {
+                if (res.code == 0) {
                     ElMessage({
-                        message:"取消成功",
-                        type:"success"
+                        message: "取消成功",
+                        type: "success"
                     })
                 }
             })
             emit("smBack", arrow.value)
         }
-        function picReload(){
+        function picReload() {
             loadingMis.value = props.startMis
-            task.tackStart({id:loadingMis.value.id}).then(res=>{
-                console.log(res,'开始');
+            console.log(loadingMis.value, 'loading');
+            task.tackStart({ id: loadingMis.value.id }).then(res => {
+                console.log(res, '开始');
+                let countTime = setInterval(() => {
+                    task.lookStep({ id: loadingMis.value.id - 0 }).then(res => {
+                        if (res.data) {
+                            stepList.value = res.data.map((item, index) => {
+                                return {
+                                    title: item.step_name,
+                                    content: item.step_name
+                                }
+                            })
+                            // clearInterval(countTime)
+                        }
+                    })
+                }, 2000)
+                setTimeout(() => {
+                    clearInterval(countTime)
+                }, 10000)
             })
         }
-        onMounted(()=>{
+        onMounted(() => {
             picReload()
         })
         return {
@@ -68,6 +86,7 @@ export default {
             misDown,
             loadingMis,//传递过来的任务名称
             picReload,//初始化组件
+            stepList,//步骤表
         }
     },
     components: {

+ 17 - 3
src/pages/mission/components/StepMethod.vue

@@ -2,7 +2,7 @@
     <div>
         <div class="bigBox">
             <el-steps :active="activeStep" space="10px" finish-status="success" direction="vertical">
-                <el-step v-for="(step, index) in steps" :key="index" :title="step.title">
+                <el-step v-for="(step, index) in steps" :key="index" :title="step.title" :icon="Loading">
                     {{ step.content }}
                 </el-step>
             </el-steps>
@@ -12,9 +12,16 @@
 </template>
   
 <script>
-import { ref,onMounted } from "vue";
+import { ref,onMounted,toRefs,watch } from "vue";
+import { Edit, Picture, Upload,Loading } from '@element-plus/icons-vue'
 export default {
-    setup() {
+    props:{
+        stepList:{
+            type:Array,
+            required:true,
+        }
+    },
+    setup(props,{emit}) {
         let activeStep = ref(0); // 当前激活的步骤
         let steps = ref([       // 步骤的数据
             { title: "done", content: "这是步骤 1 的内容" },
@@ -25,12 +32,19 @@ export default {
             { title: "步骤 6", content: "这是步骤 3 的内容" },
             // 添加更多步骤
         ])
+        watch(()=>props.stepList,(newVal)=>{
+            steps.value = newVal
+        })
+        function reload(){
+            steps.value = props.stepList
+        }
         function nextStep() {
             if (activeStep.value < steps.value.length) {
                 activeStep.value++;
             }
         };
         onMounted(()=>{
+            reload()
             setInterval(() => {
                 nextStep()
             }, 1000);

+ 9 - 1
src/pages/netStructPicture/components/dialogIndex.vue

@@ -76,6 +76,8 @@
             :iedRelation="iedRelation"
             @result="result"
             :isPhoto="isPhoto"
+            :tabName="tabName"
+            ref="getChild"
           ></component>
         </div>
       </div>
@@ -185,11 +187,13 @@ const cancelClick = () => {
 const activeNav = ref(0);
 const activeNavName = shallowRef(relationShip);
 const inoutName = ref("");
+const tabName = ref('relationShip');
 const clickNav = (navIndex, name) => {
   //点击导航栏事件
   inoutName.value = name;
   console.log("name", name);
   activeNavName.value = name;
+  tabName.value = name;
   activeNav.value = navIndex;
 };
 const activeLeft = ref(null);
@@ -209,6 +213,10 @@ const clickInoutNav = (item, index) => {
   isPhoto.value = item.code;
   inoutItemNavIndex.value = index;
 };
+const getChild = ref(null);
+watch(()=>tabName.value,(newValue)=>{
+  getChild.value.removeLine;
+})
 </script>
   <style scoped lang="scss">
 @mixin mid-center {
@@ -307,6 +315,6 @@ $height: 40px;
 .inout-right-item{
   margin-top: 27px;
   margin-left: 16px;
-  overflow-y: hidden !important;
+  // overflow-y: hidden !important;
 }
 </style>

+ 100 - 4
src/pages/netStructPicture/components/fixedEntry.vue

@@ -1,15 +1,111 @@
-<!-- 定值条目 -->
+<!-- 基础信息 -->
 <template>
-  <div>5</div>
+  <div>
+    <div class="cont-table">
+      <el-table
+        :data="dingzhiData"
+        stripe
+        style="width: 100%"
+        :cell-style="{ color: '#000',cursor:'pointer' }"
+        @row-click="svSendRowClick3"
+        :highlight-current-row="true"
+        ref="myTable5"
+      >
+        <el-table-column type="index" label="序号" width="80" />
+        <el-table-column prop="accesspoint_name" label="访问点" width="180" />
+        <el-table-column label="数据集名称">
+          <template #default="scope">
+            {{ `${scope.row.ld_desc}(${scope.row.ld_name})` }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="dataset_desc" label="数据集描述" />
+      </el-table>
+      <div class="title">
+        定值条目列表详情(共<span v-if="gooseList">{{ gooseList.length }}</span
+        >条)
+      </div>
+      <el-table
+        :data="dingzhiDataChild"
+        style="width: 100%"
+        stripe
+        :cell-style="{ color: '#000' }"
+      >
+        <el-table-column type="index" label="序号" width="80" />
+        <el-table-column prop="doi_desc" label="条目描述" width="180" />
+        <el-table-column label="最大值" prop="da_maxval"/>
+        <el-table-column label="最小值" prop="da_minval"/>
+        <el-table-column prop="da_units" label="单位" />
+        <el-table-column prop="da_stepsize" label="步长" />
+        <el-table-column prop="da_datatype" label="数据类型" />
+        <el-table-column prop="short_addr" label="内部地址" />
+      </el-table>
+    </div>
+  </div>
 </template>
 <script setup>
-import { onMounted, watch, ref,nextTick,defineEmits } from "vue";
+import { onMounted, watch, ref, nextTick, defineEmits, inject } from "vue";
+import {
+  getDingzhis
+} from "@/api/iedNetwork";
 const props = defineProps({
-  checkDialogData: {
+  checkData: {
     type: Object,
     default: () => {},
   },
+  isPhoto: {
+    type: String,
+    default: "",
+  },
+  svInfo: {
+    type: Array,
+    default: [],
+  },
+});
+const scdIdValue = inject("scdId");
+const dingzhiData = ref(null);
+const dingzhiDataChild = ref(null);
+const myTable5 = ref(null);
+const getDingzhisList = async () => {
+  const dingRes= await getDingzhis({
+    scd_id: scdIdValue,
+    ied_name: props.checkData.ied_name,
+  })
+  if(dingRes.data.length>0){
+    dingzhiData.value = dingRes.data;
+    dingzhiDataChild.value = dingRes.data[0].list
+  }
+
+  myTable5.value.setCurrentRow(dingzhiData.value[0]);
+}
+const svSendRowClick3 = (row, column) => {
+  dingzhiDataChild.value = row.list
+}
+watch(
+  () => props.checkData,
+  (newValue) => {
+    dingzhiData.value = [];
+    dingzhiDataChild.value = [];
+    if (newValue != null) {
+      getDingzhisList()
+    }
+  }
+);
+onMounted(() => {
+  getDingzhisList()
 });
 </script>
 <style scoped lang="scss">
+.cont-table {
+  height: 65vh;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+}
+:deep(.el-table) {
+  flex-basis: 45%;
+}
+.title {
+  margin: 16px;
+  color: #51637f;
+}
 </style>

+ 106 - 3
src/pages/netStructPicture/components/infoTable.vue

@@ -1,15 +1,118 @@
 <!-- 信息点表 -->
+<!-- 基础信息 -->
 <template>
-  <div>6</div>
+  <div>
+    <div class="cont-table">
+      <el-table
+        :data="dingzhiData"
+        stripe
+        style="width: 100%"
+        :cell-style="{ color: '#000', cursor: 'pointer' }"
+        @row-click="svSendRowClick3"
+        :highlight-current-row="true"
+        ref="myTable5"
+      >
+        <el-table-column type="index" label="序号" width="80" />
+        <el-table-column prop="accesspoint_name" label="访问点" width="180" />
+        <el-table-column label="逻辑设备(lnst)">
+          <template #default="scope">
+            {{ `${scope.row.ld_desc}(${scope.row.ld_inst})` }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="block_name" label="控制块名称" />
+        <el-table-column prop="block_desc" label="控制块描述" />
+        <el-table-column prop="block_datset" label="数据集名称" />
+        <el-table-column prop="block_rptid" label="RptID" />
+        <el-table-column prop="block_intgpd" label="完整性周期" />
+        <el-table-column prop="block_confrev" label="配置版本" />
+        <el-table-column prop="block_buffered" label="是否缓存" />
+        <el-table-column prop="block_buftime" label="缓存时间" />
+        <el-table-column  label="信息点数量">
+          <template #default="scope">
+           <span v-if="scope.row.list">{{ scope.row.list.length }}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="title">
+        定值条目列表详情(共<span v-if="dingzhiDataChild">{{ dingzhiDataChild.length }}</span
+        >条)
+      </div>
+      <el-table
+        :data="dingzhiDataChild"
+        style="width: 100%"
+        stripe
+        :cell-style="{ color: '#000' }"
+      >
+        <el-table-column type="index" label="序号" width="80" />
+        <el-table-column prop="doi_desc" label="条目描述" width="180" />
+        <el-table-column prop="da_datatype" label="数据类型" />
+        <el-table-column prop="short_addr" label="内部地址" />
+      </el-table>
+    </div>
+  </div>
 </template>
 <script setup>
-import { onMounted, watch, ref,nextTick,defineEmits } from "vue";
+import { onMounted, watch, ref, nextTick, defineEmits, inject } from "vue";
+import { getPointtable } from "@/api/iedNetwork";
 const props = defineProps({
-  checkDialogData: {
+  checkData: {
     type: Object,
     default: () => {},
   },
+  isPhoto: {
+    type: String,
+    default: "",
+  },
+  svInfo: {
+    type: Array,
+    default: [],
+  },
+});
+const scdIdValue = inject("scdId");
+const dingzhiData = ref(null);
+const dingzhiDataChild = ref(null);
+const myTable5 = ref(null);
+const getDingzhisList = async () => {
+  const dingRes = await getPointtable({
+    scd_id: scdIdValue,
+    ied_name: props.checkData.ied_name,
+  });
+  if (dingRes.data.length > 0) {
+    dingzhiData.value = dingRes.data;
+    dingzhiDataChild.value = dingRes.data[0].list;
+  }
+
+  myTable5.value.setCurrentRow(dingzhiData.value[0]);
+};
+const svSendRowClick3 = (row, column) => {
+  dingzhiDataChild.value = row.list;
+};
+watch(
+  () => props.checkData,
+  (newValue) => {
+    dingzhiData.value = [];
+    dingzhiDataChild.value = [];
+    if (newValue != null) {
+      getDingzhisList();
+    }
+  }
+);
+onMounted(() => {
+  getDingzhisList();
 });
 </script>
 <style scoped lang="scss">
+.cont-table {
+  height: 65vh;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+}
+:deep(.el-table) {
+  flex-basis: 45%;
+}
+.title {
+  margin: 16px;
+  color: #51637f;
+}
 </style>

+ 269 - 192
src/pages/netStructPicture/components/inoutControl.vue

@@ -3,18 +3,18 @@
   <div>
     <!-- 关联图 -->
     <div
-      v-if="isPhoto == 'photo'"
+      v-if="tabValue == 'photo'"
       class="main-cont"
       ref="myElement"
-      id="treedom"
+      id="treedom2"
     >
-      <div class="main-left">
+      <div class="main-left" ref="leftElement">
         <div
           v-for="(item, index) in leftList"
           :key="index"
           class="conts"
           @click="clickImg(item)"
-          :ref="(el) => setdom(el, item)"
+          :ref="(el) => setdom2(el, item)"
         >
           <div class="cont-item">
             <div>{{ item.ref_ied_name }}</div>
@@ -28,6 +28,7 @@
               class="ied-desc-child"
               v-for="(item3, index3) in cItem.childItem"
               :key="index3"
+              :ref="(el) => setdomLeftChild2(el, item3)"
             >
               <div>{{ item3.ctrl_name }}</div>
               <div>{{ item3.datset_desc }}</div>
@@ -36,31 +37,32 @@
         </div>
       </div>
       <!-- 中间部分 -->
-      <div class="main-middle" ref="middleHeight">
+      <div class="main-middle" ref="middleHeight" id="end">
         <div class="middle-title">
-          <div v-if="listData">{{ listData.ied_name }}</div>
-          <div v-if="listData">{{ listData.desc }}</div>
+          <div v-if="listData2">{{ listData2.ied_name }}</div>
+          <div v-if="listData2">{{ listData2.desc }}</div>
         </div>
         <div class="middle-item" ref="middleElement">
           <div
-            class="ied-desc-child middle-child"
-            v-for="(itemChild, index) in svInfo"
+            class="midlestyle"
+            v-for="(item, index) in svInfo"
             :key="index"
+            :ref="(el) => setdomMiddle2(el, item)"
           >
-            <div>{{ `${itemChild.ldinst}/${itemChild.attr_name}` }}</div>
-            <div>{{ itemChild.datset_desc }}</div>
-            <div class="ied-desc">APPID:{{ itemChild.APPID }}</div>
+            <div>{{ `${item.ldinst}/${item.attr_name}` }}</div>
+            <div>{{ item.datset_desc }}</div>
+            <div class="ied-desc">APPID:{{ item.APPID }}</div>
           </div>
         </div>
       </div>
       <!-- 右侧 -->
-      <div class="main-right">
+      <div class="main-right" ref="rightElement">
         <div
           v-for="(item, index) in rightList"
           :key="index"
           class="conts"
           @click="clickImg(item)"
-          :ref="(el) => setdomRight(el, item)"
+          :ref="(el) => setdomRight2(el, item)"
         >
           <div class="cont-item">
             <div>{{ item.ref_ied_name }}</div>
@@ -74,6 +76,7 @@
               class="ied-desc-child"
               v-for="(item3, index3) in cItem.childItem"
               :key="index3"
+              :ref="(el) => setdomRight2Child2(el, item3)"
             >
               <div>{{ item3.ctrl_name }}</div>
               <div>{{ item3.datset_desc }}</div>
@@ -83,7 +86,7 @@
       </div>
       <div id="wrapper"></div>
     </div>
-    <div v-if="isPhoto != 'photo'">
+    <div v-if="tabValue != 'photo'">
       <inoutSendOrRv
         :isPhoto="isPhoto"
         :checkData="checkData"
@@ -93,7 +96,7 @@
   </div>
 </template>
 <script setup>
-import { onMounted, watch, ref, nextTick, defineEmits, inject } from "vue";
+import { onMounted, watch, ref, nextTick, defineEmits, inject  } from "vue";
 import devicePng from "@/assets/image/instruct/device.png";
 import LeaderLine from "../../../../public/leader-line.min.js";
 import AnimEvent from "../../../../public/anim-event.min.js";
@@ -126,6 +129,10 @@ const props = defineProps({
     type: Object,
     default: () => {},
   },
+  tabName: {
+    type: String,
+    default: "",
+  },
 });
 const svInfo = ref(null);
 const scdIdValue = inject("scdId");
@@ -138,7 +145,7 @@ const getIedChild = async () => {
     forcerefresh: 0,
   });
   //左右侧内部侧数据组装
-  listData.value.list.forEach((item, index) => {
+  listData2.value.list.forEach((item, index) => {
     item.titleItems = [];
     childRes.data.forEach((key) => {
       if (key.target_ied_name === item.ref_ied_name) {
@@ -177,47 +184,66 @@ const getNetworkInfo = async () => {
     scd_id: scdIdValue,
     ied_name: props.checkData.ied_name,
   });
-  if (svResInfoCtrl.data.GSEControl) {
+  if (svResInfoCtrl.data && svResInfoCtrl.data.GSEControl) {
     svResInfo.data.forEach((item) => {
       svResInfoCtrl.data.GSEControl.forEach((key) => {
-        key.APPID =
-          item.cb_name == key.attr_name
-            ? JSON.parse(item.address_json).APPID
-            : "";
+        if (item.cb_name == key.attr_name) {
+          key.APPID = JSON.parse(item.address_json).APPID;
+        }
       });
     });
     svInfo.value = svResInfoCtrl.data.GSEControl;
-  }
-};
-watch(
-  () => props.checkData,
-  (newValue) => {
-    if (newValue != null) {
-      getIedChild();
-      getNetworkInfo();
+    if (svInfo.value && svInfo.value.length > 3) {
+      middleElement.value.style.marginTop = "20px";
+    } else {
+      middleElement.value.style.marginTop = "150px"; // 设置元素的垂直位置
     }
   }
-);
+};
 //线条
 const middleElement = ref(null);
 const myElement = ref(null);
-let leaderLines = ref([]); //控制线条显示
+let leaderLines2 = ref([]); //控制线条显示
 const leftList = ref([]);
 const rightList = ref([]);
-const domList = ref(new Map()); //获取 所有的ref
-const domListRight = ref(new Map()); //获取 所有的ref
-const listData = ref(props.checkData); //线条左右两侧的数据
+const domList2 = ref(new Map()); //获取 所有的ref
+const domListRight2 = ref(new Map()); //获取右侧所有的ref
+const domListMiddle2 = ref(new Map()); //获取中间所有的ref
+const domListRightChild2 = ref(new Map()); //获取右侧所有子的ref
+const domListLeftChild2 = ref(new Map()); //获取中间所有子的ref
+const listData2 = ref(props.checkData); //线条左右两侧的数据
 const emit = defineEmits(["result"]); //如果不加这个再次点击左侧会没有反应
-const setdom = (el, item) => {
+const tabValue = ref(props.isPhoto); //点击tab切换的数据
+const rightElement = ref(null);
+const leftElement = ref(null);
+const setdom2 = (el, item) => {
   //左侧dom
   if (el) {
-    domList.value.set(item, el);
+    domList2.value.set(item, el);
   }
 };
-const setdomRight = (el, item) => {
+const setdomRight2 = (el, item) => {
   //右侧dom
   if (el) {
-    domListRight.value.set(item, el);
+    domListRight2.value.set(item, el);
+  }
+};
+const setdomMiddle2 = (el, item) => {
+  // 中间dom
+  if (el) {
+    domListMiddle2.value.set(item, el);
+  }
+};
+//左侧子Dom
+const setdomLeftChild2 = (el, item) => {
+  if (el) {
+    domListLeftChild2.value.set(item, el);
+  }
+};
+//右侧子Dom
+const setdomRight2Child2 = (el, item) => {
+  if (el) {
+    domListRightChild2.value.set(item, el);
   }
 };
 const processArray = (arr) => {
@@ -242,51 +268,21 @@ const processArray = (arr) => {
 const clickImg = (dataItem) => {
   Object.values(props.iedRelation).find((item) => {
     if (item.ied_name == dataItem.ref_ied_name) {
-      listData.value = item;
+      listData2.value = item;
     }
   });
 };
-watch(
-  () => props.checkData,
-  (newValue, oldV) => {
-    listData.value = [];
-    listData.value = newValue;
-    if (newValue && leaderLines.value.length > 0) {
-      // leaderLines.value.forEach((line) => line.remove()); //清除连线
-      leaderLines.value = [];
-    }
-  },
-  { deep: true }
-);
-watch(
-  () => listData.value,
-  (newValue) => {
-    emit("result", newValue);
-    clickResetLine();
-  }
-);
-watch(
-  () => props.isOpen,
-  (newValue) => {
-    if (newValue) {
-      domList.value.clear();
-      domListRight.value.clear();
-      leaderLines.value = [];
-    }
-    nextTick(() => {
-      middleLinePosition();
-      removeLine();
-    });
-  }
-);
+
 //点击后重置数据和线条
-const clickResetLine = () => {
-  domList.value.clear();
-  domListRight.value.clear();
-  leaderLines.value = [];
-  middleLinePosition();
-  setLine();
-  removeLine();
+const clickResetLine2 = () => {
+  domList2.value.clear();
+  domListRight2.value.clear();
+  domListMiddle2.value.clear();
+  domListLeftChild2.value.clear();
+  domListRightChild2.value.clear();
+  leaderLines2.value = [];
+  setLine2();
+  removeLine2();
 };
 // 将设备列表分成两份
 const bothSide = (data) => {
@@ -297,110 +293,156 @@ const bothSide = (data) => {
   rightList.value = formatArr.splice(0);
 };
 
-const setLeaderline = () => {
+const setLeaderline2 = () => {
   // lineArr.value = [];
   //线条样式
-  const lineStyle0 = {
-    color: "#51637F",
-    size: 2,
-    path: "straight",
-    startPlug: "arrow1",
-    endPlug: "behind",
-    startSocket: "right",
-    endSocket: "left",
-  };
-  const lineStyle1 = {
-    color: "#51637F",
-    size: 2,
-    path: "straight",
-    endPlug: "arrow1",
-    startSocket: "right",
-    endSocket: "left",
-  };
-  const lineStyle2 = {
-    color: "#134BEA",
-    size: 2,
-    path: "straight",
-    startPlug: "arrow1",
-    endPlug: "arrow1",
-    startSocket: "right",
-    endSocket: "left",
-  };
-  const lineStyleRight0 = {
-    color: "#51637F",
-    size: 2,
-    path: "straight",
-    startPlug: "arrow1",
-    endPlug: "behind",
-    startSocket: "left",
-    endSocket: "right",
-  };
-  const lineStyleRight1 = {
-    color: "#51637F",
-    size: 2,
-    path: "straight",
-    endPlug: "arrow1",
-    startSocket: "left",
-    endSocket: "right",
-  };
-  const lineStyleRight2 = {
-    color: "#134BEA",
-    size: 2,
-    path: "straight",
-    startPlug: "arrow1",
-    endPlug: "arrow1",
-    startSocket: "left",
-    endSocket: "right",
-  };
   const startDom = document.getElementById("end");
-  //循环画线
-  for (const [key, value] of domList.value) {
+  //左侧子组件
+  for (const [key, value] of domListLeftChild2.value) {
     const endDom = value;
     let line;
-    if (key.ref_type == 0) {
-      // line = new LeaderLine(endDom, startDom, lineStyle0);
-    } else if (key.ref_type == 2) {
-      // line = new LeaderLine(endDom, startDom, lineStyle0);
+    const options = key.inputs_cnt.toString();
+    const rectEnd = endDom.getBoundingClientRect();
+    if (key.ctrl_type == "smv") {
+      line = new LeaderLine(
+        endDom,
+        LeaderLine.pointAnchor(startDom, { x: 0, y: rectEnd.top - 222 }),
+        {
+          color: "red",
+          size: 2,
+          path: "straight",
+          startSocket: "right",
+          endSocket: "left",
+          middleLabel: LeaderLine.captionLabel({
+            text: options,
+          }),
+        }
+      );
+    } else {
+      line = new LeaderLine(
+        endDom,
+        LeaderLine.pointAnchor(startDom, { x: 0, y: rectEnd.top - 222 }),
+        {
+          color: "#255CE7",
+          size: 2,
+          path: "straight",
+          startSocket: "right",
+          endSocket: "left",
+          y: 50,
+          middleLabel: LeaderLine.captionLabel({
+            text: options,
+          }),
+        }
+      );
     }
-    //  保存进数组,方便进行遍历删除
-    leaderLines.value.push(line);
+    leaderLines2.value.push(line);
   }
-  //循环画线右侧
-  for (const [key, value] of domListRight.value) {
+  //右侧子组件
+  for (const [key, value] of domListRightChild2.value) {
     const endDom = value;
-    let line2;
-    if (key.ref_type == 0) {
-      // line2 = new LeaderLine(endDom, startDom, lineStyleRight0);
-    } else if (key.ref_type == 2) {
-      // line2 = new LeaderLine(endDom, startDom, lineStyleRight0);
-    }
-    //  保存进数组,方便进行遍历删除
-    leaderLines.value.push(line2);
-  }
-  hiddenLine();
-};
-const middleHeight = ref(null);
-//设置中间盒子的所在位置
-const middleLinePosition = () => {
-  setTimeout(() => {
-    const heights = myElement.value.scrollHeight;
-    if (leftList.value.length > 2 || rightList.value.length > 2) {
-      middleElement.value.style.marginTop = `${(heights - 60) / 2}px`; // 设置元素的垂直位置
-      middleHeight.value.style.height = heights
+    let line;
+    const rectEnd = endDom.getBoundingClientRect();
+    const options = key.inputs_cnt.toString();
+    if (key.ctrl_type == "smv") {
+      line = new LeaderLine(
+        LeaderLine.pointAnchor(startDom, { x: "100%", y: rectEnd.top - 222 }),
+        endDom,
+        {
+          color: "red",
+          size: 2,
+          path: "straight",
+          startSocket: "right",
+          endSocket: "left",
+          startPlug: "arrow1",
+          endPlug: "behind",
+          middleLabel: LeaderLine.captionLabel(options),
+        }
+      );
     } else {
-      middleElement.value.style.marginTop = "150px"; // 设置元素的垂直位置
+      line = new LeaderLine(
+        LeaderLine.pointAnchor(startDom, { x: "100%", y: rectEnd.top - 222 }),
+        endDom,
+        {
+          color: "#255CE7",
+          size: 2,
+          path: "straight",
+          startSocket: "right",
+          endSocket: "left",
+          startPlug: "arrow1",
+          endPlug: "behind",
+          middleLabel: LeaderLine.captionLabel(options),
+        }
+      );
     }
-  }, 0);
+    leaderLines2.value.push(line);
+  }
+  if (iedChild.value) {
+    iedChild.value.forEach((item) => {
+      //循环画线左侧
+      for (const [key, value] of domList2.value) {
+        let line;
+        for (let [key2, value2] of domListMiddle2.value) {
+          //中间的数据dom
+          if (key.ref_ied_name == item.source_ied_name) {
+            const endDom = value;
+            if (item.ctrl_id == key2.node_id) {
+              const startDom = value2;
+              const options2 = item.inputs_cnt.toString();
+              line = new LeaderLine(endDom, startDom, {
+                color: "#51637F",
+                size: 2,
+                path: "straight",
+                endPlug: "behind",
+                startPlug: "arrow1",
+                startSocket: "right",
+                endSocket: "left",
+                middleLabel: LeaderLine.captionLabel(options2),
+              });
+              leaderLines2.value.push(line);
+            }
+          }
+        }
+      }
+      //循环画线右侧
+      for (let [key, value] of domListRight2.value) {
+        let line2;
+        for (let [key2, value2] of domListMiddle2.value) {
+          //中间的数据dom
+          if (key.ref_ied_name == item.source_ied_name) {
+            const endDom = value;
+            if (item.ctrl_id == key2.node_id) {
+              const startDom = value2;
+              const options3 = item.inputs_cnt.toString();
+              line2 = new LeaderLine(startDom, endDom, {
+                color: "#51637F",
+                size: 2,
+                path: "straight",
+                startPlug: "behind",
+                endPlug: "arrow1",
+                endSocket: "left",
+                startSocket: "right",
+                middleLabel: LeaderLine.captionLabel(options3),
+              });
+              leaderLines2.value.push(line2);
+            }
+          }
+        }
+      }
+    });
+  }
+  hiddenLine2();
 };
 //滚动时重定位线条
-const newPositionLine = () => {
-  document.getElementById("treedom").addEventListener(
+const newPositionLine2 = () => {
+  document.getElementById("treedom2").addEventListener(
     "scroll",
     AnimEvent.add(() => {
-      leaderLines.value.forEach((line) => {
-        hiddenLine();
-        // line.position();
-        // line.positionByWindowResize = false;
+      leaderLines2.value.forEach((line) => {
+        if (line) {
+          hiddenLine2();
+          line.position();
+          line.positionByWindowResize = false;
+        }
       });
       //中间展示图片的
     }),
@@ -408,7 +450,7 @@ const newPositionLine = () => {
   );
 };
 //弹窗打开后使得线条在指定区域中
-const hiddenLine = () => {
+const hiddenLine2 = () => {
   const elmWrapper = document.getElementById("wrapper");
   // 移动 line
   document.body.querySelectorAll("body .leader-line").forEach((node) => {
@@ -421,15 +463,16 @@ const hiddenLine = () => {
     (rectWrapper.left + window.scrollY) * -1
   }px, ${(rectWrapper.top + window.scrollX) * -1}px)`;
 };
-const setLine = () => {
-  if (listData.value) {
-    bothSide(listData.value.list);
+const setLine2 = () => {
+  if (listData2.value) {
+    bothSide(listData2.value.list);
   }
   setTimeout(() => {
-    setLeaderline();
-  }, 30);
+    setLeaderline2();
+  }, 500);
 };
-const removeLine = () => {
+
+const removeLine2 = () => {
   const elmWrapper = document.getElementById("wrapper");
   document.body.querySelectorAll("body .leader-line").forEach((node) => {
     elmWrapper.removeChild(node);
@@ -438,33 +481,68 @@ const removeLine = () => {
 onMounted(() => {
   if (props.checkData != null) {
     getIedChild();
-    getNetworkInfo();
+
   }
   //不加条件切换下方tab时会出现bug
   if (props.isPhoto == "photo") {
+    getNetworkInfo();
     nextTick(() => {
-      setLine();
-      middleLinePosition();
+      setLine2();
       nextTick(() => {
-        newPositionLine();
+        newPositionLine2();
       });
     });
   }
 });
+
 watch(
   () => props.isPhoto,
   (newValue) => {
-    if (props.isPhoto == "photo") {
+    tabValue.value = newValue;
+    if (tabValue.value == "photo") {
       nextTick(() => {
-        setLine();
-        middleLinePosition();
-        nextTick(() => {
-          newPositionLine();
-        });
+        setLine2();
+        newPositionLine2();
       });
     }
   }
 );
+watch(
+  () => props.checkData,
+  (newValue) => {
+    listData2.value = [];
+    svInfo.value = [];
+    listData2.value = newValue;
+    if (newValue != null) {
+      getIedChild();
+   
+    }
+    if (tabValue.value == "photo") {
+      clickResetLine2();
+      getNetworkInfo();
+    }
+    emit("result", newValue);
+    if (newValue && leaderLines2.value.length > 0) {
+      leaderLines2.value = [];
+    }
+  }
+);
+watch(
+  () => props.isOpen,
+  (newValue) => {
+    if (newValue) {
+      domList2.value.clear();
+      domListRight2.value.clear();
+      domListMiddle2.value.clear();
+      domListLeftChild2.value.clear();
+      domListRightChild2.value.clear();
+      leaderLines2.value = [];
+    }
+    nextTick(() => {
+      removeLine2();
+    });
+  }
+);
 </script>
 <style lang="scss"  scoped>
 @mixin img-size {
@@ -479,8 +557,6 @@ watch(
 .main-cont {
   display: flex;
   justify-content: space-evenly;
-  overflow-y: auto;
-  height: 65vh;
 }
 
 .leader-line {
@@ -493,6 +569,7 @@ watch(
 .main-middle {
   box-sizing: border-box;
   border: 2px dashed #98a8ff;
+  background: #edf3ff;
   img {
     margin-bottom: 10px;
   }
@@ -507,8 +584,6 @@ watch(
     color: #ffcb11;
     border-bottom: 1px solid #a3ade0;
   }
-  .middel-child {
-  }
 }
 .main-right {
   display: flex;
@@ -523,6 +598,7 @@ watch(
   margin-bottom: 24px;
   border: 2px dashed #98a8ff;
   cursor: pointer;
+  background: #f7f8fb;
   .cont-item {
     @include left-and-right;
     color: #1a2447;
@@ -543,7 +619,8 @@ watch(
     display: block;
   }
 }
-.ied-desc-child {
+.ied-desc-child,
+.midlestyle {
   @include left-and-right;
   align-items: center;
   border: 1px solid #7484ab;

+ 4 - 4
src/pages/netStructPicture/components/inoutSendOrRv.vue

@@ -6,7 +6,7 @@
         :data="svTableCtrl"
         stripe
         style="width: 100%"
-        :cell-style="{ color: '#000' }"
+        :cell-style="{ color: '#000',cursor:'pointer' }"
         @row-click="svSendRowClick"
         :highlight-current-row="true"
         ref="myTable"
@@ -54,7 +54,7 @@
         :data="svReceive"
         stripe
         style="width: 100%"
-        :cell-style="{ color: '#000' }"
+        :cell-style="{ color: '#000',cursor:'pointer' }"
         @row-click="svSendRowClick2"
         :highlight-current-row="true"
         ref="myTable2"
@@ -105,7 +105,7 @@
         :data="gooseCtrl"
         stripe
         style="width: 100%"
-        :cell-style="{ color: '#000' }"
+        :cell-style="{ color: '#000',cursor:'pointer' }"
         @row-click="svSendRowClick3"
         :highlight-current-row="true"
         ref="myTable3"
@@ -153,7 +153,7 @@
         :data="gooseReCtrl"
         stripe
         style="width: 100%"
-        :cell-style="{ color: '#000' }"
+        :cell-style="{ color: '#000',cursor:'pointer' }"
         @row-click="svSendRowClick4"
         :highlight-current-row="true"
         ref="myTable4"

+ 5 - 5
src/pages/netStructPicture/components/netWork.vue

@@ -151,7 +151,7 @@ const loading = ref(true);
 //获取网络图的顶部列表
 const getNetWork = async () => {
   const infoRes = await nodeList({
-    scd_id: 296000081,
+    scd_id: 452000123,
     pagesize: 10000,
     name: "SubNetwork",
   });
@@ -170,7 +170,7 @@ const allApData = ref({});
 const initLoad = async () => {
   allApData.value = {};
   const allAP = await nodeList({
-    scd_id: 296000081,
+    scd_id: 452000123,
     pagesize: 10000,
     name: "ConnectedAP",
   });
@@ -198,7 +198,7 @@ const initLoad = async () => {
 };
 //处理重复的ip
 const ipNetaddr = async () => {
-  const ipRes = await iedNetaddr({ scd_id: 296000081 });
+  const ipRes = await iedNetaddr({ scd_id: 452000123 });
   if (ipRes.code == 1) {
     return;
   }
@@ -500,11 +500,11 @@ const clickNetworkInfo = (value) => {
 
 const iedRelationData = ref([]);
 const iedRelation = async () => {
-  const iedRes = await scdIedRelation({ scd_id: 296000081 });
+  const iedRes = await scdIedRelation({ scd_id: 452000123 });
   iedRelationData.value = iedRes.data;
 };
 //弹窗=============
-provide('scdId',296000081)
+provide('scdId',452000123)
 </script>
   
 <style scoped lang="scss">

+ 349 - 345
src/pages/netStructPicture/components/relationShip.vue

@@ -1,374 +1,378 @@
 <!-- 装置关联关系 -->
 <template>
-<div>
-  <div class="main-cont" ref="myElement" id="treedom">
-    <div class="main-left">
-      <div
-        v-for="(item, index) in leftList"
-        :key="index"
-        class="cont"
-        @click="clickImg(item)"
-      >
-        <img
-          :src="devicePng"
-          alt=""
-          class="img-item"
-          :ref="(el) => setdom(el, item)"
-        />
-        <div>{{ item.ref_ied_name }}</div>
-        <div class="ied-desc">{{ item.ref_ied_desc }}</div>
+  <div>
+    <div class="main-cont" ref="myElement" id="treedom">
+      <div class="main-left">
+        <div
+          v-for="(item, index) in leftList"
+          :key="index"
+          class="cont"
+          @click="clickImg(item)"
+        >
+          <img
+            :src="devicePng"
+            alt=""
+            class="img-item"
+            :ref="(el) => setdom(el, item)"
+          />
+          <div>{{ item.ref_ied_name }}</div>
+          <div class="ied-desc">{{ item.ref_ied_desc }}</div>
+        </div>
       </div>
-    </div>
-    <div class="main-middle">
-      <div class="middle-item" ref="middleElement">
-        <img :src="devicePng" alt="" id="end" />
-        <div v-if="listData">{{ listData.ied_name }}</div>
-        <div v-if="listData">{{ listData.desc }}</div>
+      <div class="main-middle">
+        <div class="middle-item" ref="middleElement">
+          <img :src="devicePng" alt="" id="end" />
+          <div v-if="listData">{{ listData.ied_name }}</div>
+          <div v-if="listData">{{ listData.desc }}</div>
+        </div>
       </div>
-    </div>
-    <div class="main-right">
-      <div
-        v-for="(item, index) in rightList"
-        :key="index"
-        class="cont"
-        @click="clickImg(item)"
-      >
-        <img
-          :src="devicePng"
-          alt=""
-          class="img-item"
-          :ref="(el) => setdomRight(el, item)"
-        />
-        <div>{{ item.ref_ied_name }}</div>
-        <div class="ied-desc">{{ item.ref_ied_desc }}</div>
+      <div class="main-right">
+        <div
+          v-for="(item, index) in rightList"
+          :key="index"
+          class="cont"
+          @click="clickImg(item)"
+        >
+          <img
+            :src="devicePng"
+            alt=""
+            class="img-item"
+            :ref="(el) => setdomRight(el, item)"
+          />
+          <div>{{ item.ref_ied_name }}</div>
+          <div class="ied-desc">{{ item.ref_ied_desc }}</div>
+        </div>
       </div>
     </div>
+    <div id="wrapper"></div>
   </div>
-  <div id="wrapper"></div>
-</div>
-</template>
-<script setup>
-import { onMounted, watch, ref, nextTick, defineEmits } from "vue";
-import devicePng from "@/assets/image/instruct/device.png";
-import LeaderLine from "../../../../public/leader-line.min.js";
-import AnimEvent from "../../../../public/anim-event.min.js";
-const props = defineProps({
-  checkData: {
-    type: Object,
-    default: () => {},
-  },
-  isOpen: {
-    type: Boolean,
-    default: false,
-  },
-  iedRelation: {
-    type: Object,
-    default: () => {},
+  </template>
+  <script setup>
+  import { onMounted, watch, ref, nextTick, defineEmits } from "vue";
+  import devicePng from "@/assets/image/instruct/device.png";
+  import LeaderLine from "../../../../public/leader-line.min.js";
+  import AnimEvent from "../../../../public/anim-event.min.js";
+  const props = defineProps({
+    checkData: {
+      type: Object,
+      default: () => {},
+    },
+    isOpen: {
+      type: Boolean,
+      default: false,
+    },
+    iedRelation: {
+      type: Object,
+      default: () => {},
+    },
+    tabName: {
+    type: String,
+    default: "",
   },
-});
-const middleElement = ref(null);
-const myElement = ref(null);
-let leaderLines = ref([]); //控制线条显示
-const leftList = ref([]);
-const rightList = ref([]);
-const domList = ref(new Map()); //获取 所有的ref
-const domListRight = ref(new Map()); //获取 所有的ref
-const listData = ref(props.checkData); //线条左右两侧的数据
-const emit = defineEmits(["result"]); //如果不加这个再次点击左侧会没有反应
-const setdom = (el, item) => {
-  //左侧dom
-  if (el) {
-    domList.value.set(item, el);
-  }
-};
-const setdomRight = (el, item) => {
-  //右侧dom
-  if (el) {
-    domListRight.value.set(item, el);
-  }
-};
-const processArray = (arr) => {
-  // ref_ied_id作为键,obj作为值
-  const uniqueObjects = new Map();
-  // 遍历数组
-  for (const obj of arr) {
-    const { ref_ied_id } = obj;
-    // 如果当前对象的 ref_ied_id 属性已经存在于 uniqueObjects 中
-    if (uniqueObjects.has(ref_ied_id)) {
-      // 将对应对象的 ref_type 属性设为 2,箭头双向
-      uniqueObjects.get(ref_ied_id).ref_type = 2;
-    } else {
-      // 否则,将当前对象添加到 uniqueObjects 中
-      uniqueObjects.set(ref_ied_id, obj);
-    }
-  }
-  // 将 uniqueObjects 中的值转为数组并返回
-  return Array.from(uniqueObjects.values());
-};
-//点击图片的时候筛选出数据
-const clickImg = (dataItem) => {
-  Object.values(props.iedRelation).find((item) => {
-    if (item.ied_name == dataItem.ref_ied_name) {
-      listData.value = item;
-    }
   });
-};
-watch(
-  () => props.checkData,
-  (newValue, oldV) => {
-    listData.value = newValue;
-    if (newValue && leaderLines.value.length > 0) {
-      // leaderLines.value.forEach((line) => line.remove()); //清除连线
-      leaderLines.value = [];
+  const middleElement = ref(null);
+  const myElement = ref(null);
+  let leaderLines = ref([]); //控制线条显示
+  const leftList = ref([]);
+  const rightList = ref([]);
+  const domList = ref(new Map()); //获取 所有的ref
+  const domListRight = ref(new Map()); //获取 所有的ref
+  const listData = ref(props.checkData); //线条左右两侧的数据
+  const emit = defineEmits(["result"]); //如果不加这个再次点击左侧会没有反应
+  const setdom = (el, item) => {
+    //左侧dom
+    if (el) {
+      domList.value.set(item, el);
     }
-  },
-  { deep: true }
-);
-watch(
-  () => listData.value,
-  (newValue) => {
-    emit("result", newValue);
-    clickResetLine();
-  }
-);
-watch(
-  () => props.isOpen,
-  (newValue) => {
-    if (newValue) {
-      domList.value.clear();
-      domListRight.value.clear();
-      leaderLines.value = [];
+  };
+  const setdomRight = (el, item) => {
+    //右侧dom
+    if (el) {
+      domListRight.value.set(item, el);
     }
-    nextTick(() => {
-      middleLinePosition();
-      removeLine();
+  };
+  const processArray = (arr) => {
+    // ref_ied_id作为键,obj作为值
+    const uniqueObjects = new Map();
+    // 遍历数组
+    for (const obj of arr) {
+      const { ref_ied_id } = obj;
+      // 如果当前对象的 ref_ied_id 属性已经存在于 uniqueObjects 中
+      if (uniqueObjects.has(ref_ied_id)) {
+        // 将对应对象的 ref_type 属性设为 2,箭头双向
+        uniqueObjects.get(ref_ied_id).ref_type = 2;
+      } else {
+        // 否则,将当前对象添加到 uniqueObjects 中
+        uniqueObjects.set(ref_ied_id, obj);
+      }
+    }
+    // 将 uniqueObjects 中的值转为数组并返回
+    return Array.from(uniqueObjects.values());
+  };
+  //点击图片的时候筛选出数据
+  const clickImg = (dataItem) => {
+    Object.values(props.iedRelation).find((item) => {
+      if (item.ied_name == dataItem.ref_ied_name) {
+        listData.value = item;
+      }
     });
-  }
-);
-//点击后重置数据和线条
-const clickResetLine = () => {
-  domList.value.clear();
-  domListRight.value.clear();
-  leaderLines.value = [];
-  middleLinePosition();
-  setLine();
-  removeLine();
-};
-// 将设备列表分成两份
-const bothSide = (data) => {
-  const formatArr = processArray(data);
-  const arrlenght = formatArr.length;
-  const long1 = Math.ceil(arrlenght / 2);
-  leftList.value = formatArr.splice(0, long1);
-  rightList.value = formatArr.splice(0);
-};
-
-const setLeaderline = () => {
-  // lineArr.value = [];
-  //线条样式
-  const lineStyle0 = {
-    color: "#51637F",
-    size: 2,
-    path: "straight",
-    startPlug: "arrow1",
-    endPlug: "behind",
-    startSocket: "right",
-    endSocket: "left",
   };
-  const lineStyle1 = {
-    color: "#51637F",
-    size: 2,
-    path: "straight",
-    endPlug: "arrow1",
-    startSocket: "right",
-    endSocket: "left",
+  watch(
+    () => props.checkData,
+    (newValue, oldV) => {
+      listData.value = newValue;
+      if (newValue && leaderLines.value.length > 0) {
+        // leaderLines.value.forEach((line) => line.remove()); //清除连线
+        leaderLines.value = [];
+      }
+    },
+    { deep: true }
+  );
+  watch(
+    () => listData.value,
+    (newValue) => {
+      emit("result", newValue);
+      clickResetLine();
+    }
+  );
+  watch(
+    () => props.isOpen,
+    (newValue) => {
+      if (newValue) {
+        domList.value.clear();
+        domListRight.value.clear();
+        leaderLines.value = [];
+      }
+      nextTick(() => {
+        middleLinePosition();
+        removeLine();
+      });
+    }
+  );
+  //点击后重置数据和线条
+  const clickResetLine = () => {
+    domList.value.clear();
+    domListRight.value.clear();
+    leaderLines.value = [];
+    middleLinePosition();
+    setLine();
+    removeLine();
   };
-  const lineStyle2 = {
-    color: "#134BEA",
-    size: 2,
-    path: "straight",
-    startPlug: "arrow1",
-    endPlug: "arrow1",
-    startSocket: "right",
-    endSocket: "left",
+  // 将设备列表分成两份
+  const bothSide = (data) => {
+    const formatArr = processArray(data);
+    const arrlenght = formatArr.length;
+    const long1 = Math.ceil(arrlenght / 2);
+    leftList.value = formatArr.splice(0, long1);
+    rightList.value = formatArr.splice(0);
   };
-  const lineStyleRight0 = {
-    color: "#51637F",
-    size: 2,
-    path: "straight",
-    startPlug: "arrow1",
-    endPlug: "behind",
-    startSocket: "left",
-    endSocket: "right",
+  
+  const setLeaderline = () => {
+    // lineArr.value = [];
+    //线条样式
+    const lineStyle0 = {
+      color: "#51637F",
+      size: 2,
+      path: "straight",
+      startPlug: "arrow1",
+      endPlug: "behind",
+      startSocket: "right",
+      endSocket: "left",
+    };
+    const lineStyle1 = {
+      color: "#51637F",
+      size: 2,
+      path: "straight",
+      endPlug: "arrow1",
+      startSocket: "right",
+      endSocket: "left",
+    };
+    const lineStyle2 = {
+      color: "#134BEA",
+      size: 2,
+      path: "straight",
+      startPlug: "arrow1",
+      endPlug: "arrow1",
+      startSocket: "right",
+      endSocket: "left",
+    };
+    const lineStyleRight0 = {
+      color: "#51637F",
+      size: 2,
+      path: "straight",
+      startPlug: "arrow1",
+      endPlug: "behind",
+      startSocket: "left",
+      endSocket: "right",
+    };
+    const lineStyleRight1 = {
+      color: "#51637F",
+      size: 2,
+      path: "straight",
+      endPlug: "arrow1",
+      startSocket: "left",
+      endSocket: "right",
+    };
+    const lineStyleRight2 = {
+      color: "#134BEA",
+      size: 2,
+      path: "straight",
+      startPlug: "arrow1",
+      endPlug: "arrow1",
+      startSocket: "left",
+      endSocket: "right",
+    };
+    const startDom = document.getElementById("end");
+    //循环画线
+    for (const [key, value] of domList.value) {
+      const endDom = value;
+      let line;
+      if (key.ref_type == 0) {
+        line = new LeaderLine(endDom, startDom, lineStyle0);
+      } else if (key.ref_type == 1) {
+        line = new LeaderLine(endDom, startDom, lineStyle1);
+      } else if (key.ref_type == 2) {
+        line = new LeaderLine(endDom, startDom, lineStyle2);
+      }
+      //  保存进数组,方便进行遍历删除
+      leaderLines.value.push(line);
+    }
+    //循环画线右侧
+    for (const [key, value] of domListRight.value) {
+      const endDom = value;
+      let line2;
+      if (key.ref_type == 0) {
+        line2 = new LeaderLine(endDom, startDom, lineStyleRight0);
+      } else if (key.ref_type == 1) {
+        line2 = new LeaderLine(endDom, startDom, lineStyleRight1);
+      } else if (key.ref_type == 2) {
+        line2 = new LeaderLine(endDom, startDom, lineStyleRight2);
+      }
+      //  保存进数组,方便进行遍历删除
+      leaderLines.value.push(line2);
+    }
+    hiddenLine();
+  };
+  //设置中间盒子的所在位置
+  const middleLinePosition = () => {
+    setTimeout(() => {
+      const heights = myElement.value.scrollHeight;
+      if (leftList.value.length > 3 || rightList.value.length > 3) {
+        middleElement.value.style.marginTop = `${(heights - 60) / 2}px`; // 设置元素的垂直位置
+      } else {
+        middleElement.value.style.marginTop = "150px"; // 设置元素的垂直位置
+      }
+    }, 0);
   };
-  const lineStyleRight1 = {
-    color: "#51637F",
-    size: 2,
-    path: "straight",
-    endPlug: "arrow1",
-    startSocket: "left",
-    endSocket: "right",
+  onMounted(() => {
+    nextTick(() => {
+      setLine();
+      middleLinePosition();
+      nextTick(() => {
+        newPositionLine();
+      });
+    });
+  });
+  //滚动时重定位线条
+  const newPositionLine = () => {
+    document.getElementById("treedom").addEventListener(
+      "scroll",
+      AnimEvent.add(() => {
+        leaderLines.value.forEach((line) => {
+          hiddenLine();
+          line.position();
+          line.positionByWindowResize = false;
+        });
+        //中间展示图片的
+      }),
+      false
+    );
   };
-  const lineStyleRight2 = {
-    color: "#134BEA",
-    size: 2,
-    path: "straight",
-    startPlug: "arrow1",
-    endPlug: "arrow1",
-    startSocket: "left",
-    endSocket: "right",
+  //弹窗打开后使得线条在指定区域中
+  const hiddenLine = () => {
+    const elmWrapper = document.getElementById("wrapper");
+    // 移动 line
+    document.body.querySelectorAll("body .leader-line").forEach((node) => {
+      elmWrapper.appendChild(node);
+    });
+    elmWrapper.style.transform = "none";
+    var rectWrapper = elmWrapper.getBoundingClientRect();
+    // Move to the origin of coordinates as the document
+    elmWrapper.style.transform = `translate(${
+      (rectWrapper.left + window.scrollY) * -1
+    }px, ${(rectWrapper.top + window.scrollX) * -1}px)`;
   };
-  const startDom = document.getElementById("end");
-  //循环画线
-  for (const [key, value] of domList.value) {
-    const endDom = value;
-    let line;
-    if (key.ref_type == 0) {
-      line = new LeaderLine(endDom, startDom, lineStyle0);
-    } else if (key.ref_type == 1) {
-      line = new LeaderLine(endDom, startDom, lineStyle1);
-    } else if (key.ref_type == 2) {
-      line = new LeaderLine(endDom, startDom, lineStyle2);
+  const setLine = () => {
+    if (listData.value) {
+      bothSide(listData.value.list);
     }
-    //  保存进数组,方便进行遍历删除
-    leaderLines.value.push(line);
+    setTimeout(() => {
+      setLeaderline();
+    }, 30);
+  };
+  const removeLine = () => {
+    const elmWrapper = document.getElementById("wrapper");
+    document.body.querySelectorAll("body .leader-line").forEach((node) => {
+      elmWrapper.removeChild(node);
+    });
+  };
+  </script>
+  <style lang="scss">
+  @mixin img-size {
+    width: 150px;
+    height: 90px;
+    margin-bottom: 10px;
   }
-  //循环画线右侧
-  for (const [key, value] of domListRight.value) {
-    const endDom = value;
-    let line2;
-    if (key.ref_type == 0) {
-      line2 = new LeaderLine(endDom, startDom, lineStyleRight0);
-    } else if (key.ref_type == 1) {
-      line2 = new LeaderLine(endDom, startDom, lineStyleRight1);
-    } else if (key.ref_type == 2) {
-      line2 = new LeaderLine(endDom, startDom, lineStyleRight2);
-    }
-    //  保存进数组,方便进行遍历删除
-    leaderLines.value.push(line2);
+  @mixin left-and-right {
+    display: flex;
+    flex-direction: column;
+  }
+  .main-cont {
+    display: flex;
+    justify-content: space-evenly;
+  }
+  
+  .leader-line {
+    z-index: 3000;
   }
-  hiddenLine();
-};
-//设置中间盒子的所在位置
-const middleLinePosition = () => {
-  setTimeout(() => {
-    const heights = myElement.value.scrollHeight;
-    if (leftList.value.length > 3 || rightList.value.length > 3) {
-      middleElement.value.style.marginTop = `${(heights - 60) / 2}px`; // 设置元素的垂直位置
-    } else {
-      middleElement.value.style.marginTop = "150px"; // 设置元素的垂直位置
+  .main-left {
+    display: flex;
+    @include left-and-right;
+    .img-item {
+      @include img-size;
     }
-  }, 0);
-};
-onMounted(() => {
-  nextTick(() => {
-    setLine();
-    middleLinePosition();
-    nextTick(() => {
-      newPositionLine();
-    });
-  });
-});
-//滚动时重定位线条
-const newPositionLine = () => {
-  document.getElementById("treedom").addEventListener(
-    "scroll",
-    AnimEvent.add(() => {
-      leaderLines.value.forEach((line) => {
-        hiddenLine();
-        line.position();
-        line.positionByWindowResize = false;
-      });
-      //中间展示图片的
-    }),
-    false
-  );
-};
-//弹窗打开后使得线条在指定区域中
-const hiddenLine = () => {
-  const elmWrapper = document.getElementById("wrapper");
-  // 移动 line
-  document.body.querySelectorAll("body .leader-line").forEach((node) => {
-    elmWrapper.appendChild(node);
-  });
-  elmWrapper.style.transform = "none";
-  var rectWrapper = elmWrapper.getBoundingClientRect();
-  // Move to the origin of coordinates as the document
-  elmWrapper.style.transform = `translate(${
-    (rectWrapper.left + window.scrollY) * -1
-  }px, ${(rectWrapper.top + window.scrollX) * -1}px)`;
-};
-const setLine = () => {
-  if (listData.value) {
-    bothSide(listData.value.list);
   }
-  setTimeout(() => {
-    setLeaderline();
-  }, 30);
-};
-const removeLine = () => {
-  const elmWrapper = document.getElementById("wrapper");
-  document.body.querySelectorAll("body .leader-line").forEach((node) => {
-    elmWrapper.removeChild(node);
-  });
-};
-</script>
-<style lang="scss">
-@mixin img-size {
-  width: 150px;
-  height: 90px;
-  margin-bottom: 10px;
-}
-@mixin left-and-right {
-  display: flex;
-  flex-direction: column;
-}
-.main-cont {
-  display: flex;
-  justify-content: space-evenly;
-}
-
-.leader-line {
-  z-index: 3000;
-}
-.main-left {
-  display: flex;
-  @include left-and-right;
-  .img-item {
-    @include img-size;
+  .main-middle {
+    box-sizing: border-box;
+    img {
+      margin-bottom: 10px;
+    }
+    .middle-item {
+      @include left-and-right;
+      align-items: center;
+      color: #ffcb11;
+    }
   }
-}
-.main-middle {
-  box-sizing: border-box;
-  img {
-    margin-bottom: 10px;
+  .main-right {
+    display: flex;
+    @include left-and-right;
+    .img-item {
+      @include img-size;
+    }
   }
-  .middle-item {
+  
+  .cont {
     @include left-and-right;
     align-items: center;
-    color: #ffcb11;
-  }
-}
-.main-right {
-  display: flex;
-  @include left-and-right;
-  .img-item {
-    @include img-size;
+    margin-bottom: 10px;
+    .ied-desc {
+      color: #255ce7;
+    }
   }
-}
-
-.cont {
-  @include left-and-right;
-  align-items: center;
-  margin-bottom: 10px;
-  .ied-desc {
-    color: #255ce7;
+  
+  #wrapper {
+    width: 0;
+    height: 0;
+    position: relative; /* Origin of coordinates for lines, and scrolled content (i.e. not `absolute`) */
   }
-}
-
-#wrapper {
-  width: 0;
-  height: 0;
-  position: relative; /* Origin of coordinates for lines, and scrolled content (i.e. not `absolute`) */
-}
-</style>
+  </style>

+ 6 - 6
src/pages/netStructPicture/components/scdVisual.vue

@@ -161,7 +161,7 @@ import scdDialogIndex from "./scdDialogIndex";
 const userStoreCode = useDataStore();
 const data = reactive({
   queryParams: {
-    scd_id: 296000081,
+    scd_id: 452000123,
   },
 });
 const loading = ref(true);
@@ -171,7 +171,7 @@ const { queryParams } = toRefs(data);
 // 表单重置
 const reset = () => {
   queryParams.value = {
-    scd_id: 296000081,
+    scd_id: 452000123,
     voltage_level_id: null, //电压等级
     area_id: null, //间隔
     device_type_id: null, //装置类型
@@ -185,7 +185,7 @@ const allIedType = [{ name: "全部", code: "alls" }];
 const voltageLevel = ref([{ name: "全部", id: "alls" }]); //电压等级
 const areaType = ref([]);
 const getArea = async () => {
-  const areaRes = await areaList({ scd_id: 296000081 });
+  const areaRes = await areaList({ scd_id: 452000123 });
   if (!areaRes.data) {
     voltageLevel.value = [];
     loading.value = false;
@@ -223,7 +223,7 @@ const getArea = async () => {
 //设备类型
 const iedTypeData = ref([]);
 const getTypelist = async () => {
-  const typeRes = await iedTypelist({ scd_id: 296000081 });
+  const typeRes = await iedTypelist({ scd_id: 452000123 });
   iedTypeData.value = typeRes.data ? [...allIedType, ...typeRes.data] : [];
 };
 const iedName = ref([]);
@@ -254,7 +254,7 @@ const searchInput = (value) => {
 const count = ref(0);
 const iedNameData = async () => {
   //IED编码或名称
-  const iedRes = await scdIedRelation({ scd_id: 296000081 });
+  const iedRes = await scdIedRelation({ scd_id: 452000123 });
   iedName.value = iedRes.data;
   count.value = iedRes.count;
 };
@@ -282,7 +282,7 @@ const changeLevel = async (value, mainValue) => {
     open.value = true;
     dialogData.value = iedName.value;
   } else if (value) {
-    const mainClick = { scd_id: 296000081, area_id: value };
+    const mainClick = { scd_id: 452000123, area_id: value };
     const forms = mainValue ? mainClick : queryParams.value;
     open.value = true;
     dialogData.value = [];

+ 512 - 5
src/pages/netStructPicture/components/virtualRelation.vue

@@ -1,15 +1,522 @@
-<!-- 虚端子关系 -->
+<!-- 输入输出控制块 -->
 <template>
-  <div>3</div>
+  <div>
+    <!-- 关联图 -->
+    <div class="main-cont" id="treedom3">
+      <div class="main-left">
+        <div
+          v-for="(item, index) in leftList"
+          :key="index"
+          class="conts"
+          @click="clickImg(item)"
+        >
+          <div class="cont-title">
+            <img :src="devicePng" alt="" class="img-item" />
+            <div class="cont-item">
+              <div>{{ item.ref_ied_desc }}</div>
+              <div>{{ item.ref_ied_name }}</div>
+            </div>
+          </div>
+          <div
+            v-for="(cItem, index2) in item.titleItems"
+            :key="index2"
+            :ref="(el) => setdomLeftChild3(el, cItem)"
+          >
+            <div class="text-midle">
+              <div>
+                {{
+                  `${cItem.attr_ld_inst}/${cItem.attr_prefix}${cItem.attr_ln_class}.${cItem.attr_do_name}.${cItem.attr_da_name}`
+                }}
+              </div>
+              <div>{{ cItem.do_source_desc }}</div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <!-- 中间部分 -->
+      <div class="main-middle" ref="middleHeight" id="end">
+        <div class="cont-title">
+          <img :src="devicePng" alt="" class="img-item" />
+          <div class="middle-title">
+            <div>{{ listData3.desc }}</div>
+            <div>{{ listData3.ied_name }}</div>
+          </div>
+        </div>
+        <div class="middle-item">
+          <div
+            class="midle-cont"
+            v-for="(item, index) in svInfo"
+            :key="index"
+            :ref="(el) => setdomMiddle3(el, item)"
+          >
+            <div style="margin: 0 4px" v-if="!item.isDecollate">
+              {{ item.no }}
+            </div>
+            <div class="midlestyle" v-if="!item.isDecollate">
+              <div v-if="item.attr_da_name == 'general'">
+                {{
+                  `${item.attr_ld_inst}/${item.attr_ln_class}${item.attr_ln_inst}.${item.attr_do_name}.${item.attr_da_name}`
+                }}
+              </div>
+              <div v-else>{{ item.attr_int_addr }}</div>
+              <div>{{ item.do_source_desc }}</div>
+            </div>
+            <div class="midlestyle omit" v-if="item.isDecollate">
+              {{ item.do_source_desc }}
+            </div>
+          </div>
+        </div>
+      </div>
+      <!-- 右侧 -->
+      <div class="main-right">
+        <div
+          v-for="(item, index) in rightList"
+          :key="index"
+          class="conts"
+          @click="clickImg(item)"
+        >
+          <div class="cont-title">
+            <img :src="devicePng" alt="" class="img-item" />
+            <div class="cont-item">
+              <div>{{ item.ref_ied_desc }}</div>
+              <div>{{ item.ref_ied_name }}</div>
+            </div>
+          </div>
+          <div
+            v-for="(cItem, index2) in item.titleItems"
+            :key="index2"
+            :ref="(el) => setdomRightChild3(el, cItem)"
+          >
+            <div class="text-midle">
+              <div>{{ `${cItem.attr_int_addr}` }}</div>
+              <div>{{ cItem.do_target_desc }}</div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div id="wrapper"></div>
+    </div>
+  </div>
 </template>
 <script setup>
-import { onMounted, watch, ref,nextTick,defineEmits } from "vue";
+import { onMounted, watch, ref, nextTick, defineEmits, inject } from "vue";
+import devicePng from "@/assets/image/instruct/device.png";
+import LeaderLine from "../../../../public/leader-line.min.js";
+import AnimEvent from "../../../../public/anim-event.min.js";
+import {
+  //send发送
+  iednetworkInfo,
+  iedSVSendCtrlblock,
+  gooseSendctrlblock,
+  //虚短子关系
+  getMiddleinputs,
+} from "@/api/iedNetwork";
+import jsPlumb from "jsplumb";
 const props = defineProps({
-  checkDialogData: {
+  checkData: {
     type: Object,
     default: () => {},
   },
+  checkData: {
+    type: Object,
+    default: () => {},
+  },
+  isOpen: {
+    type: Boolean,
+    default: false,
+  },
+  iedRelation: {
+    type: Object,
+    default: () => {},
+  },
+  tabName: {
+    type: String,
+    default: "",
+  },
+});
+const svInfo = ref(null);
+const scdIdValue = inject("scdId");
+
+//处理两边的数据
+const processBoth = (list, svResInfo, inoutType) => {
+  list.forEach((item, index) => {
+    item.titleItems = [];
+    svResInfo.data.forEach((key) => {
+      if (key.ied_name == item.ref_ied_name) {
+        if (
+          (item.titleItems.length < 1 && key.inout_type == inoutType) ||
+          (!item.titleItems.some(
+            (titleKey) => titleKey.ref_ied_name == key.ied_name
+          ) &&
+            key.inout_type === inoutType)
+        ) {
+          item.titleItems.push(key);
+        }
+      }
+    });
+  });
+};
+let leaderLines3 = ref([]); //控制线条显示
+const leftList = ref([]);
+const rightList = ref([]);
+const domListMiddle3 = ref(new Map()); //获取中间所有的ref
+const domListRightChild3 = ref(new Map()); //获取右侧所有子的ref
+const domListLeftChild3 = ref(new Map()); //获取中间所有子的ref
+const listData3 = ref(props.checkData); //线条左右两侧的数据
+const emit = defineEmits(["result"]); //如果不加这个再次点击左侧会没有反应
+const setdomMiddle3 = (el, item) => {
+  // 中间dom
+  if (el) {
+    domListMiddle3.value.set(item, el);
+  }
+};
+//左侧子Dom
+const setdomLeftChild3 = (el, item) => {
+  if (el) {
+    domListLeftChild3.value.set(item, el);
+  }
+};
+//右侧子Dom
+const setdomRightChild3 = (el, item) => {
+  if (el) {
+    domListRightChild3.value.set(item, el);
+  }
+};
+//得到中间的子版块数据
+const getNetworkInfo3 = async () => {
+  const svResInfo = await getMiddleinputs({
+    scd_id: scdIdValue,
+    ied_name: props.checkData.ied_name,
+  });
+  const data = {
+    attr_ld_inst: "",
+    attr_ln_class: "",
+    attr_ln_inst: "",
+    attr_do_name: "",
+    attr_da_name: "",
+    do_source_desc: "...",
+    no: "",
+    isDecollate: true,
+  };
+  //处理两边的数据
+  if (svResInfo.data.length > 0) {
+    processBoth(leftList.value, svResInfo, "in");
+    processBoth(rightList.value, svResInfo, "out");
+  }
+
+  //处理中间的数据有省略号的
+  let newData = [];
+  for (let i = 0; i < svResInfo.data.length; i++) {
+    newData.push(svResInfo.data[i]);
+    if (
+      i < svResInfo.data.length - 1 &&
+      svResInfo.data[i].ied_name != svResInfo.data[i + 1].ied_name
+    ) {
+      newData.push(data);
+    }
+  }
+
+  svInfo.value = newData;
+};
+const processArray = (arr) => {
+  // ref_ied_id作为键,obj作为值
+  const uniqueObjects = new Map();
+  // 遍历数组
+  for (const obj of arr) {
+    const { ref_ied_id } = obj;
+    // 如果当前对象的 ref_ied_id 属性已经存在于 uniqueObjects 中
+    if (uniqueObjects.has(ref_ied_id)) {
+      // 将对应对象的 ref_type 属性设为 2,箭头双向
+      uniqueObjects.get(ref_ied_id).ref_type = 2;
+    } else {
+      // 否则,将当前对象添加到 uniqueObjects 中
+      uniqueObjects.set(ref_ied_id, obj);
+    }
+  }
+  // 将 uniqueObjects 中的值转为数组并返回
+  return Array.from(uniqueObjects.values());
+};
+//点击图片的时候筛选出数据
+const clickImg = (dataItem) => {
+  Object.values(props.iedRelation).find((item) => {
+    if (item.ied_name == dataItem.ref_ied_name) {
+      listData3.value = item;
+    }
+  });
+};
+
+//点击后重置数据和线条
+const clickResetLine3 = () => {
+  domListMiddle3.value.clear();
+  domListLeftChild3.value.clear();
+  domListRightChild3.value.clear();
+  leaderLines3.value = [];
+  setLine();
+  removeLine3();
+};
+
+// 将设备列表分成两份
+const bothSide = (data) => {
+  leftList.value = [];
+  rightList.value = [];
+  data.forEach((item) => {
+    if (item.ref_type == 2 || item.ref_type == 1) {
+      item.titleItems = [];
+      leftList.value.push(item);
+    } else {
+      item.titleItems = [];
+      rightList.value.push(item);
+    }
+  });
+};
+const setLeaderline = () => {
+  //左侧子组件
+  for (let [key, value] of domListMiddle3.value) {
+    for (const [key2, value2] of domListLeftChild3.value) {
+      const endDom = value2;
+      if (key.node_id == key2.node_id) {
+        const line = new LeaderLine(endDom, value, {
+          color: "#7484AB",
+          size: 2,
+          path: "straight",
+          startSocket: "right",
+          endSocket: "left",
+          y: 50,
+          startPlug: "disc",
+          endPlug: "arrow1",
+        });
+        leaderLines3.value.push(line);
+      }
+    }
+  }
+  for (let [key, value] of domListMiddle3.value) {
+    //右侧子组件
+    for (const [key2, value2] of domListRightChild3.value) {
+      const endDom = value2;
+      if (key.node_id == key2.node_id) {
+        const line2 = new LeaderLine(value, endDom, {
+          color: "#7484AB",
+          size: 2,
+          path: "straight",
+          startSocket: "right",
+          endSocket: "left",
+          startPlug: "disc",
+          endPlug: "arrow1",
+        });
+        leaderLines3.value.push(line2);
+      }
+    }
+  }
+  hiddenLine();
+};
+//滚动时重定位线条
+const newPositionLine = () => {
+  document.getElementById("treedom3").addEventListener(
+    "scroll",
+    AnimEvent.add(() => {
+      leaderLines3.value.forEach((line) => {
+        if (line) {
+          hiddenLine();
+          line.position();
+          line.positionByWindowResize = false;
+        }
+      });
+      //中间展示图片的
+    }),
+    false
+  );
+};
+//弹窗打开后使得线条在指定区域中
+const hiddenLine = () => {
+  const elmWrapper = document.getElementById("wrapper");
+  // 移动 line
+  document.body.querySelectorAll("body .leader-line").forEach((node) => {
+    elmWrapper.appendChild(node);
+  });
+  elmWrapper.style.transform = "none";
+  var rectWrapper = elmWrapper.getBoundingClientRect();
+  // Move to the origin of coordinates as the document
+  elmWrapper.style.transform = `translate(${
+    (rectWrapper.left + window.scrollY) * -1
+  }px, ${(rectWrapper.top + window.scrollX) * -1}px)`;
+};
+const setLine = () => {
+  if (listData3.value) {
+    bothSide(listData3.value.list);
+  }
+  setTimeout(() => {
+    setLeaderline();
+  }, 500);
+};
+
+const removeLine3 = () => {
+  leaderLines3.value = [];
+  const elmWrapper = document.getElementById("wrapper");
+  document.body.querySelectorAll("body .leader-line").forEach((node) => {
+    elmWrapper.removeChild(node);
+  });
+};
+onMounted(() => {
+  if (props.checkData != null) {
+    getNetworkInfo3();
+  }
+  //不加条件切换下方tab时会出现bug
+  nextTick(() => {
+    setLine();
+    nextTick(() => {
+      newPositionLine();
+    });
+  });
 });
+watch(
+  () => props.checkData,
+  (newValue) => {
+    listData3.value = [];
+    svInfo.value = [];
+    listData3.value = newValue;
+    if (newValue != null) {
+      getNetworkInfo3();
+    }
+    clickResetLine3();
+    emit("result", newValue);
+    if (newValue && leaderLines3.value.length > 0) {
+      leaderLines3.value = [];
+    }
+  }
+);
+watch(
+  () => props.isOpen,
+  (newValue) => {
+    if (newValue) {
+      domListMiddle3.value.clear();
+      domListLeftChild3.value.clear();
+      domListRightChild3.value.clear();
+      leaderLines3.value = [];
+    }
+    nextTick(() => {
+      removeLine3();
+    });
+  }
+);
 </script>
-<style scoped lang="scss">
+<style lang="scss"  scoped>
+@mixin img-size {
+  width: 48px;
+  height: 48px;
+}
+@mixin left-and-right {
+  display: flex;
+  flex-direction: column;
+}
+.main-cont {
+  display: flex;
+  justify-content: space-evenly;
+}
+
+.leader-line {
+  z-index: 3000;
+}
+.main-left {
+  display: flex;
+  @include left-and-right;
+}
+.main-middle {
+  box-sizing: border-box;
+  border: 2px dashed #98a8ff;
+  background: #edf3ff;
+  margin:0 60px;
+  img {
+    @include img-size;
+  }
+  .middle-item {
+    @include left-and-right;
+    align-items: center;
+    cursor: pointer;
+  }
+  .cont-title {
+    display: flex;
+    align-items: center;
+    margin: 12px 14px 5px 14px;
+    border-bottom: 1px solid #a3ade0;
+  }
+  .middle-title {
+    color: #ffcb11;
+    margin-left: 8px;
+  }
+}
+.main-right {
+  display: flex;
+  @include left-and-right;
+  .img-item {
+    @include img-size;
+  }
+}
+
+.conts {
+  @include left-and-right;
+  margin-bottom: 24px;
+  border: 2px dashed #98a8ff;
+  cursor: pointer;
+  background: #f7f8fb;
+  padding: 12px;
+  .cont-title {
+    display: flex;
+    align-items: center;
+    margin: 12px 14px 5px 14px;
+    padding: 12px;
+    border-bottom: 1px solid #a3ade0;
+  }
+  .cont-item {
+    color: #1a2447;
+    margin-left: 6px;
+    vertical-align: middle;
+  }
+  .ied-desc {
+    color: #255ce7;
+  }
+  .ied-desc-title {
+    color: #134bea;
+  }
+
+  .ied-desc-child-title {
+    color: #5182ff;
+    margin-left: 14px;
+    display: block;
+  }
+}
+.midle-cont {
+  display: flex;
+  border: 1px solid #7484ab;
+  align-items: center;
+  width: 94%;
+  margin-bottom: 8px;
+  color: #1a2447;
+}
+.ied-desc-child,
+.midlestyle {
+  @include left-and-right;
+  align-items: center;
+  border-radius: 2px;
+  padding: 5px;
+  color: #1a2447;
+  flex: 1;
+}
+.omit {
+  font-weight: bold;
+  letter-spacing: 8px;
+  font-size: 15px;
+}
+#wrapper {
+  width: 0;
+  height: 0;
+  position: relative; /* Origin of coordinates for lines, and scrolled content (i.e. not `absolute`) */
+}
+.text-midle {
+  text-align: center;
+  width: 94%;
+  border: 1px solid #7484ab;
+  margin-bottom: 8px;
+  border-radius: 2px;
+  padding: 5px;
+}
 </style>

+ 1 - 0
src/router/index.js

@@ -75,6 +75,7 @@ const routes = [
                 }
             },
             {
+                
                 path:"/home/netStructPicture",
                 component:()=>import("@/pages/netStructPicture"),
                 meta:{

+ 4 - 3
src/utils/request.js

@@ -7,7 +7,7 @@ import { useRouter } from 'vue-router'
 const service = axios.create({
     // baseURL: window.STATIC_CONFIG.proxyUrl, // url = base url + request url
     baseURL: "http://8.142.173.95:9527/api",
-    timeout: 15000, // request timeout
+    timeout: 1500000000, // request timeout
     headers:{
         "Content-Type":"application/x-www-form-urlencoded"
     }
@@ -67,7 +67,7 @@ service.interceptors.request.use(
         // return Promise.reject(error)
     }
 )
-
+var router = useRouter()
 // 响应拦截
 service.interceptors.response.use(
     response => {
@@ -77,12 +77,13 @@ service.interceptors.response.use(
     },
     error => {
         console.log(error,'相应拦截器error');
+        console.log(router,'router');
         if(error.code == "ERR_NETWORK"){
             ElMessage({
                 type:"error",
                 message:"网络错误,请重新登录",
             })
-            useRouter().push("/login")
+            router.push("/login")
         }
         if (error.response.status === 401) {
             ElMessage({