inoutControl.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. <!-- 输入输出控制块 -->
  2. <template>
  3. <div>
  4. <!-- 关联图 -->
  5. <div
  6. v-if="tabValue == 'photo'"
  7. class="main-cont"
  8. ref="myElement"
  9. id="treedom2"
  10. >
  11. <div class="main-left" ref="leftElement">
  12. <div
  13. v-for="(item, index) in leftList"
  14. :key="index"
  15. class="conts"
  16. @click="clickImg(item)"
  17. :ref="(el) => setdom2(el, item)"
  18. >
  19. <div class="cont-item">
  20. <div>{{ item.ref_ied_name }}</div>
  21. <div>{{ item.ref_ied_desc }}</div>
  22. </div>
  23. <div v-for="(cItem, index2) in item.titleItems" :key="index2">
  24. <div class="ied-desc-child-title">
  25. {{ cItem.ld_inst }} {{ cItem.ld_desc }}
  26. </div>
  27. <div
  28. class="ied-desc-child"
  29. v-for="(item3, index3) in cItem.childItem"
  30. :key="index3"
  31. :class="{ 'smv-color': item3.ctrl_type == 'smv' }"
  32. :ref="(el) => setdomLeftChild2(el, item3)"
  33. >
  34. <div>{{ item3.ctrl_name }}</div>
  35. <div>{{ item3.datset_desc }}</div>
  36. </div>
  37. </div>
  38. </div>
  39. </div>
  40. <!-- 中间部分 -->
  41. <div class="main-middle" ref="middleHeight" id="end">
  42. <div class="middle-title" v-if="listData2">
  43. <div>{{ listData2.ied_name }}</div>
  44. <div v-if="listData2">{{ listData2.desc }}</div>
  45. </div>
  46. <div class="middle-item" ref="middleElement">
  47. <div
  48. class="midlestyle"
  49. v-for="(item, index) in svInfo"
  50. :key="index"
  51. :class="{ 'smv-color': item.attr_name == 'smvcb0' }"
  52. :ref="(el) => setdomMiddle2(el, item)"
  53. >
  54. <div>{{ `${item.ldinst}/${item.attr_name}` }}</div>
  55. <div>{{ item.datset_desc }}</div>
  56. <div
  57. class="ied-desc"
  58. style="color: #1a2447"
  59. v-if="item.attr_name != 'smvcb0'"
  60. >
  61. APPID:{{ item.APPID }}
  62. </div>
  63. <div class="ied-desc" style="color: #1a2447" v-else>
  64. APPID:{{ item.address.APPID }}
  65. </div>
  66. </div>
  67. </div>
  68. </div>
  69. <!-- 右侧 -->
  70. <div class="main-right" ref="rightElement">
  71. <div
  72. v-for="(item, index) in rightList"
  73. :key="index"
  74. class="conts"
  75. @click="clickImg(item)"
  76. :ref="(el) => setdomRight2(el, item)"
  77. >
  78. <div class="cont-item">
  79. <div>{{ item.ref_ied_name }}</div>
  80. <div>{{ item.ref_ied_desc }}</div>
  81. </div>
  82. <div v-for="(cItem, index2) in item.titleItems" :key="index2">
  83. <div class="ied-desc-child-title">
  84. {{ cItem.ld_inst }} {{ cItem.ld_desc }}
  85. </div>
  86. <div
  87. class="ied-desc-child"
  88. v-for="(item3, index3) in cItem.childItem"
  89. :key="index3"
  90. :class="{ 'smv-color': item3.ctrl_type == 'smv' }"
  91. :ref="(el) => setdomRight2Child2(el, item3)"
  92. >
  93. <div>{{ item3.ctrl_name }}</div>
  94. <div>{{ item3.datset_desc }}</div>
  95. </div>
  96. </div>
  97. </div>
  98. </div>
  99. <div id="wrapper"></div>
  100. </div>
  101. <div v-if="tabValue != 'photo'">
  102. <inoutSendOrRv
  103. :isPhoto="isPhoto"
  104. :checkData="checkData"
  105. :svInfo="svInfo"
  106. ></inoutSendOrRv>
  107. </div>
  108. <inoutDialog
  109. :circleOpen="circleOpen"
  110. :listData2="listData2"
  111. :checkData="checkData"
  112. :dilogData="dilogData"
  113. :dilogTitie="dilogTitie"
  114. :dilogRightData="dilogRightData"
  115. @done="done"
  116. :titleUnusual="titleUnusual"
  117. :dilogLeftTitle = "dilogLeftTitle"
  118. >
  119. </inoutDialog>
  120. </div>
  121. </template>
  122. <script setup>
  123. import { onMounted, watch, ref, nextTick, defineEmits, inject } from "vue";
  124. import LeaderLine from "../../../../public/leader-line.min.js";
  125. import AnimEvent from "../../../../public/anim-event.min.js";
  126. import inoutSendOrRv from "./inoutSendOrRv";
  127. import inoutDialog from "./inoutDialog.vue";
  128. import {
  129. //send发送
  130. iednetworkInfo,
  131. iedSVSendCtrlblock,
  132. gooseSendctrlblock,
  133. scdIedRelation,
  134. getiedInputs,
  135. } from "@/api/iedNetwork";
  136. import jsPlumb from "jsplumb";
  137. const props = defineProps({
  138. checkData: {
  139. type: Object,
  140. default: () => {},
  141. },
  142. isPhoto: {
  143. type: String,
  144. default: "",
  145. },
  146. checkData: {
  147. type: Object,
  148. default: () => {},
  149. },
  150. isOpen: {
  151. type: Boolean,
  152. default: false,
  153. },
  154. iedRelation: {
  155. type: Object,
  156. default: () => {},
  157. },
  158. });
  159. const svInfo = ref(null);
  160. const scdIdValue = inject("scdId");
  161. const iedChild = ref(null);
  162. const circleOpen = ref(false); //数字点击事件
  163. //得到两边子版块的数据
  164. const getIedChild = async () => {
  165. const childRes = await gooseSendctrlblock({
  166. scd_id: scdIdValue,
  167. ied_name: props.checkData.ied_name,
  168. forcerefresh: 0,
  169. });
  170. //左右侧内部侧数据组装
  171. listData2.value.list.forEach((item, index) => {
  172. item.titleItems = [];
  173. childRes.data.forEach((key) => {
  174. if (key.target_ied_name === item.ref_ied_name) {
  175. if (
  176. item.titleItems.length < 1 ||
  177. !item.titleItems.some(
  178. (titleKey) =>
  179. titleKey.ld_inst === key.ld_inst &&
  180. titleKey.ld_desc === key.ld_desc
  181. )
  182. ) {
  183. key.childItem = [];
  184. item.titleItems.push(key);
  185. }
  186. item.titleItems.forEach((itemKey) => {
  187. if (
  188. itemKey.ld_inst == key.ld_inst &&
  189. itemKey.ld_desc == key.ld_desc
  190. ) {
  191. itemKey.childItem.push(key);
  192. }
  193. });
  194. }
  195. });
  196. });
  197. iedChild.value = childRes.data;
  198. };
  199. //得到中间的子版块数据
  200. const getNetworkInfo = async () => {
  201. const svResInfo = await iednetworkInfo({
  202. scd_id: scdIdValue,
  203. ied_name: props.checkData.ied_name,
  204. });
  205. const svResInfoCtrl = await iedSVSendCtrlblock({
  206. scd_id: scdIdValue,
  207. ied_name: props.checkData.ied_name,
  208. });
  209. if (svResInfoCtrl.data && svResInfoCtrl.data.GSEControl) {
  210. //处理数据得到APPID
  211. svResInfo.data.forEach((item) => {
  212. svResInfoCtrl.data.GSEControl.forEach((key) => {
  213. if (item.cb_name == key.attr_name) {
  214. key.APPID = JSON.parse(item.address_json).APPID;
  215. }
  216. });
  217. });
  218. svInfo.value = [
  219. ...svResInfoCtrl.data.SampledValueControl,
  220. ...svResInfoCtrl.data.GSEControl,
  221. ];
  222. if (svInfo.value && svInfo.value.length > 3) {
  223. middleElement.value.style.marginTop = "20px";
  224. } else {
  225. middleElement.value.style.marginTop = "150px"; // 设置元素的垂直位置
  226. }
  227. }
  228. };
  229. //线条
  230. const middleElement = ref(null);
  231. const myElement = ref(null);
  232. let leaderLines2 = ref([]); //控制线条显示
  233. const leftList = ref([]);
  234. const rightList = ref([]);
  235. const domList2 = ref(new Map()); //获取 所有的ref
  236. const domListRight2 = ref(new Map()); //获取右侧所有的ref
  237. const domListMiddle2 = ref(new Map()); //获取中间所有的ref
  238. const domListRightChild2 = ref(new Map()); //获取右侧所有子的ref
  239. const domListLeftChild2 = ref(new Map()); //获取中间所有子的ref
  240. const listData2 = ref(props.checkData); //线条左右两侧的数据
  241. const emit = defineEmits(["result"]); //如果不加这个再次点击左侧会没有反应
  242. const tabValue = ref(props.isPhoto); //点击tab切换的数据
  243. const rightElement = ref(null);
  244. const leftElement = ref(null);
  245. const setdom2 = (el, item) => {
  246. //左侧dom
  247. if (el) {
  248. domList2.value.set(item, el);
  249. }
  250. };
  251. const setdomRight2 = (el, item) => {
  252. //右侧dom
  253. if (el) {
  254. domListRight2.value.set(item, el);
  255. }
  256. };
  257. const setdomMiddle2 = (el, item) => {
  258. // 中间dom
  259. if (el) {
  260. domListMiddle2.value.set(item, el);
  261. }
  262. };
  263. //左侧子Dom
  264. const setdomLeftChild2 = (el, item) => {
  265. if (el) {
  266. domListLeftChild2.value.set(item, el);
  267. }
  268. };
  269. //右侧子Dom
  270. const setdomRight2Child2 = (el, item) => {
  271. if (el) {
  272. domListRightChild2.value.set(item, el);
  273. }
  274. };
  275. const processArray = (arr) => {
  276. // ref_ied_id作为键,obj作为值
  277. const uniqueObjects = new Map();
  278. // 遍历数组
  279. for (const obj of arr) {
  280. const { ref_ied_id } = obj;
  281. // 如果当前对象的 ref_ied_id 属性已经存在于 uniqueObjects 中
  282. if (uniqueObjects.has(ref_ied_id)) {
  283. // 将对应对象的 ref_type 属性设为 2,箭头双向
  284. uniqueObjects.get(ref_ied_id).ref_type = 2;
  285. } else {
  286. // 否则,将当前对象添加到 uniqueObjects 中
  287. uniqueObjects.set(ref_ied_id, obj);
  288. }
  289. }
  290. // 将 uniqueObjects 中的值转为数组并返回
  291. return Array.from(uniqueObjects.values());
  292. };
  293. //点击图片的时候筛选出数据
  294. const clickImg = (dataItem) => {
  295. Object.values(props.iedRelation).find((item) => {
  296. if (item.ied_name == dataItem.ref_ied_name) {
  297. listData2.value = item;
  298. }
  299. });
  300. };
  301. //点击后重置数据和线条
  302. const clickResetLine2 = () => {
  303. domList2.value.clear();
  304. domListRight2.value.clear();
  305. domListMiddle2.value.clear();
  306. domListLeftChild2.value.clear();
  307. domListRightChild2.value.clear();
  308. leaderLines2.value = [];
  309. setLine2();
  310. removeLine2();
  311. };
  312. // 将设备列表分成两份
  313. const bothSide = (data) => {
  314. const formatArr = processArray(data);
  315. const arrlenght = formatArr.length;
  316. const long1 = Math.ceil(arrlenght / 2);
  317. leftList.value = formatArr.splice(0, long1);
  318. rightList.value = formatArr.splice(0);
  319. };
  320. //圆圈数字的位置endDom, options,posit,keys,startDom
  321. const dilogLeftTitle = ref(null);//弹窗左侧白色
  322. const dilogRightData = ref(null);
  323. const dilogData = ref(null);
  324. const dilogTitie = ref(null);//输入的标题等数据
  325. const titleUnusual =ref('input');//区分点击输入还是输出
  326. const circelSet = (endDom, options, posit, keys, startDom, keyMiddle, mark) => {
  327. let elmButton = endDom.appendChild(document.createElement("div"));
  328. // 阻止点击事件冒泡
  329. elmButton.addEventListener("click", async (event) => {
  330. event.stopPropagation();
  331. console.log("keys", keys, keyMiddle);
  332. if (mark == "middle") {
  333. const ResInput = await getiedInputs({
  334. title: "虚端子—详细信息",
  335. s_ied_name: keyMiddle.ref_ied_name,
  336. m_ied_name: keyMiddle.ied_name,
  337. m_ctrlid: keys.node_id,
  338. s_ctrlid: "",
  339. scd_id: scdIdValue,
  340. });
  341. const resRla = await scdIedRelation({
  342. scd_id: scdIdValue,
  343. ied_name: keyMiddle.ref_ied_name,
  344. reset: 1,
  345. });
  346. dilogData.value = ResInput.data;
  347. dilogRightData.value = resRla.data;
  348. dilogTitie.value = keyMiddle;
  349. dilogLeftTitle.value = keys;
  350. titleUnusual.value ='inout'
  351. } else {
  352. const ResInput = await getiedInputs({
  353. title: "虚端子—详细信息",
  354. s_ied_name: keys.target_ied_name,
  355. m_ied_name: keys.source_ied_name,
  356. m_ctrlid: "",
  357. s_ctrlid: keys.ctrl_id,
  358. scd_id: scdIdValue,
  359. });
  360. const resRla = await scdIedRelation({
  361. scd_id: scdIdValue,
  362. ied_name: keys.target_ied_name,
  363. reset: 1,
  364. });
  365. dilogData.value = ResInput.data;
  366. dilogRightData.value = resRla.data;
  367. dilogTitie.value = keys;
  368. titleUnusual.value ='input'
  369. }
  370. circleOpen.value = true;
  371. });
  372. elmButton.className = "circel-name";
  373. elmButton.innerHTML = options;
  374. elmButton.style.zIndex = "9999";
  375. elmButton.style.width = "20px";
  376. elmButton.style.color = "#fff";
  377. elmButton.style.textAlign = "center";
  378. elmButton.style.height = "20px";
  379. elmButton.style.borderRadius = "10px";
  380. elmButton.style.background = "#255CE7";
  381. elmButton.style.position = "absolute";
  382. if (posit == "left") {
  383. elmButton.style.right = -64 + "px";
  384. elmButton.style.top = 13 + "px";
  385. } else if (posit == "right") {
  386. elmButton.style.left = -64 + "px";
  387. elmButton.style.top = 13 + "px";
  388. } else if (posit == "leftMiddle" || posit == "rightMiddle") {
  389. const dom1Rect = endDom.getBoundingClientRect();
  390. const dom2Rect = startDom.getBoundingClientRect();
  391. // 计算dom1和dom2矩形的中间y坐标。
  392. const dom1MiddleY = dom1Rect.top + dom1Rect.height / 2;
  393. const dom2MiddleY = dom2Rect.top + dom2Rect.height / 2;
  394. if (posit == "leftMiddle") {
  395. elmButton.style.top =
  396. dom1MiddleY + (dom2MiddleY - dom1MiddleY) / 2 - dom1Rect.top + "px";
  397. elmButton.style.right = -74 + "px";
  398. } else {
  399. elmButton.style.top =
  400. dom1MiddleY + (dom2MiddleY - dom1MiddleY) / 2 - dom1Rect.top + "px";
  401. elmButton.style.left = -74 + "px";
  402. }
  403. }
  404. // lineData.value.forEach((ele, index) => {
  405. // const text = ele.doms.querySelector("text");
  406. // text.setAttribute("font-size", "14px");
  407. // text.setAttribute("fill", "#fff"); //文本颜色 ,有点没起效果
  408. // text.setAttribute("dominant-baseline", "ideographic"); //垂直居中
  409. // text.setAttribute("text-anchor", "middle"); //水平居中
  410. // const bbox = text.getBBox(); //获取当前文本的位置和尺寸数据
  411. // // 通过setAttribute方法设置圆形的属性值,包括圆心坐标、半径和背景颜色。
  412. // const width = bbox.width;
  413. // const height = bbox.height;
  414. // const x = parseFloat(text.getAttribute("x"));
  415. // const y = parseFloat(text.getAttribute("y"));
  416. // const circle = document.createElementNS(
  417. // "http://www.w3.org/2000/svg",
  418. // "circle"
  419. // );
  420. // circle.setAttribute("cx", x);
  421. // circle.setAttribute("cy", y - 10);
  422. // circle.setAttribute("r", Math.max(width, height) / 2 + 3); // 加上5像素的额外宽度
  423. // circle.setAttribute("fill", "#255CE7");
  424. // circle.setAttribute("id", `circle${index}`);
  425. // // 将圆形作为文本元素的前置元素,以此实现圆形元素显示在文本元素的底部
  426. // text.parentElement.insertBefore(circle, text);
  427. // // ele.doms.parentElement.addEventListener("click", () =>{
  428. // // console.log('ele', ele)
  429. // // })
  430. // });
  431. // 获取所有circle元素,并为它们添加点击事件监听器
  432. // let circles = document.querySelectorAll("circle");
  433. // console.log('circles', circles)
  434. // circles.forEach((circleClick) => {
  435. // console.log("circleClick");
  436. // circleClick.addEventListener(
  437. // "click",
  438. // handleCircleClick,
  439. // false
  440. // );
  441. // });
  442. };
  443. const done = (emits) => {
  444. circleOpen.value = emits;
  445. dilogData.value =null;
  446. };
  447. let lineData = ref([]);
  448. const setLeaderline2 = () => {
  449. //线条样式
  450. const startDom = document.getElementById("end");
  451. //左侧子组件
  452. for (const [key, value] of domListLeftChild2.value) {
  453. const endDom = value;
  454. let line;
  455. const options = key.inputs_cnt.toString();
  456. const rectEnd = endDom.getBoundingClientRect();
  457. if (key.ctrl_type == "smv") {
  458. line = new LeaderLine(
  459. endDom,
  460. LeaderLine.pointAnchor(startDom, { x: 0, y: rectEnd.top - 232 }),
  461. {
  462. color: "red",
  463. size: 2,
  464. path: "straight",
  465. startSocket: "right",
  466. endSocket: "left",
  467. }
  468. );
  469. circelSet(endDom, options, "left", key);
  470. } else {
  471. line = new LeaderLine(
  472. endDom,
  473. LeaderLine.pointAnchor(startDom, { x: 0, y: rectEnd.top - 232 }),
  474. {
  475. color: "#255CE7",
  476. size: 2,
  477. path: "straight",
  478. startSocket: "right",
  479. endSocket: "left",
  480. // y: 50,
  481. // middleLabel: LeaderLine.captionLabel({
  482. // text: options,
  483. // }),
  484. }
  485. );
  486. circelSet(endDom, options, "left", key);
  487. }
  488. leaderLines2.value.push(line);
  489. }
  490. //右侧子组件
  491. for (const [key, value] of domListRightChild2.value) {
  492. const endDom = value;
  493. let line;
  494. const rectEnd = endDom.getBoundingClientRect();
  495. const options = key.inputs_cnt.toString();
  496. if (key.ctrl_type == "smv") {
  497. line = new LeaderLine(
  498. LeaderLine.pointAnchor(startDom, { x: "100%", y: rectEnd.top - 232 }),
  499. endDom,
  500. {
  501. color: "red",
  502. size: 2,
  503. path: "straight",
  504. startSocket: "right",
  505. endSocket: "left",
  506. startPlug: "arrow1",
  507. endPlug: "behind",
  508. // middleLabel: LeaderLine.captionLabel(options),
  509. }
  510. );
  511. circelSet(endDom, options, "right", key);
  512. } else {
  513. line = new LeaderLine(
  514. LeaderLine.pointAnchor(startDom, { x: "100%", y: rectEnd.top - 232 }),
  515. endDom,
  516. {
  517. color: "#255CE7",
  518. size: 2,
  519. path: "straight",
  520. startSocket: "right",
  521. endSocket: "left",
  522. startPlug: "arrow1",
  523. endPlug: "behind",
  524. // middleLabel: LeaderLine.captionLabel(options),
  525. }
  526. );
  527. circelSet(endDom, options, "right", key);
  528. }
  529. leaderLines2.value.push(line);
  530. }
  531. if (iedChild.value) {
  532. iedChild.value.forEach((item) => {
  533. //循环画线左侧中间
  534. for (const [key, value] of domList2.value) {
  535. let line;
  536. for (let [key2, value2] of domListMiddle2.value) {
  537. //中间的数据dom
  538. if (key.ref_ied_name == item.source_ied_name) {
  539. const endDom = value;
  540. if (item.ctrl_id == key2.node_id) {
  541. const startDom = value2;
  542. const options2 = item.inputs_cnt.toString();
  543. let lineStyle = {
  544. color: "#51637F",
  545. size: 2,
  546. path: "straight",
  547. endPlug: "behind",
  548. startPlug: "arrow1",
  549. startSocket: "right",
  550. endSocket: "left",
  551. // middleLabel: LeaderLine.captionLabel(options2),
  552. };
  553. if (key2.attr_name == "smvcb0") {
  554. lineStyle.color = "red";
  555. }
  556. line = new LeaderLine(endDom, startDom, lineStyle);
  557. circelSet(
  558. endDom,
  559. options2,
  560. "leftMiddle",
  561. key2,
  562. startDom,
  563. key,
  564. "middle"
  565. );
  566. leaderLines2.value.push(line);
  567. }
  568. }
  569. }
  570. }
  571. //循环画线右侧中间
  572. for (let [key, value] of domListRight2.value) {
  573. let line2;
  574. for (let [key2, value2] of domListMiddle2.value) {
  575. //中间的数据dom
  576. if (key.ref_ied_name == item.source_ied_name) {
  577. const endDom = value;
  578. if (item.ctrl_id == key2.node_id) {
  579. const startDom = value2;
  580. const options3 = item.inputs_cnt.toString();
  581. let lineStyle2 = {
  582. color: "#51637F",
  583. size: 2,
  584. path: "straight",
  585. startPlug: "behind",
  586. endPlug: "arrow1",
  587. endSocket: "left",
  588. startSocket: "right",
  589. // middleLabel: LeaderLine.captionLabel(options3),
  590. };
  591. if (key2.attr_name == "smvcb0") {
  592. lineStyle2.color = "red";
  593. }
  594. line2 = new LeaderLine(startDom, endDom, lineStyle2);
  595. circelSet(
  596. endDom,
  597. options3,
  598. "rightMiddle",
  599. key2,
  600. startDom,
  601. key,
  602. "middle"
  603. );
  604. leaderLines2.value.push(line2);
  605. }
  606. }
  607. }
  608. }
  609. });
  610. }
  611. // const allText = document.querySelectorAll(".leader-line");
  612. // circelSet();
  613. hiddenLine2();
  614. };
  615. //滚动时重定位线条
  616. const newPositionLine2 = (diffline) => {
  617. document.getElementById("treedom2").addEventListener(
  618. "scroll",
  619. AnimEvent.add(() => {
  620. diffline.forEach((line) => {
  621. if (line) {
  622. hiddenLine2();
  623. line.position();
  624. line.positionByWindowResize = false;
  625. }
  626. });
  627. //中间展示图片的
  628. }),
  629. false
  630. );
  631. window.addEventListener(
  632. "resize",
  633. AnimEvent.add(function () {
  634. diffline.forEach((line) => {
  635. hiddenLine2();
  636. line.position();
  637. line.positionByWindowResize = false;
  638. });
  639. }),
  640. false
  641. );
  642. };
  643. //弹窗打开后使得线条在指定区域中
  644. const hiddenLine2 = () => {
  645. if (props.isPhoto == "photo" && !circleOpen.value) {
  646. const elmWrapper = document.getElementById("wrapper");
  647. // 移动 line
  648. document.body.querySelectorAll("body .leader-line").forEach((node) => {
  649. elmWrapper.appendChild(node);
  650. });
  651. elmWrapper.style.transform = "none";
  652. var rectWrapper = elmWrapper.getBoundingClientRect();
  653. // Move to the origin of coordinates as the document
  654. elmWrapper.style.transform = `translate(${
  655. (rectWrapper.left + window.scrollY) * -1
  656. }px, ${(rectWrapper.top + window.scrollX) * -1}px)`;
  657. }
  658. };
  659. const setLine2 = () => {
  660. if (listData2.value) {
  661. bothSide(listData2.value.list);
  662. }
  663. setTimeout(() => {
  664. setLeaderline2();
  665. }, 500);
  666. };
  667. const removeLine2 = () => {
  668. const elmWrapper = document.getElementById("wrapper");
  669. if (elmWrapper) {
  670. elmWrapper.querySelectorAll("body .leader-line").forEach((node) => {
  671. // elmWrapper.removeChild(node);
  672. node.remove();
  673. });
  674. }
  675. };
  676. onMounted(() => {
  677. if (props.checkData != null && props.isPhoto == "photo") {
  678. getIedChild();
  679. getNetworkInfo();
  680. }
  681. //不加条件切换下方tab时会出现bug
  682. if (props.isPhoto == "photo") {
  683. nextTick(() => {
  684. setLine2();
  685. nextTick(() => {
  686. newPositionLine2(leaderLines2.value);
  687. });
  688. });
  689. }
  690. });
  691. watch(
  692. () => props.isPhoto,
  693. (newValue) => {
  694. tabValue.value = newValue;
  695. let child = document.querySelectorAll(".circel-name");
  696. if (child) {
  697. child.forEach((item) => {
  698. item.remove();
  699. });
  700. }
  701. if (listData2.value != null && tabValue.value == "photo") {
  702. nextTick(() => {
  703. removeLine2();
  704. clickResetLine2();
  705. setLine2();
  706. newPositionLine2(leaderLines2.value);
  707. getIedChild();
  708. getNetworkInfo();
  709. });
  710. }
  711. }
  712. );
  713. watch(
  714. () => props.checkData,
  715. (newValue) => {
  716. let child = document.querySelectorAll(".circel-name");
  717. if (child) {
  718. child.forEach((item) => {
  719. item.remove();
  720. });
  721. }
  722. listData2.value = [];
  723. svInfo.value = [];
  724. listData2.value = newValue;
  725. if (newValue != null && tabValue.value == "photo") {
  726. getIedChild();
  727. clickResetLine2();
  728. getNetworkInfo();
  729. }
  730. emit("result", newValue);
  731. if (newValue && leaderLines2.value.length > 0) {
  732. leaderLines2.value = [];
  733. }
  734. }
  735. );
  736. watch(
  737. () => props.isOpen,
  738. (newValue) => {
  739. if (newValue) {
  740. domList2.value.clear();
  741. domListRight2.value.clear();
  742. domListMiddle2.value.clear();
  743. domListLeftChild2.value.clear();
  744. domListRightChild2.value.clear();
  745. leaderLines2.value = [];
  746. } else {
  747. nextTick(() => {
  748. removeLine2();
  749. });
  750. }
  751. }
  752. );
  753. watch(
  754. () => listData2.value,
  755. (newValue) => {
  756. emit("result", newValue);
  757. clickResetLine2();
  758. }
  759. );
  760. </script>
  761. <style lang="scss" scoped>
  762. @mixin img-size {
  763. width: 150px;
  764. height: 90px;
  765. margin-bottom: 10px;
  766. }
  767. @mixin left-and-right {
  768. display: flex;
  769. flex-direction: column;
  770. }
  771. .main-cont {
  772. margin-top: 10px;
  773. display: flex;
  774. justify-content: space-evenly;
  775. }
  776. .leader-line {
  777. z-index: 3000;
  778. }
  779. .main-left {
  780. display: flex;
  781. @include left-and-right;
  782. }
  783. .main-middle {
  784. box-sizing: border-box;
  785. border: 2px dashed #98a8ff;
  786. background: #edf3ff;
  787. img {
  788. margin-bottom: 10px;
  789. }
  790. .middle-item {
  791. @include left-and-right;
  792. align-items: center;
  793. cursor: pointer;
  794. }
  795. .middle-title {
  796. margin: 12px;
  797. text-align: center;
  798. color: #ffcb11;
  799. border-bottom: 1px solid #a3ade0;
  800. }
  801. }
  802. .main-right {
  803. display: flex;
  804. @include left-and-right;
  805. .img-item {
  806. @include img-size;
  807. }
  808. }
  809. .conts {
  810. position: relative;
  811. @include left-and-right;
  812. margin-bottom: 24px;
  813. border: 2px dashed #98a8ff;
  814. cursor: pointer;
  815. background: #f7f8fb;
  816. .cont-item {
  817. @include left-and-right;
  818. color: #1a2447;
  819. align-items: center;
  820. margin: 12px 14px 5px 14px;
  821. border-bottom: 1px solid #a3ade0;
  822. }
  823. .ied-desc {
  824. color: #255ce7;
  825. }
  826. .ied-desc-title {
  827. color: #134bea;
  828. }
  829. .ied-desc-child-title {
  830. color: #5182ff;
  831. margin-left: 14px;
  832. display: block;
  833. }
  834. }
  835. .ied-desc-child,
  836. .midlestyle {
  837. @include left-and-right;
  838. align-items: center;
  839. border: 1px solid #7484ab;
  840. border-radius: 2px;
  841. margin: 12px 14px;
  842. padding: 5px;
  843. color: #1a2447;
  844. position: relative;
  845. }
  846. #wrapper {
  847. width: 0;
  848. height: 0;
  849. position: relative; /* Origin of coordinates for lines, and scrolled content (i.e. not `absolute`) */
  850. }
  851. .smv-color {
  852. color: red;
  853. border: 1px solid red;
  854. }
  855. </style>