CidTree.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. <template>
  2. <div>
  3. <div class="bigBox" :class="{ bigBoxUp: isUPdate == 'update' }">
  4. <div>
  5. <div class="titles">
  6. <img
  7. style="width: 20px; height: 20px"
  8. src="../../../assets/icon/HardDrives.png"
  9. alt=""
  10. />
  11. <div>装置列表</div>
  12. </div>
  13. </div>
  14. <div class="tagBox">
  15. <div
  16. class="cont-line tagP"
  17. :class="{ clicktag: tagChoose == index }"
  18. v-for="(item, index) in tagList"
  19. :key="index"
  20. @click="tagClick(item, index)"
  21. >
  22. <span v-if="!OpensclTrue">{{
  23. `(${item.ied_name})${item.desc}`
  24. }}</span>
  25. <span v-else>{{ `(${item.ied_name})${item.ied_desc}` }}</span>
  26. </div>
  27. </div>
  28. <div class="setting">
  29. <el-tree
  30. :data="treeData"
  31. :props="defaultProps"
  32. highlight-current
  33. @node-click="handleNodeClick"
  34. >
  35. <template #default="{ node, data }">
  36. <span class="label" :class="{ 'tree-label': node.expanded }">{{
  37. node.label
  38. }}</span
  39. ><span
  40. :class="{ 'tree-label': clickItemcode == data.itemcode }"
  41. style="position: absolute; right: 10px"
  42. ><span v-if="OpensclTrue">{{ data.num }}</span
  43. ><span v-else>{{ data.num }}</span></span
  44. >
  45. </template>
  46. </el-tree>
  47. </div>
  48. </div>
  49. </div>
  50. </template>
  51. <script setup>
  52. import { ref, onMounted, toRefs, watch } from "vue";
  53. import cid from "@/api/cid/cid";
  54. import scdCheck from "@/api/scdCheck/scdCheck";
  55. import { compIedstatType } from "@/api/scdCheck/scdCheck2";
  56. import { useRoute } from "vue-router";
  57. const route = useRoute();
  58. const props = defineProps({
  59. OpensclTrue: {
  60. type: Boolean,
  61. default: false,
  62. },
  63. iedRelation: {
  64. type: Object,
  65. default: () => {},
  66. },
  67. UPdate: {
  68. //判断是否是点击更改 进入的界面
  69. type: String,
  70. default: "",
  71. },
  72. clickRowDatas: {
  73. type: Object,
  74. default: () => {},
  75. },
  76. allCidStart: {
  77. type: Array,
  78. default: () => [],
  79. },
  80. });
  81. const emit = defineEmits(["treeBack", "clickCode", "treeBackDefalut"]);
  82. let tagList = ref(props.iedRelation);
  83. const loading = ref(true);
  84. let tagChoose = ref("");
  85. let treeData = ref([
  86. {
  87. label: "装置信息",
  88. itemcode: "ied",
  89. num: 0,
  90. children: [
  91. {
  92. label: "基本信息",
  93. itemcode: "scd.ied",
  94. num: 0,
  95. },
  96. ],
  97. },
  98. {
  99. label: "通信参数",
  100. itemcode: "Communication",
  101. num: 0,
  102. children: [
  103. {
  104. label: "通信接入点",
  105. itemcode: "scd.ied.Communication",
  106. num: 0,
  107. },
  108. {
  109. label: "站控层通信参数",
  110. itemcode: "scd.ied.Communication.S1",
  111. num: 0,
  112. },
  113. {
  114. label: "GOOSE 通信参数",
  115. itemcode: "scd.ied.Communication.GSE",
  116. num: 0,
  117. },
  118. { label: "SV 通信参数", itemcode: "scd.ied.Communication.SMV", num: 0 },
  119. ],
  120. },
  121. {
  122. label: "测点信息",
  123. itemcode: "Point",
  124. num: 0,
  125. children: [
  126. {
  127. label: "遥信",
  128. itemcode: "scd.ied.YX",
  129. num: 0,
  130. },
  131. {
  132. label: "遥控",
  133. itemcode: "scd.ied.YK",
  134. num: 0,
  135. },
  136. {
  137. label: "遥测",
  138. itemcode: "scd.ied.YC",
  139. num: 0,
  140. },
  141. {
  142. label: "遥脉",
  143. num: 0,
  144. itemcode: "scd.ied.YM",
  145. },
  146. {
  147. label: "定值",
  148. itemcode: "scd.ied.DZ",
  149. num: 0,
  150. },
  151. ],
  152. },
  153. {
  154. label: "回路配置",
  155. itemcode: "config",
  156. num: 0,
  157. children: [
  158. {
  159. label: "发布虚端子",
  160. itemcode: "scd.ied.FCDA",
  161. num: 0,
  162. },
  163. {
  164. label: "定阅虚端子",
  165. itemcode: "scd.ied.ExtRef",
  166. num: 0,
  167. },
  168. {
  169. label: "虚回路信息",
  170. itemcode: "scd.ied.Relation",
  171. num: 0,
  172. },
  173. ],
  174. },
  175. {
  176. label: "建模信息",
  177. itemcode: "model",
  178. num: 0,
  179. children: [
  180. {
  181. label: "数据集",
  182. itemcode: "scd.ied.DatSet",
  183. num: 0,
  184. },
  185. {
  186. label: "数据集成员",
  187. itemcode: "scd.ied.DatSetMeber",
  188. num: 0,
  189. },
  190. {
  191. label: "GOOSE控制块",
  192. itemcode: "scd.ied.GSEControl",
  193. num: 0,
  194. },
  195. {
  196. label: "SV控制块",
  197. itemcode: "scd.ied.SampledValueControl",
  198. num: 0,
  199. },
  200. {
  201. label: "报告控制块",
  202. itemcode: "scd.ied.ReportControl",
  203. num: 0,
  204. },
  205. {
  206. label: "日志控制块",
  207. itemcode: "scd.ied.LogControl",
  208. num: 0,
  209. },
  210. ],
  211. },
  212. ]);
  213. let needName = ref("");
  214. //得到差异项code的数字数据
  215. const codeStatic = async () => {
  216. const ids = clickRow.value ? clickRow.value.id : "";
  217. const names = clickTage.value ? clickTage.value.ied_name : "";
  218. const res = await compIedstatType({
  219. comp_id: ids,
  220. ied_name: names,
  221. comptype: "u",
  222. });
  223. if(!res) return;
  224. updateNum(treeData.value, res.data);
  225. };
  226. const updateNum = (treeNode, data) => {
  227. for (let node of treeNode) {
  228. node.num = 0;
  229. // 检查当前节点的 itemcode 是否在 data 中
  230. if (data && data.hasOwnProperty(node.itemcode)) {
  231. node.num = parseInt(data[node.itemcode]);
  232. }
  233. if (data && node.itemcode == "scd.ied.Relation"&&data["scd.ied.ExtRef"]) {
  234. node.num = parseInt(data["scd.ied.ExtRef"]);
  235. }
  236. // 如果当前节点有子节点,递归处理子节点
  237. if (node.children) {
  238. updateNum(node.children, data);
  239. // 计算父级节点的num是子节点num的和
  240. node.num = node.children
  241. .filter((child) => child.itemcode !== "scd.ied.Relation")
  242. .reduce((total, child) => total + child.num, 0);
  243. }
  244. }
  245. loading.value = false
  246. };
  247. let defaultProps = ref({
  248. label: "label",
  249. children: "children",
  250. num: "num",
  251. });
  252. const isUPdate = ref(props.UPdate);
  253. watch(
  254. () => props.UPdate,
  255. (newValue) => {
  256. isUPdate.value = newValue;
  257. }
  258. );
  259. watch(
  260. () => props.iedRelation, //点击SCD文件一致性校核,点击查看,点击修改进如的装置列表
  261. (newValue) => {
  262. if (newValue) {
  263. tagList.value = newValue;
  264. }
  265. }
  266. );
  267. const allCidStartProps = ref(null);
  268. watch(
  269. //CID一致性校验左侧的数据处理
  270. () => props.allCidStart,
  271. (newValue) => {
  272. if (newValue && newValue.length) {
  273. allCidStartProps.value = newValue;
  274. treeData.value.forEach((node) => {
  275. addChildItems(node, newValue);
  276. });
  277. }
  278. }
  279. );
  280. //Cid使用递归
  281. const addChildItems = (node, data) => {
  282. if (!node.childItemCid) {
  283. node.childItemCid = [];
  284. }
  285. data.forEach((item) => {
  286. if (node.itemcode === item.diff_object_type) {
  287. let text;
  288. text = item.diff_desc.replace(/[\r|\n|\t]/g, ""); //处理返回的数据中换行等,整理好规整数据
  289. item.diff_desc = JSON.parse(text);
  290. node.childItemCid.push(item);
  291. }
  292. });
  293. if (node.children) {
  294. node.children.forEach((childNode) => {
  295. addChildItems(childNode, data);
  296. });
  297. // 计算并设置 num 值
  298. let childrenNum = 0;
  299. node.children.forEach((childNode) => {
  300. childrenNum += childNode.childItemCid.length;
  301. });
  302. node.num = childrenNum;
  303. } else {
  304. node.num = node.childItemCid.length;
  305. }
  306. };
  307. const reload = () => {
  308. if (!props.OpensclTrue) {
  309. //网络结构体点击CID一致性校核打开获取的装置列表
  310. cid.getAll({ scd_id: route.query.id, ied_name: "" }).then((res) => {
  311. tagList.value = res.data;
  312. tagChoose.value = res.data ? Object.keys(res.data)[0] : "";
  313. clickTage.value = res.data ? Object.values(res.data)[0] : "";
  314. emit("treeBack", clickTage.value)
  315. });
  316. }
  317. };
  318. const clickTage = ref(null);
  319. const tagClick = (row, num) => {
  320. loading.value = true;
  321. treeData.value.forEach(item=>{
  322. item.num = 0;
  323. item.childItemCid = [];
  324. if(item.children){
  325. item.children.forEach(key=>{
  326. key.num=0;
  327. key.childItemCid = [];
  328. })
  329. }
  330. })
  331. tagChoose.value = num;
  332. clickTage.value = row;
  333. emit("treeBack", row)
  334. // cid
  335. // .findFile({
  336. // scd_id: route.query.id,
  337. // ied_name: row.desc,
  338. // pageno: 1,
  339. // pagesize: 10,
  340. // station_id: route.query.stationId,
  341. // })
  342. // .then((res) => {});
  343. // scdCheck
  344. // .lookCheck({
  345. // pageindex: 1,
  346. // pagesize: 10,
  347. // station_id: route.query.stationId,
  348. // scd_id: route.query.id,
  349. // is_checkin: 2,
  350. // ied_name: row.ied_name,
  351. // })
  352. // .then((res) => {
  353. // let fileInfo;
  354. // if (res.data) {
  355. // fileInfo = res.data.filter((item) => item.scd_id == route.query.id);
  356. // if (fileInfo.length > 0) {
  357. // emit("treeBack", row, fileInfo[0]);
  358. // }
  359. // }
  360. // let a = res.data.filter((item) => item.type_name == "CID");
  361. // if (a.length > 0) {
  362. // needName.value = a[0].file_name;
  363. // emit("treeBack", needName.value, a[0].id);
  364. // }
  365. // });
  366. if (props.OpensclTrue) {
  367. codeStatic();
  368. }
  369. };
  370. const clickRow = ref(props.clickRowDatas);
  371. //对比文件:头部对比的单个数据
  372. watch(
  373. () => props.clickRowDatas,
  374. (newValue) => {
  375. if (newValue) {
  376. clickRow.value = newValue;
  377. }
  378. }
  379. );
  380. const clickItemcode = ref("");
  381. const handleNodeClick = (e) => {
  382. clickItemcode.value = e.itemcode;
  383. emit("clickCode", e.itemcode, e);
  384. };
  385. onMounted(() => {
  386. tagChoose.value = props.iedRelation ? Object.keys(props.iedRelation)[0] : "";
  387. clickTage.value = props.iedRelation
  388. ? Object.values(props.iedRelation)[0]
  389. : "";
  390. emit("treeBackDefalut", clickTage.value);
  391. reload();
  392. if (props.OpensclTrue) {
  393. codeStatic();
  394. }
  395. });
  396. </script>
  397. <style scoped lang="scss">
  398. p,
  399. h3 {
  400. margin: 0;
  401. padding: 0;
  402. }
  403. .bigBox {
  404. width: 100%;
  405. height: calc(100vh - 280px);
  406. margin-top: 20px;
  407. border: 1px solid #a3ade0;
  408. border-radius: 2px;
  409. cursor: pointer;
  410. background: #f7f8fb;
  411. & > div:first-child {
  412. display: flex;
  413. justify-content: flex-start;
  414. align-items: center;
  415. color: #1a2447;
  416. margin: 16px 0 0 16px;
  417. }
  418. }
  419. .bigBoxUp {
  420. height: calc(100vh - 230px) !important;
  421. }
  422. :deep(.el-tree) {
  423. --el-fill-color-blank: #f7f8fb;
  424. }
  425. .tagBox {
  426. width: 92%;
  427. height: 45%;
  428. overflow-y: auto;
  429. margin: 8px 16px 0px 16px;
  430. }
  431. .tagP {
  432. overflow: hidden;
  433. text-overflow: ellipsis;
  434. white-space: nowrap;
  435. margin-top: 8px;
  436. font-size: 16px;
  437. }
  438. .setting {
  439. width: 92%;
  440. height: 45%;
  441. overflow-y: auto;
  442. border-top: 1px solid #a3ade0;
  443. margin: 2px auto;
  444. .label {
  445. padding: 5px 8px;
  446. }
  447. :deep(.el-tree--highlight-current .el-tree-node) {
  448. margin: 5px 0;
  449. color: #1a2447;
  450. }
  451. :deep(
  452. .el-tree--highlight-current
  453. .el-tree-node.is-current
  454. > .el-tree-node__content
  455. ) {
  456. background: transparent;
  457. }
  458. :deep(
  459. .el-tree--highlight-current
  460. .el-tree-node.is-current
  461. > .el-tree-node__content
  462. .label
  463. ) {
  464. color: #134bea;
  465. border: 1px solid #255ce7;
  466. background: #f6f9ff;
  467. }
  468. }
  469. .titles {
  470. display: flex;
  471. align-items: center;
  472. & > div {
  473. font-size: 16px;
  474. margin-left: 8px;
  475. vertical-align: middle;
  476. font-weight: bold;
  477. }
  478. }
  479. .cont-line,
  480. :deep(.el-tree-node__label) {
  481. color: #1a2447;
  482. font-size: 14px;
  483. }
  484. .clicktag {
  485. color: #255ce7;
  486. }
  487. .tree-label {
  488. color: #134bea;
  489. }
  490. </style>