123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563 |
- <!-- 虚端子关系 -->
- <template>
- <div v-loading="loading" element-loading-text="加载数据中" style="overflow: hidden">
- <!-- 关联图 -->
- <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_ln_inst}.${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" v-if="listData3">
- <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.inout_type == 'out'">
- {{
- `${item.attr_ld_inst}/${item.attr_prefix}/${item.attr_ln_class}${item.attr_ln_inst}.${item.attr_do_name}.${item.attr_da_name}`
- }}
- </div>
- <div v-else-if="item.inout_type == 'in'">{{ item.attr_int_addr }}</div>
- <div v-if="item.inout_type == 'out'">
- {{ item.do_source_desc }}
- </div>
- <div v-else-if="item.inout_type == 'in'">
- {{ item.do_target_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="wrapperVirtual"></div>
- </div>
- </div>
- </template>
- <script setup>
- 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 {
- //虚短子关系
- getMiddleinputs,
- scdIedRelation,
- } from "@/api/iedNetwork";
- import { useRoute } from "vue-router";
- import { clickImgEvent } from "@/utils/common.js";
- const route = useRoute();
- const props = defineProps({
- checkData: {
- type: Object,
- default: () => {},
- },
- isOpen: {
- type: Boolean,
- default: false,
- },
- iedRelation: {
- type: Object,
- default: () => {},
- },
- delScdId: {
- type: String,
- default: "",
- },
- isScdView: {
- type: Boolean,
- default: false,
- },
- });
- const svInfo = ref(null);
- const loading = ref(true);
- //处理两边的数据
- const processBoth = (list, svResInfo, inoutType) => {
- if (!list||!svResInfo.data) return;
- 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);
- }
- };
- let tagList = ref(null); //左侧更改的设备列表
- //得到中间的子版块数据
- const getNetworkInfo3 = async (names) => {
- let svResInfo;
- svResInfo = await getMiddleinputs({
- scd_id: scdIdValue,
- ied_name: names,
- });
- 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&&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 clickImg = async (dataItem) => {
- loading.value =true;
- listData3.value =await clickImgEvent(props,dataItem,scdIdValue);
- getNetworkInfo3(dataItem.ref_ied_name)
- };
- //点击后重置数据和线条
- const clickResetLine3 = () => {
- domListMiddle3.value.clear();
- domListLeftChild3.value.clear();
- domListRightChild3.value.clear();
- leaderLines3.value = [];
- removeLine3();
- setLine();
- };
- // 将设备列表分成两份
- const bothSide = (data) => {
- leftList.value = [];
- rightList.value = [];
- if(!data) return;
- 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;
- LeaderLine.positionByWindowResize = false;
- 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;
- LeaderLine.positionByWindowResize = false;
- 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);
- }
- }
- }
- loading.value =false;
- hiddenLine();
- };
- //滚动时重定位线条
- const newPositionLine = () => {
- document.getElementById("treedom3").addEventListener(
- "scroll",
- AnimEvent.add(() => {
- if (!leaderLines3.value) return;
- leaderLines3.value.forEach((line) => {
- if (line) {
- hiddenLine();
- line.position();
- line.positionByWindowResize = false;
- }
- });
- //中间展示图片的
- }),
- false
- );
- document.getElementById("treedom3").addEventListener(
- "resize",
- AnimEvent.add(function () {
- if (!diffline) return;
- diffline.forEach((line) => {
- hiddenLine();
- line.position();
- line.positionByWindowResize = false;
- });
- }),
- false
- );
- };
- //弹窗打开后使得线条在指定区域中
- const hiddenLine = () => {
- const elmWrapper = document.getElementById("wrapperVirtual");
- if(!elmWrapper) return;
- // 移动 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();
- newPositionLine();
- }, 500);
- };
- const removeLine3 = () => {
- leaderLines3.value = [];
- const elmWrapper = document.getElementById("wrapperVirtual");
- if (elmWrapper) {
- document.body.querySelectorAll("#wrapperVirtual .leader-line").forEach((node) => {
- elmWrapper.removeChild(node);
- });
- }
- };
- let scdIdValue = "";
- onMounted(() => {
- if (props.delScdId) {
- scdIdValue = props.delScdId;
- } else {
- scdIdValue = route.query.id;
- }
- if (props.checkData != null&&listData3.value) {
- getNetworkInfo3(listData3.value.ied_name);
- }
- //不加条件切换下方tab时会出现bug
- nextTick(() => {
- setLine();
- });
- });
- watch(
- () => props.checkData,
- (newValue) => {
- loading.value =true;
- listData3.value = [];
- svInfo.value = [];
- listData3.value = newValue;
- if (newValue != null&&listData3.value) {
- getNetworkInfo3(listData3.value.ied_name);
- }
- 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();
- });
- }
- );
- watch(
- () => listData3.value,
- (newValue) => {
- emit("result", newValue);
- clickResetLine3();
- }
- );
- </script>
- <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;
- margin-top: 60px;
- }
- .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;
- }
- #wrapperVirtual {
- 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>
|