scdTree.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. <template>
  2. <div>
  3. <div class="btnBox">
  4. <div @click="checkNow">
  5. <img :src="addPng" alt="" />
  6. <span>新的比对</span>
  7. </div>
  8. <div @click="reloadCheck">
  9. <img :src="againPng" alt="" />
  10. <span>重新比对</span>
  11. </div>
  12. <div @click="excelPort">
  13. <img :src="dervicePng" alt="" />
  14. <span>导出所有结果</span>
  15. </div>
  16. </div>
  17. <div class="tableBox">
  18. <el-table
  19. ref="multipleTable"
  20. :data="tableList"
  21. style="width: 100%; height: calc(100vh - 320px)"
  22. stripe
  23. @select="select"
  24. :header-cell-style="{
  25. background: '#F7F8FB !important',
  26. color: '#7484AB',
  27. borderBottom: '1px solid #A3ADE0 !important',
  28. fontWeight: '400',
  29. }"
  30. >
  31. <el-table-column width="55" type="selection" />
  32. <el-table-column
  33. label="对比scd"
  34. width="190"
  35. :show-overflow-tooltip="true"
  36. >
  37. <template #default="scope">{{ scope.row.name }}</template>
  38. </el-table-column>
  39. <el-table-column
  40. property="CREATED_TIME"
  41. label="时间"
  42. width="auto"
  43. :show-overflow-tooltip="true"
  44. />
  45. <el-table-column fixed="right" label="操作" width="120">
  46. <template #default="scope">
  47. <el-button
  48. link
  49. type="primary"
  50. size="small"
  51. @click="searchScdCheck(scope.row)"
  52. ><el-icon> <View /> </el-icon>查看</el-button
  53. >
  54. </template>
  55. </el-table-column>
  56. </el-table>
  57. </div>
  58. <!-- <div>新的对比
  59. <LookScd
  60. v-if="lookScdModal"
  61. :lookScdModal="lookScdModal"
  62. :aktType="aktType"
  63. @lookScdBack="lookScdBack"
  64. >
  65. </LookScd>
  66. </div> -->
  67. <!-- 新的对比弹窗 -->
  68. <el-dialog
  69. @close="cancelClick"
  70. v-model="lookScdModal"
  71. width="30vw"
  72. style="height: 400px"
  73. append-to-body
  74. draggable
  75. >
  76. <template #header>
  77. <div class="my-header">
  78. <div class="title">请选择对比的SCD文件</div>
  79. </div>
  80. </template>
  81. <div
  82. class="uploda-file"
  83. v-loading="loadingAdd"
  84. element-loading-text="上传文件中..."
  85. >
  86. <span class="file-title">选择文件</span>
  87. <el-input
  88. v-model="chooseFile"
  89. class="w-50 m-2"
  90. placeholder="点击右侧按钮上传文件"
  91. clearable
  92. @clear="clearFile"
  93. >
  94. <template #suffix>
  95. <img
  96. v-if="chooseFile"
  97. :src="uploadSPng"
  98. alt=""
  99. style="width: 20px; height: 20px"
  100. />
  101. <img
  102. v-if="loadingAddError"
  103. :src="uploadEPng"
  104. alt=""
  105. style="width: 20px; height: 20px"
  106. />
  107. </template>
  108. </el-input>
  109. <el-upload
  110. v-model:file-list="fileList"
  111. :limit="1"
  112. class="upload-demo"
  113. :http-request="uploadFile"
  114. :on-exceed="exceed"
  115. :show-file-list="false"
  116. :disabled="isLoadingNew"
  117. >
  118. <template #trigger>
  119. <div class="upload-title">
  120. <img :src="uploadPng" alt="" />
  121. <span>上传文件</span>
  122. </div>
  123. </template>
  124. </el-upload>
  125. </div>
  126. <div class="sure-file">
  127. <div v-if="!isAnalysis && AnalysisProcess" class="analysis success">
  128. 文件解析完成
  129. </div>
  130. <div v-else-if="isAnalysis && AnalysisProcess" class="analysis fail">
  131. 文件解析失败
  132. </div>
  133. <div v-if="chooseFile && !AnalysisProcess" class="analysis">
  134. 文件正在解析中,请等待...
  135. </div>
  136. <!-- <div
  137. class="sures"
  138. :class="{ 'sures-success': !isAnalysis && AnalysisProcess }"
  139. >
  140. 确认上传
  141. </div> -->
  142. <div
  143. class="sures sures-success"
  144. v-if="!isAnalysis && AnalysisProcess && !isLoadingNew"
  145. @click="yesAnalysisClick"
  146. >
  147. 开始对比
  148. </div>
  149. <div class="sures" v-else @click="noAnalysisClick">开始对比</div>
  150. </div>
  151. </el-dialog>
  152. <!-- 导出所有结果 -->
  153. <el-dialog
  154. v-model="exportModal"
  155. width="25vw"
  156. style="height: 200px"
  157. append-to-body
  158. draggable
  159. @close="closeExport"
  160. >
  161. <template #header>
  162. <div class="my-header">
  163. <div class="title">数据导出</div>
  164. </div>
  165. </template>
  166. <div v-if="!exportLink" class="export-ink">请稍等,正在导出数据中...</div>
  167. <div v-else class="export-ink">
  168. 数据文件已生成完成,
  169. <el-link :href="exportLink" type="primary" class="load"
  170. >点击立即下载</el-link
  171. >
  172. </div>
  173. </el-dialog>
  174. </div>
  175. </template>
  176. <script setup>
  177. import { ref, onMounted, watch, defineEmits, onUnmounted } from "vue";
  178. import scdCheck from "@/api/scdCheck/scdCheck";
  179. import {
  180. uploadfile,
  181. tmpParse,
  182. compStart,
  183. compstatView,
  184. scdExpTableData,
  185. } from "@/api/scdCheck/scdCheck2";
  186. import {
  187. ElMessage,
  188. ElLoading,
  189. ElMessageBox,
  190. ElNotification,
  191. } from "element-plus";
  192. import dervicePng from "@/assets/image/scdcheck/derive.png";
  193. import againPng from "@/assets/image/scdcheck/again.png";
  194. import addPng from "@/assets/image/scdcheck/add.png";
  195. import uploadPng from "@/assets/image/scdcheck/upload.png";
  196. import uploadSPng from "@/assets/image/scdcheck/upload_success.png";
  197. import uploadEPng from "@/assets/image/scdcheck/upload_error.png";
  198. import { useRoute } from "vue-router";
  199. import createds from "@/utils/scdMqtt.js";
  200. const route = useRoute();
  201. const emit = defineEmits(["scdTreeBack", "scdView", "scdJpadList"]);
  202. let tableList = ref([]);
  203. let multipleTable = ref();
  204. let lookScdArr = ref([]);
  205. let lookScdModal = ref(false);
  206. const fileList = ref([]); //上传的文件
  207. const loadingAdd = ref(false); //文件上传的加载状态
  208. const loadingAddError = ref(false); //文件上传的加载状态
  209. const chooseFile = ref("");
  210. const chooseContrast = ref(null);
  211. const checkNow = (e) => {
  212. tipsLoading();
  213. if(isLoadingNew.value) return;
  214. //scd比对
  215. results();
  216. };
  217. const tipsLoading = () => {
  218. if (isLoadingNew.value) {
  219. return ElMessage({
  220. type: "warning",
  221. message: "正在进行新的对比!",
  222. });
  223. }
  224. };
  225. const isLoadingNew = ref(false); //是否正在进行新的对比,还未结束
  226. const results = () => {
  227. lookScdModal.value = true;
  228. contrast.value = false;
  229. chooseContrast.value = null;
  230. AnalysisProcess.value = false;
  231. isAnalysis.value = false;
  232. chooseFile.value = "";
  233. exportLink.value = "";
  234. };
  235. //关闭弹窗的时候清楚掉选择的列表
  236. const closeExport = () => {
  237. chooseContrast.value = null;
  238. multipleTable.value.clearSelection();
  239. };
  240. const exportModal = ref(false);
  241. const exportLink = ref("");
  242. const excelPort = () => {
  243. tipsLoading();
  244. if (isLoadingNew.value) return;
  245. exportLink.value = "";
  246. if (!chooseContrast.value) {
  247. return ElMessage({
  248. type: "warning",
  249. message: "请选择一条历史校验记录或创建新一致性校验!",
  250. });
  251. }
  252. exportModal.value = true;
  253. //导出excel
  254. scdExpTableData({
  255. code: "scd-comp-result",
  256. caption: "SCD一致性对比结果",
  257. expcols:
  258. "source_scd_name,target_scd_name,ied_name,ied_desc,opt,diff_object_type,diff_object_name,desc",
  259. expcolnames:
  260. "基准SCD,目标比对SCD,装置名称,装置描述,操作,比对内容类型,差异项,差异内容",
  261. comp_id: chooseContrast.value.id,
  262. }).then((res) => {
  263. if (res.data) {
  264. exportLink.value = window.ApiServer + "/" + res.data;
  265. } else {
  266. ElMessage({
  267. message: res.msg,
  268. type: "info",
  269. });
  270. }
  271. });
  272. };
  273. const contrast = ref(false); //是否是重新对比
  274. const reloadCheck = async () => {
  275. tipsLoading();
  276. if (isLoadingNew.value) return;
  277. contrast.value = true;
  278. mesg.value = null;
  279. //重新比对
  280. if (!chooseContrast.value) {
  281. ElMessage({
  282. type: "warning",
  283. message: "请选择一条历史校验记录或创建新一致性校验!",
  284. });
  285. } else {
  286. yesAnalysisClick();
  287. }
  288. };
  289. const exceed = (files) => {
  290. if (fileList.value.length > 0) {
  291. ElMessage({
  292. type: "warning",
  293. message: "请清除选择文件后重新选择!",
  294. });
  295. }
  296. };
  297. const uploadFile = async (e) => {
  298. fileList.value = [];
  299. chooseFile.value = "";
  300. loadingAddError.value = false;
  301. loadingAdd.value = true;
  302. const fileRes = await uploadfile({
  303. file: e.file,
  304. station_id: route.query.stationId,
  305. is_checkin: 0,
  306. data_type: "a_scd",
  307. });
  308. if (fileRes&&fileRes.code == 0) {
  309. fileList.value.push(fileRes.data);
  310. chooseFile.value = fileRes.data.filename;
  311. loadingAdd.value = false;
  312. ElMessage({
  313. type: "success",
  314. message: "上传成功!",
  315. });
  316. const resParse = await tmpParse({
  317. station_id: route.query.stationId,
  318. scd_name: fileRes.data.filename,
  319. scd_path: fileRes.data.path,
  320. });
  321. startMqtt(`/jujutong/scd_check_tools/parse/#`);
  322. } else {
  323. loadingAdd.value = false;
  324. loadingAddError.value = true;
  325. ElMessage({
  326. type: "error",
  327. message: "上传失败!",
  328. });
  329. }
  330. };
  331. //查看scd对比
  332. let data = {};
  333. const searchScdCheck = async (row) => {
  334. data = {};
  335. data = row;
  336. emit("scdView", data);
  337. const loading = ElLoading.service({
  338. lock: true,
  339. text: "正在查询数据",
  340. background: "rgba(0, 0, 0, 0.7)",
  341. });
  342. const res = await compstatView({
  343. comp_id: row.id,
  344. });
  345. if (res&&res.code == 0) {
  346. emit("scdJpadList", res.data);
  347. loading.close();
  348. }
  349. };
  350. const lookScdBack = (data, row) => {
  351. //选择scd文件模态框返回数据
  352. lookScdModal.value = data;
  353. lookScdArr.value = row;
  354. emit("scdTreeBack", lookScdArr.value);
  355. };
  356. const aktType = () => {
  357. //初始化数据
  358. scdCheck
  359. .flashStationDui({ station_id: route.query.stationId })
  360. .then((res) => {
  361. //获取差异纪录列表
  362. if(!res) return;
  363. tableList.value = res.data;
  364. });
  365. };
  366. // mqtt=======
  367. const PublicMqtt = ref(null);
  368. const mesg = ref(null); //订阅成功的消息
  369. const isAnalysis = ref(false); //解析是否成功
  370. const AnalysisProcess = ref(false); //解析是否完成
  371. const startMqtt = (val) => {
  372. //val = 订阅地址
  373. //设置订阅地址checkNo
  374. PublicMqtt.value = new createds(val);
  375. //初始化mqtt
  376. PublicMqtt.value.init();
  377. //链接mqtt
  378. PublicMqtt.value.link();
  379. getMessage();
  380. };
  381. //获取订阅数据
  382. const getMessage = () => {
  383. PublicMqtt.value.client.on("message", (topic, message) => {
  384. // topic包含error就表示解析错误,message此时就是错误信息
  385. AnalysisProcess.value = true;
  386. mesg.value = JSON.parse(message.toString());
  387. if (topic.includes("error")) {
  388. isAnalysis.value = true;
  389. ElMessage({
  390. type: "error",
  391. message: mesg.value,
  392. });
  393. } else {
  394. isAnalysis.value = false;
  395. contrast.value = false;
  396. }
  397. });
  398. };
  399. //取消MQTT订阅
  400. const unsubscribe = () => {
  401. //如果页面并没有初始化MQTT,无需取消订阅
  402. if (PublicMqtt.value) {
  403. PublicMqtt.value.unsubscribes();
  404. }
  405. };
  406. onUnmounted(() => {
  407. //页面销毁结束订阅
  408. if (PublicMqtt.value) {
  409. PublicMqtt.value.unsubscribes();
  410. PublicMqtt.value.over();
  411. }
  412. });
  413. // mqtt=======
  414. // 取消弹窗
  415. const cancelClick = () => {
  416. loadingAddError.value = false;
  417. loadingAdd.value = false;
  418. AnalysisProcess.value = false;
  419. unsubscribe();
  420. };
  421. //点击输入框中的清除按钮
  422. const clearFile = () => {
  423. fileList.value = [];
  424. AnalysisProcess.value = false;
  425. unsubscribe();
  426. };
  427. watch(
  428. () => chooseFile.value,
  429. (newValue) => {
  430. if (!newValue) {
  431. fileList.value = [];
  432. }
  433. }
  434. );
  435. //解析完成开始对比的点击
  436. const yesAnalysisClick = () => {
  437. ElMessageBox.confirm(
  438. "该操作耗时较长,校验开始后将清除原有校验结果且无法中止,确定开始吗?",
  439. "Warning",
  440. {
  441. confirmButtonText: "确定",
  442. cancelButtonText: "取消",
  443. type: "warning",
  444. }
  445. )
  446. .then(async () => {
  447. ElNotification({
  448. title: "信息",
  449. message: "正在进行SCD的一致性比对...请稍候",
  450. duration: 0,
  451. });
  452. isLoadingNew.value = true;
  453. let anRes;
  454. if (mesg.value && !contrast.value) {
  455. anRes = await compStart({
  456. type: "SCD",
  457. station_id: route.query.stationId,
  458. source_scd_id: route.query.id,
  459. target_scd_id: mesg.value.rootid,
  460. comp_id: 0,
  461. });
  462. } else if (chooseContrast.value) {
  463. anRes = await compStart({
  464. type: "SCD",
  465. station_id: route.query.stationId,
  466. source_scd_id: chooseContrast.value.source_id,
  467. target_scd_id: chooseContrast.value.target_id,
  468. comp_id: chooseContrast.value.id,
  469. });
  470. }
  471. if (anRes&&anRes.code == 0) {
  472. loadingAdd.value = false;
  473. aktType();
  474. ElMessage({
  475. type: "success",
  476. message: "对比完成!",
  477. });
  478. ElNotification.closeAll();
  479. isLoadingNew.value = false;
  480. lookScdModal.value = false;
  481. } else {
  482. ElMessage({
  483. type: "error",
  484. message: err.msg,
  485. });
  486. }
  487. })
  488. .catch((err) => {});
  489. };
  490. //解析失败或未完成开始对比的点击
  491. const noAnalysisClick = () => {
  492. if (isLoadingNew.value) {
  493. ElMessage({
  494. type: "warning",
  495. message: "正在对比中!",
  496. });
  497. } else {
  498. ElMessage({
  499. type: "warning",
  500. message: "请上传文件并等待文件解析完成!",
  501. });
  502. }
  503. };
  504. const parentData = ref(null);
  505. const isDelete = ref(true);
  506. // 表格单选操作
  507. const select = (selection, row) => {
  508. multipleTable.value.clearSelection();
  509. // 主要用于将当前勾选的表格状态清除;
  510. // 当表格数据都没有被勾选的时候就返回;
  511. if (selection.length == 0) {
  512. isDelete.value = true;
  513. return;
  514. }
  515. chooseContrast.value = row;
  516. multipleTable.value.toggleRowSelection(row, true);
  517. isDelete.value = false;
  518. };
  519. onMounted(async () => {
  520. parentData.value = JSON.parse(route.query.parentData);
  521. aktType();
  522. });
  523. </script>
  524. <style scoped lang="scss">
  525. .btnBox > div,
  526. .upload-title {
  527. height: 50px;
  528. display: flex;
  529. align-items: center;
  530. justify-content: center;
  531. margin-right: 8px;
  532. cursor: pointer;
  533. background: url("~@/assets/image/scdcheck/bgscd.png") no-repeat center;
  534. border-radius: 2px;
  535. font-size: 14px;
  536. color: #255ce7;
  537. img {
  538. width: 20px;
  539. height: 20px;
  540. margin: 0 4px 0 0;
  541. }
  542. }
  543. .upload-title {
  544. width: 102px;
  545. background-size: 103px 50px;
  546. margin-top: 4px;
  547. }
  548. .btnBox {
  549. display: flex;
  550. margin-bottom: 12px;
  551. & > div:first-child,
  552. & > div:nth-child(2) {
  553. width: 102px;
  554. background-size: 102px 45px;
  555. }
  556. & > div:last-child {
  557. width: 128px;
  558. background-size: 128px 45px;
  559. }
  560. }
  561. .my-header {
  562. border-bottom: 1px solid #a3ade0;
  563. font-size: 16px;
  564. color: #1a2447;
  565. .title {
  566. padding-bottom: 15px;
  567. }
  568. }
  569. .uploda-file {
  570. display: flex;
  571. align-items: center;
  572. }
  573. .upload-demo {
  574. display: flex;
  575. }
  576. .sure-file {
  577. display: flex;
  578. flex-direction: column;
  579. justify-content: center;
  580. align-items: center;
  581. }
  582. .sures {
  583. background: #dfe8ff;
  584. margin-left: 60px;
  585. color: #fff;
  586. width: 124px;
  587. height: 32px;
  588. margin-top: 60px;
  589. line-height: 32px;
  590. text-align: center;
  591. cursor: pointer;
  592. }
  593. .sures-success {
  594. background: #255ce7;
  595. }
  596. .export-ink {
  597. display: flex;
  598. text-align: center;
  599. justify-content: center;
  600. .load {
  601. margin-left: 10px;
  602. border-bottom: 1px solid #409eff;
  603. }
  604. }
  605. .file-title {
  606. width: 90px;
  607. color: #1a2447;
  608. font-size: 14px;
  609. margin-right: 8px;
  610. }
  611. :deep(.el-input__wrapper) {
  612. height: 38px;
  613. border: 1px solid #a3ade0;
  614. }
  615. .analysis {
  616. margin-left: 67px;
  617. margin-top: 10px;
  618. color: #255ce7;
  619. }
  620. .analysis.success {
  621. color: #3be078;
  622. }
  623. .analysis.fail {
  624. color: #e50505;
  625. }
  626. :deep(.el-message-box) {
  627. vertical-align: inherit !important;
  628. } // 取消多选第一列的展示(即:将多选变成单选的第一步); 取消该样式后,就不会出现多选的情况;但由此可知还有其他的方法来实现单选;
  629. ::v-deep(.el-table th.el-table__cell:nth-child(1) .cell) {
  630. visibility: hidden;
  631. }
  632. </style>