assetssMag.vue 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360
  1. <template>
  2. <div class="global-variable">
  3. <div class="condition">
  4. <!-- <el-alert
  5. title="分析前请核对数据是否导入,点击查看是否导入即可查看"
  6. type="warning"
  7. show-icon
  8. >
  9. </el-alert> -->
  10. <el-form
  11. :inline="true"
  12. ref="ruleForm"
  13. :model="formInline"
  14. class="demo-form-inline"
  15. :rules="rules"
  16. >
  17. <el-form-item label="分析主题:" prop="analysisName">
  18. <el-input
  19. size="small"
  20. v-model="formInline.analysisName"
  21. placeholder="请输入分析主题"
  22. ></el-input>
  23. </el-form-item>
  24. <el-form-item label="风场名称:" prop="fieldName">
  25. <el-input
  26. size="small"
  27. v-model="formInline.fieldName"
  28. placeholder="请输入风场名称"
  29. ></el-input>
  30. </el-form-item>
  31. <el-form-item label="分析状态:" prop="analysisState">
  32. <el-select
  33. size="small"
  34. v-model="formInline.analysisState"
  35. placeholder="请选择分析状态"
  36. >
  37. <el-option
  38. v-for="item in options"
  39. :key="item.value"
  40. :label="item.label"
  41. :value="item.value"
  42. >
  43. </el-option>
  44. </el-select>
  45. </el-form-item>
  46. <el-form-item>
  47. <el-button type="primary" @click="() => fetchData()" size="small"
  48. >查询</el-button
  49. >
  50. <el-button @click="reset('ruleForm')" size="small">重置</el-button>
  51. </el-form-item>
  52. <el-form-item class="right-align">
  53. <el-button @click="Newanalyse" size="small">创建分析</el-button>
  54. <el-button
  55. @click="examine"
  56. size="small"
  57. v-hasPermi="['home:offlinedata']"
  58. >查看导入数据</el-button
  59. >
  60. <el-button
  61. @click="handleAutoAsstessList"
  62. size="small"
  63. v-hasPermi="['home:performance:autoAssetss']"
  64. >查看自动分析列表</el-button
  65. >
  66. <!-- <el-button @click="handleDownLoadChart" size="small">下载</el-button> -->
  67. </el-form-item>
  68. </el-form>
  69. <!-- <div class="progress" v-if="downloadDisabled">
  70. <div class="progressText">文档生成进度:</div>
  71. <el-progress
  72. :percentage="progressPercent"
  73. :color="colors"
  74. ></el-progress>
  75. </div> -->
  76. </div>
  77. <div class="list-page">
  78. <el-table
  79. class="center-align-table"
  80. :data="tableData"
  81. border
  82. :cell-style="rowStyle"
  83. >
  84. <el-table-column
  85. align="center"
  86. label="分析主题"
  87. prop="analysisName"
  88. min-width="200"
  89. fixed
  90. >
  91. <template slot-scope="scope">
  92. <el-tooltip
  93. class="item"
  94. effect="dark"
  95. :content="scope.row.sketch || '暂无分析简述'"
  96. placement="top"
  97. >
  98. <span>{{ scope.row.analysisName }}</span>
  99. </el-tooltip>
  100. </template>
  101. </el-table-column>
  102. <el-table-column
  103. align="center"
  104. prop="fieldName"
  105. label="风场名称"
  106. min-width="200"
  107. >
  108. </el-table-column>
  109. <el-table-column
  110. prop="loginName"
  111. align="center"
  112. label="分析状态"
  113. min-width="150"
  114. >
  115. <template slot-scope="scope">
  116. <span v-if="scope.row.analysisState == -1">未关联</span>
  117. <span
  118. v-else-if="
  119. scope.row.analysisState == 20 && scope.row.errState == 0
  120. "
  121. style="color: #f90"
  122. >分析中</span
  123. >
  124. <span
  125. v-else-if="
  126. scope.row.errState == 1 && scope.row.analysisState == 30
  127. "
  128. style="color: #f00"
  129. >分析异常</span
  130. >
  131. <span
  132. v-else-if="scope.row.analysisState == 30"
  133. style="color: #4caf50"
  134. >分析完成</span
  135. >
  136. <span
  137. v-else-if="scope.row.analysisState == 10"
  138. style="color: #4caf50"
  139. >排队中</span
  140. >
  141. <span v-else>/</span>
  142. </template>
  143. </el-table-column>
  144. <el-table-column
  145. prop="loginName"
  146. align="center"
  147. label="进度"
  148. min-width="150"
  149. >
  150. <template slot-scope="scope">
  151. <el-progress
  152. v-if="scope.row.analysisState == 20"
  153. :text-inside="true"
  154. :stroke-width="20"
  155. :percentage="scope.row.analysisProgress"
  156. :class="{
  157. 'indeterminate-progress': scope.row.analysisProgress < 100,
  158. 'animated-progress': true,
  159. }"
  160. ></el-progress>
  161. <span v-else>/</span>
  162. </template>
  163. </el-table-column>
  164. <el-table-column
  165. align="center"
  166. label="排队序号"
  167. prop="orderNum"
  168. min-width="200"
  169. >
  170. <template slot-scope="scope">
  171. <span> {{ scope.row.orderNum }}</span>
  172. </template>
  173. </el-table-column>
  174. <el-table-column
  175. align="center"
  176. label="数据类型名称"
  177. prop="dataTypeName"
  178. min-width="200"
  179. >
  180. </el-table-column>
  181. <el-table-column
  182. v-hasPermi="['home:performance:autoAssetss']"
  183. prop="onOffCall"
  184. align="center"
  185. label="自动分析状态"
  186. min-width="140"
  187. >
  188. <template slot-scope="scope">
  189. <span>
  190. {{
  191. scope.row.onOffCall == 0
  192. ? "暂停"
  193. : scope.row.onOffCall === 1
  194. ? "开启"
  195. : "/"
  196. }}</span
  197. >
  198. </template>
  199. </el-table-column>
  200. <el-table-column
  201. prop="roleName"
  202. align="center"
  203. label="异常信息"
  204. min-width="120"
  205. >
  206. <template slot-scope="scope">
  207. <el-button
  208. v-if="scope.row.errState == 1"
  209. @click="abnormalDialog(scope.row, '异常详情')"
  210. type="text"
  211. size="small"
  212. >异常详情</el-button
  213. >
  214. <span v-else>/</span>
  215. </template>
  216. </el-table-column>
  217. <el-table-column
  218. prop="roleName"
  219. align="center"
  220. label="分析记录"
  221. min-width="120"
  222. >
  223. <template slot-scope="scope">
  224. <!-- 分析完成 -->
  225. <el-button
  226. v-if="scope.row.analysisState == 30 && scope.row.errState !== 1"
  227. @click="handleAssetssDetail(scope.row, '1')"
  228. type="text"
  229. size="small"
  230. >分析详情</el-button
  231. >
  232. <!-- 分析中 -->
  233. <el-button
  234. v-else-if="
  235. scope.row.analysisState == 20 && scope.row.errState == 0
  236. "
  237. @click="handleAssetssDetail(scope.row, '0')"
  238. type="text"
  239. size="small"
  240. >分析详情</el-button
  241. >
  242. <span v-else>/</span>
  243. </template>
  244. </el-table-column>
  245. <el-table-column
  246. prop="reportVos"
  247. align="center"
  248. label="报告"
  249. min-width="120"
  250. >
  251. <template slot-scope="scope">
  252. <el-dropdown v-if="scope.row.reportVos.length > 0" trigger="click">
  253. <el-button type="text" size="small" class="el-dropdown-link">
  254. 查看报告
  255. </el-button>
  256. <el-dropdown-menu slot="dropdown">
  257. <el-dropdown-item
  258. v-for="val in scope.row.reportVos"
  259. class="reportItemVal"
  260. >
  261. <div class="reportLeft">
  262. <span>{{ val.reportName }}</span>
  263. </div>
  264. <div class="reportRight">
  265. <el-button
  266. type="text"
  267. size="small"
  268. @click="detailReportAssetss(val)"
  269. >
  270. 查看
  271. </el-button>
  272. <el-button
  273. type="text"
  274. size="small"
  275. @click="downLoadeAssetss(val)"
  276. >
  277. 下载
  278. </el-button>
  279. </div>
  280. </el-dropdown-item>
  281. </el-dropdown-menu>
  282. </el-dropdown>
  283. <span v-else>/</span>
  284. </template>
  285. </el-table-column>
  286. <el-table-column
  287. prop="dataStartTime"
  288. align="center"
  289. label="开始时间"
  290. min-width="230"
  291. >
  292. </el-table-column>
  293. <el-table-column
  294. prop="dataEndTime"
  295. align="center"
  296. label="结束时间"
  297. min-width="230"
  298. >
  299. </el-table-column>
  300. <el-table-column
  301. prop="transition"
  302. align="center"
  303. fixed="right"
  304. label="操作"
  305. min-width="300"
  306. >
  307. <template slot-scope="scope">
  308. <el-button
  309. @click="handleDownLoadChart(scope.row)"
  310. type="text"
  311. size="small"
  312. :disabled="downloadDisabled"
  313. v-if="
  314. (scope.row.errState == 1 && scope.row.analysisState == 30) ||
  315. scope.row.analysisState == 30
  316. "
  317. >
  318. 下载报告
  319. </el-button>
  320. <el-button
  321. @click="abnormalDialog(scope.row, '上传报告')"
  322. type="text"
  323. size="small"
  324. >上传报告</el-button
  325. >
  326. <el-button
  327. @click="handleAssetss(scope.row)"
  328. type="text"
  329. :disabled="
  330. (scope.row.analysisState == 20 && scope.row.errState == 0) ||
  331. scope.row.analysisState == 10
  332. "
  333. size="small"
  334. >分析</el-button
  335. >
  336. <el-button
  337. @click="abnormalDialog(scope.row, '机组异常记录')"
  338. type="text"
  339. size="small"
  340. >机组异常记录</el-button
  341. >
  342. <el-button
  343. v-if="scope.row.analysisState == 10"
  344. @click="insertQueue(scope.row, 1)"
  345. type="text"
  346. size="small"
  347. >插队</el-button
  348. >
  349. <el-button
  350. v-if="scope.row.analysisState == 10"
  351. @click="insertQueue(scope.row, 0)"
  352. type="text"
  353. size="small"
  354. >取消插队</el-button
  355. >
  356. </template>
  357. </el-table-column>
  358. </el-table>
  359. <div class="pagination-container">
  360. <el-pagination
  361. @current-change="handleCurrentChange"
  362. :current-page.sync="formInline.pageNum"
  363. layout="total, prev, pager, next"
  364. :page-size="formInline.pageSize"
  365. :total="formInline.totalSize"
  366. >
  367. </el-pagination>
  368. </div>
  369. </div>
  370. <!-- 弹出层 -->
  371. <!-- 异常信息 /机组异常记录 /上传报告-->
  372. <my-dialog
  373. :visible="dialogVisible"
  374. :title="title"
  375. :rowInfo="rowInfo"
  376. @confirm="handleConfirm"
  377. :errorInfo="errorInfo"
  378. @getTableList="fetchData"
  379. >
  380. <div slot="tableEl">
  381. <el-empty description="暂无数据"></el-empty>
  382. </div>
  383. </my-dialog>
  384. <!-- 查看报告详情 -->
  385. <el-dialog
  386. title="PDF 预览"
  387. :visible.sync="dialogReportVisible"
  388. :width="dialogWidth"
  389. class="pdfDialog"
  390. :before-close="handleCloses"
  391. >
  392. <span>
  393. <div
  394. style="
  395. float: right;
  396. color: #fff;
  397. cursor: pointer;
  398. position: absolute;
  399. left: 90%;
  400. top: 21px;
  401. "
  402. >
  403. <span
  404. v-if="dialogWidth === '80%'"
  405. @click="() => (dialogWidth = '100%')"
  406. >全屏查看</span
  407. >
  408. <span
  409. v-if="dialogWidth === '100%'"
  410. @click="() => (dialogWidth = '80%')"
  411. >还原</span
  412. >
  413. <!-- {{ isFullscreen ? "还原" : "全屏" }} -->
  414. </div>
  415. </span>
  416. <div class="pdf-container" ref="viewer">
  417. <iframe :src="pdfUrl" width="100%" height="100%"></iframe>
  418. </div>
  419. <div></div>
  420. </el-dialog>
  421. <!-- 创建分析弹出框 -->
  422. <el-dialog
  423. title="创建分析"
  424. :visible.sync="addDialogVisible"
  425. width="30%"
  426. :before-close="AddHandleCloses"
  427. >
  428. <el-form
  429. :model="addRuleForm"
  430. :rules="addRules"
  431. ref="addRuleForm"
  432. label-width="100px"
  433. class="add-ruleForm"
  434. >
  435. <el-form-item label="关联风场" prop="fieldCode">
  436. <el-select
  437. v-model="addRuleForm.fieldCode"
  438. placeholder="请选择关联风场"
  439. >
  440. <el-option
  441. :label="item.fieldName"
  442. v-for="item in fieldCodeList"
  443. :value="item.codeNumber"
  444. ></el-option>
  445. </el-select>
  446. </el-form-item>
  447. <el-form-item label="" prop="analysisName">
  448. <b style="color: #f00; font-size: 12px"
  449. >不填写分析主题,自动采用系统生成的主题!</b
  450. >
  451. </el-form-item>
  452. <el-form-item label="分析主题" prop="analysisName">
  453. <el-input v-model="addRuleForm.analysisName"></el-input>
  454. </el-form-item>
  455. <el-form-item label="分析简述" prop="sketch">
  456. <el-input type="textarea" v-model="addRuleForm.sketch"></el-input>
  457. </el-form-item>
  458. <el-form-item>
  459. <el-button type="primary" @click="addRuleFormSubmit">提交</el-button>
  460. <el-button @click="AddHandleCloses">取消</el-button>
  461. </el-form-item>
  462. </el-form>
  463. </el-dialog>
  464. </div>
  465. </template>
  466. <script>
  467. import MyDialog from "./components/dialogCom.vue";
  468. import { downloadPDF } from "@/utils/common";
  469. import {
  470. analysisResultList,
  471. addAnalysisResult,
  472. queryCodeNum,
  473. editPriority,
  474. analysisDetail,
  475. } from "@/api/performance";
  476. import { downloadDocx } from "@/utils/common";
  477. import { getFieldInfo } from "@/api/overview";
  478. import axios from "axios";
  479. import pLimit from "p-limit";
  480. import { allAnalysisType } from "./js/allAnalysisType";
  481. import { mapMutations, mapState } from "vuex";
  482. import {
  483. windEngineMillPage,
  484. getWindEngineGroupByFieldCode,
  485. } from "@/api/ledger.js";
  486. export default {
  487. components: {
  488. MyDialog,
  489. },
  490. data() {
  491. return {
  492. progress: {
  493. current: 0,
  494. total: 0,
  495. },
  496. colors: [
  497. { color: "#f56c6c", percentage: 20 },
  498. { color: "#e6a23c", percentage: 40 },
  499. { color: "#5cb87a", percentage: 60 },
  500. { color: "#1989fa", percentage: 80 },
  501. { color: "#6f7ad3", percentage: 100 },
  502. ],
  503. fileDataList: {},
  504. fieldInfo: {}, //风场信息
  505. firstLoad: false, // 是否是第一次加载
  506. fieldCodeList: [],
  507. addDialogVisible: false,
  508. dialogWidth: "80%",
  509. intervalId: null,
  510. startTime: null,
  511. maxPollingTime: 3 * 60 * 1000, //轮询最大时间
  512. dialogVisible: false,
  513. loadingView: false,
  514. loading: false, //数据加载中
  515. errorInfo: "",
  516. options: [
  517. {
  518. value: "-1",
  519. label: "未关联",
  520. },
  521. {
  522. value: "10",
  523. label: "排队中",
  524. },
  525. {
  526. value: "20",
  527. label: "分析中",
  528. },
  529. {
  530. value: "30",
  531. label: "已分析",
  532. },
  533. ],
  534. addRules: {
  535. fieldCode: [
  536. { required: true, message: "请选择关联风场", trigger: "change" },
  537. ],
  538. },
  539. addRuleForm: {
  540. fieldCode: "",
  541. analysisName: "",
  542. sketch: "",
  543. },
  544. rules: {
  545. fieldName: { trigger: "blur" },
  546. },
  547. roleList: [],
  548. formInline: {
  549. fieldName: undefined,
  550. pageNum: 1,
  551. pageSize: 10,
  552. totalSize: 0,
  553. analysisName: undefined,
  554. analysisState: undefined,
  555. },
  556. allAnalysis: [],
  557. tableData: [],
  558. rowInfo: {},
  559. title: "",
  560. viewerInstance: null, // PDF 文件 URL
  561. dialogReportVisible: false,
  562. pdfUrl: "",
  563. isPolling: false, // 轮询状态标识
  564. firstLoad: true, // 是否是第一次加载
  565. };
  566. },
  567. created() {
  568. this.firstLoad = true;
  569. window.addEventListener("message", this.handleMessage); //江
  570. this.fetchData();
  571. },
  572. computed: {
  573. ...mapState("settings", {
  574. downloadDisabled: "downloadDisabled",
  575. }),
  576. progressPercent() {
  577. if (this.progress.total === 0) return 0;
  578. return Math.round((this.progress.current / this.progress.total) * 100);
  579. },
  580. },
  581. methods: {
  582. ...mapMutations("settings", ["setDownloadDisabled"]),
  583. async postChartData(
  584. urlType,
  585. row,
  586. itemAnalysis,
  587. itemField,
  588. filterAnalysis,
  589. typeChart
  590. ) {
  591. try {
  592. if (itemField.analysisTypeName === "环境温度传感器") {
  593. console.log(itemField, "itemField");
  594. }
  595. const objectname =
  596. itemAnalysis.analysisTypeCode === "temperature_large_components"
  597. ? filterAnalysis.filterFileAddr +
  598. "/" +
  599. itemField.fieldEngineName +
  600. ".jpg"
  601. : itemField.engineTypeCode
  602. ? urlType + itemField.engineTypeCode + ".jpg"
  603. : urlType + itemField.fieldEngineName + ".jpg";
  604. const res = await axios.post(
  605. `/downLoadChart/chartServer/charts/${urlType}`,
  606. {
  607. fieldEngineCode: itemField.fieldEngineCode,
  608. bucketName: "bucket-zhzn",
  609. engineTypeCode: itemField.machineTypeCode,
  610. objectName:
  611. `charts/${row.fieldCode}/${row.batchCode}/${itemAnalysis.analysisTypeCode}/` +
  612. objectname,
  613. fieldInfo: this.fieldInfo,
  614. fileAddr: itemField.fileAddr,
  615. chartType:
  616. filterAnalysis.typeDocxName === "production_indicator_unit"
  617. ? "radar"
  618. : urlType,
  619. }
  620. );
  621. // 每完成 10% 提示一次(可调)
  622. const percent = Math.floor(
  623. (this.progress.current / this.progress.total) * 100
  624. );
  625. if (percent % 5 === 0 && !this._shownPercents?.includes(percent)) {
  626. this._shownPercents = this._shownPercents || [];
  627. this._shownPercents.push(percent);
  628. this.$notify.info(
  629. `📈 已完成 ${percent}%/${this.progress.current}张,共 ${this.progress.total} 张图表`
  630. );
  631. }
  632. let key = `zn-techcn-replace-tags-${filterAnalysis.typeDocxName}-${typeChart}`;
  633. if (urlType === "yawErrorBarSumChart") {
  634. key = `zn-techcn-replace-tags-${filterAnalysis.typeDocxName}-generalFiles2`;
  635. if (!this.fileDataList["yawErrorRows"]) {
  636. this.$set(this.fileDataList, "yawErrorRows", []); // Vue 2 中响应式设置对象属性
  637. }
  638. this.fileDataList["yawErrorRows"] = res?.data?.data?.data;
  639. } else if (urlType === "yawErrorChart") {
  640. key = `zn-techcn-replace-tags-${filterAnalysis.typeDocxName}-generalFiles1`;
  641. }
  642. if (filterAnalysis.typeDocxName === "production_indicator_all") {
  643. if (!this.fileDataList["rows"]) {
  644. this.$set(this.fileDataList, "rows", []); // Vue 2 中响应式设置对象属性
  645. }
  646. this.fileDataList["rows"] = res?.data?.data?.data;
  647. }
  648. if (itemField.engineTypeCode === "total_fault_result") {
  649. if (!this.fileDataList["faultRows"]) {
  650. this.$set(this.fileDataList, "faultRows", []); // Vue 2 中响应式设置对象属性
  651. }
  652. this.fileDataList["faultRows"] = res?.data?.data?.data;
  653. }
  654. if (itemField.engineTypeCode === "turbine_fault_result") {
  655. if (!this.fileDataList["windTurbineRows"]) {
  656. this.$set(this.fileDataList, "windTurbineRows", []); // Vue 2 中响应式设置对象属性
  657. }
  658. this.fileDataList["windTurbineRows"] = res?.data?.data?.data;
  659. }
  660. if (filterAnalysis.typeDocxName === "production_indicator_unit") {
  661. if (!this.fileDataList[key]) {
  662. this.$set(this.fileDataList, key, []); // Vue 2 中响应式设置对象属性
  663. }
  664. res?.data?.data?.imageUrls.map((imgval) => {
  665. this.fileDataList[key].push(imgval);
  666. });
  667. } else {
  668. if (!this.fileDataList[key]) {
  669. this.$set(this.fileDataList, key, []); // Vue 2 中响应式设置对象属性
  670. }
  671. this.fileDataList[key].push(res?.data?.data?.imageUrl);
  672. }
  673. } catch (err) {
  674. console.error("生成失败:", err);
  675. }
  676. },
  677. async handleDownLoadChart(row) {
  678. this.progress.current = 0;
  679. this.progress.total = 0;
  680. this.fileDataList = {};
  681. this.setDownloadDisabled(true);
  682. this.$notify.warning("开始生成 Word 文档...");
  683. try {
  684. await this.getAllAnalysis(row.batchCode);
  685. await this.getFieldDetail(row.batchCode);
  686. this.$message.info("开始生成word文档");
  687. const limit = pLimit(5); // 限制同时并发的请求数量为 5
  688. const tasks = [];
  689. for (const itemAnalysis of this.allAnalysis) {
  690. const filterAnalysis = allAnalysisType.filter(
  691. (itemType) => itemType.typeName === itemAnalysis.analysisTypeName
  692. )[0];
  693. if (itemAnalysis.generalFiles) {
  694. //这里过滤的是发电机温度的类型 在url 中是否能找到filterFileAddr
  695. for (const itemField of filterAnalysis.filterFileAddr
  696. ? itemAnalysis.generalFiles
  697. .filter((item) => item.fileAddr.endsWith(".json"))
  698. .filter((item) =>
  699. item.fileAddr.includes(filterAnalysis.filterFileAddr)
  700. ) || []
  701. : itemAnalysis.generalFiles) {
  702. //静态偏航误差 --通过allAnalysisType.js文件配置实现需求
  703. if (Array.isArray(filterAnalysis.generalFiles.urlType)) {
  704. filterAnalysis.generalFiles.urlType.map(
  705. (itemUrlType, indUrlType) => {
  706. tasks.push(
  707. limit(async () => {
  708. await this.postChartData(
  709. itemUrlType,
  710. row,
  711. itemAnalysis,
  712. itemField,
  713. filterAnalysis,
  714. "generalFiles"
  715. );
  716. this.progress.current++;
  717. })
  718. );
  719. }
  720. );
  721. } else if (filterAnalysis.typeCode === "fault") {
  722. if (itemField.fileAddr.includes("turbine_fault_result")) {
  723. if (itemField.engineTypeCode === "turbine_fault_result") {
  724. tasks.push(
  725. limit(async () => {
  726. await this.postChartData(
  727. "faultUnitChart",
  728. row,
  729. itemAnalysis,
  730. itemField,
  731. filterAnalysis,
  732. "generalFiles"
  733. );
  734. this.progress.current++;
  735. })
  736. );
  737. }
  738. } else {
  739. if (itemField.engineTypeCode === "total_fault_result") {
  740. tasks.push(
  741. limit(async () => {
  742. await this.postChartData(
  743. "faultAllChart",
  744. row,
  745. itemAnalysis,
  746. itemField,
  747. filterAnalysis,
  748. "generalFiles"
  749. );
  750. this.progress.current++;
  751. })
  752. );
  753. }
  754. }
  755. } else if (filterAnalysis.typeCode === "production_indicator") {
  756. //总图全场
  757. if (
  758. itemField.fileAddr.includes(
  759. filterAnalysis.generalFiles.FileTypeFromUrl
  760. )
  761. ) {
  762. tasks.push(
  763. limit(async () => {
  764. await this.postChartData(
  765. filterAnalysis.generalFiles.urlType,
  766. row,
  767. itemAnalysis,
  768. itemField,
  769. filterAnalysis,
  770. "generalFiles"
  771. );
  772. this.progress.current++;
  773. // 每完成 10% 提示一次(可调)
  774. })
  775. );
  776. } else {
  777. tasks.push(
  778. limit(async () => {
  779. await this.postChartData(
  780. "radarChart",
  781. row,
  782. itemAnalysis,
  783. itemField,
  784. filterAnalysis,
  785. "generalFiles"
  786. );
  787. this.progress.current++;
  788. })
  789. );
  790. }
  791. } else {
  792. tasks.push(
  793. limit(async () => {
  794. await this.postChartData(
  795. filterAnalysis.generalFiles.urlType,
  796. row,
  797. itemAnalysis,
  798. itemField,
  799. filterAnalysis,
  800. "generalFiles"
  801. );
  802. this.progress.current++;
  803. })
  804. );
  805. }
  806. }
  807. }
  808. if (itemAnalysis.diagramRelations) {
  809. for (const itemField of filterAnalysis.filterFileAddr
  810. ? itemAnalysis.diagramRelations
  811. .filter((item) => item.fileAddr.endsWith(".json"))
  812. .filter((item) =>
  813. item.fileAddr.includes(filterAnalysis.filterFileAddr)
  814. ) || []
  815. : itemAnalysis.diagramRelations) {
  816. const urlType = Array.isArray(
  817. filterAnalysis.diagramRelations.urlType
  818. )
  819. ? this.getFileTypeFromUrl(
  820. itemField.fileAddr,
  821. filterAnalysis.diagramRelations.FileTypeFromUrl
  822. ) === filterAnalysis.diagramRelations.FileTypeFromUrl
  823. ? filterAnalysis.diagramRelations.urlType[0]
  824. : filterAnalysis.diagramRelations.urlType[1]
  825. : filterAnalysis.diagramRelations.urlType;
  826. tasks.push(
  827. limit(async () => {
  828. await this.postChartData(
  829. urlType,
  830. row,
  831. itemAnalysis,
  832. itemField,
  833. filterAnalysis,
  834. "diagramRelations"
  835. );
  836. this.progress.current++;
  837. })
  838. );
  839. }
  840. }
  841. }
  842. this.progress.total = tasks.length;
  843. await Promise.all(tasks);
  844. const engineTypeList = await this.getEngineTypeList(
  845. this.fieldInfo.engineMillTypes,
  846. row.batchCode
  847. );
  848. this.$notify.success("✅ 图表全部生成完成,开始生成 Word 文档...");
  849. const wordFilePath = await axios.post(
  850. "/downLoadChart/chartServer/charts/CopyFileCsv",
  851. {
  852. fieldInfo: this.fieldInfo,
  853. dataTime: `${this.analysisInfo.dataStartTime}-${this.analysisInfo.dataEndTime}`,
  854. bucketName: "bucket-zhzn",
  855. objectName: `charts/${row.fieldCode}/${row.batchCode}`,
  856. engineTypeList: engineTypeList,
  857. ...this.fileDataList,
  858. }
  859. );
  860. // //下载minio 文件
  861. downloadDocx(
  862. wordFilePath.data.data.url,
  863. wordFilePath.data.data.fileName
  864. );
  865. this.$notify.success("🎉 Word 文档生成并已下载!");
  866. this.setDownloadDisabled(false);
  867. } catch (error) {
  868. console.log(error, "error");
  869. this.$notify.error("🎉 Word 文档生成并下载失败!");
  870. this.setDownloadDisabled(false);
  871. }
  872. },
  873. async getEngineTypeList(typeList, batchCode) {
  874. return await Promise.all(
  875. typeList.map((item) => this.getEngineMillList(item, batchCode))
  876. );
  877. },
  878. // 查询
  879. async getEngineMillList(machineTypeCode, batchCode) {
  880. let dataArr = {
  881. fieldCode: this.fieldInfo.fieldCode,
  882. batchCode: batchCode,
  883. };
  884. const fieldRes = await getWindEngineGroupByFieldCode(dataArr);
  885. const map = new Map();
  886. const uniqueList = [];
  887. for (const item of fieldRes.data.windEngineGroupVoList) {
  888. if (!map.has(item.millTypeCode)) {
  889. map.set(item.millTypeCode, true);
  890. uniqueList.push(item);
  891. }
  892. }
  893. let paramsData = {
  894. machineTypeCode: machineTypeCode || undefined,
  895. pageNum: 1,
  896. pageSize: 10,
  897. };
  898. this.loading = true;
  899. const res = await windEngineMillPage(paramsData);
  900. const filterMill = uniqueList.filter(
  901. (item) => item.millTypeCode === res.data.list[0].millTypeCode
  902. );
  903. return { ...res.data.list[0], ratedPower: filterMill[0].ratedCapacity };
  904. },
  905. getFileTypeFromUrl(url, keyword) {
  906. return url.includes(keyword) ? keyword : "Unknown";
  907. },
  908. async getFieldDetail(batchCode) {
  909. const res = await getFieldInfo({ batchCode });
  910. this.fieldInfo = res.data.fieldInfo; //风场信息
  911. this.analysisInfo = res.data.analysisInfo;
  912. },
  913. //获取所有分析类型,分析结果接口
  914. async getAllAnalysis(batchCode) {
  915. const res = await analysisDetail({ batchCode });
  916. // console.log(res.data, "分析全部结果");
  917. this.allAnalysis = res.data;
  918. },
  919. //自动分析列表页面跳转
  920. handleAutoAsstessList() {
  921. window.open(
  922. this.$router.resolve({ path: "/home/performance/autoAssetss" }).href,
  923. "_blank"
  924. );
  925. },
  926. // 创建分析时请求
  927. async addRuleFormSubmit() {
  928. this.$refs.addRuleForm.validate(async (valid) => {
  929. if (valid) {
  930. try {
  931. const res = await addAnalysisResult(this.addRuleForm);
  932. if (res.code === 200) {
  933. this.$message({
  934. type: "success",
  935. message: "创建成功",
  936. });
  937. this.addDialogVisible = false;
  938. this.loading = false;
  939. this.isPolling = false;
  940. await this.fetchData();
  941. let obj = this.fieldCodeList.filter((itemS) => {
  942. if (itemS.codeNumber === this.addRuleForm.fieldCode) {
  943. return itemS;
  944. }
  945. });
  946. this.$router.push({
  947. path: "/home/performance/editAssets",
  948. query: {
  949. batchCode: this.tableData[0].batchCode,
  950. analysisTypeCode: this.tableData[0].analysisTypeCode,
  951. fieldEngineCode: this.tableData[0].fieldCode,
  952. fieldName: obj[0].fieldName,
  953. analysisName: this.addRuleForm.analysisName,
  954. },
  955. });
  956. }
  957. } catch (err) {
  958. console.error(err);
  959. }
  960. }
  961. });
  962. },
  963. AddHandleCloses(done) {
  964. this.$confirm("确认关闭?")
  965. .then((_) => {
  966. this.addDialogVisible = false;
  967. done();
  968. })
  969. .catch((_) => {});
  970. },
  971. //获取风场列表
  972. async getQueryCodeNumList() {
  973. this.loading = true;
  974. try {
  975. const result = await queryCodeNum();
  976. this.fieldCodeList = result.data.fieldCodeList;
  977. this.loading = false;
  978. } catch (error) {
  979. console.error(error);
  980. this.loading = false;
  981. }
  982. },
  983. handleCloses(done) {
  984. this.$confirm("确认关闭?")
  985. .then((_) => {
  986. done();
  987. })
  988. .catch((_) => {});
  989. },
  990. //查看pdf 文件
  991. detailReportAssetss(row) {
  992. this.dialogReportVisible = true;
  993. this.pdfUrl = row.reportAddr;
  994. },
  995. //下载pdf 文件
  996. downLoadeAssetss(row) {
  997. downloadPDF(row.reportAddr, row.reportName);
  998. },
  999. //插队接口
  1000. async insertQueue(row, index) {
  1001. this.$confirm(`确认插队?`, "提示", {
  1002. confirmButtonText: "确定",
  1003. cancelButtonText: "取消",
  1004. type: "warning",
  1005. })
  1006. .then(async () => {
  1007. const formData = new FormData();
  1008. formData.append("batchCode", row.batchCode);
  1009. formData.append("priority", index);
  1010. const result = await editPriority(formData);
  1011. if (result.code === 200) {
  1012. this.$message({
  1013. type: "success",
  1014. message: "插队成功",
  1015. });
  1016. await this.fetchData();
  1017. }
  1018. })
  1019. .catch(() => {});
  1020. },
  1021. //分析
  1022. handleAssetss(row) {
  1023. this.$router.push({
  1024. path: "/home/performance/editAssets",
  1025. query: {
  1026. batchCode: row.batchCode,
  1027. analysisTypeCode: row.analysisTypeCode,
  1028. fieldEngineCode: row.fieldCode,
  1029. fieldName: row.fieldName,
  1030. analysisName: row.analysisName,
  1031. },
  1032. });
  1033. },
  1034. //分析详情
  1035. handleAssetssDetail(row, state) {
  1036. const navigateToDetails = () => {
  1037. this.$router.push({
  1038. path: "/home/performance/overview",
  1039. query: {
  1040. batchCode: row.batchCode,
  1041. // analysisTypeCode: row.analysisTypeCode,
  1042. fieldCode: row.fieldCode,
  1043. },
  1044. });
  1045. };
  1046. if (state === "0") {
  1047. // 分析状态为分析中
  1048. this.$confirm(
  1049. "当前查看的分析记录为历史分析结果,最新分析记录还未分析完成不展示!"
  1050. )
  1051. .then(() => {
  1052. navigateToDetails();
  1053. })
  1054. .catch(() => {});
  1055. } else {
  1056. navigateToDetails();
  1057. }
  1058. },
  1059. abnormalDialog(row, title) {
  1060. this.dialogVisible = true;
  1061. if (title === "异常详情") {
  1062. this.errorInfo = row.errInfo;
  1063. this.rowInfo = {};
  1064. } else if (title === "机组异常记录") {
  1065. this.errorInfo = "";
  1066. this.rowInfo = { ...row };
  1067. } else if (title === "上传报告") {
  1068. this.errorInfo = "";
  1069. this.rowInfo = {};
  1070. this.rowInfo.batchCode = row.batchCode;
  1071. }
  1072. this.title = title;
  1073. },
  1074. handleConfirm() {
  1075. this.dialogVisible = false;
  1076. },
  1077. // 页码变化时才触发查询
  1078. handleCurrentChange(val) {
  1079. this.formInline.pageNum = val;
  1080. this.fetchData();
  1081. },
  1082. // 修改 getTableList 方法,避免重复请求
  1083. async getTableList() {
  1084. // 如果正在请求中,跳过此次调用
  1085. if (this.loading || this.isPolling) return;
  1086. this.loading = true;
  1087. try {
  1088. const params = { ...this.formInline, totalSize: undefined };
  1089. // 传递条件参数
  1090. if (this.formInline.analysisState !== undefined) {
  1091. params.analysisState = this.formInline.analysisState;
  1092. }
  1093. if (this.formInline.errState !== undefined) {
  1094. params.errState = this.formInline.errState;
  1095. }
  1096. const result = await analysisResultList(params);
  1097. this.tableData = result.data.list;
  1098. this.formInline.totalSize = result.data.totalSize;
  1099. } catch (error) {
  1100. this.$message({
  1101. type: "error",
  1102. message: "请检查是否连接网络",
  1103. });
  1104. } finally {
  1105. this.loading = false;
  1106. }
  1107. },
  1108. // 改进 handleMessage,避免频繁请求
  1109. handleMessage(event) {
  1110. // 确保消息来自当前域
  1111. if (event.origin !== window.location.origin) {
  1112. return;
  1113. }
  1114. const { fieldName, analysisState, errState } = event.data;
  1115. // 更新表单字段
  1116. if (fieldName !== undefined) {
  1117. this.formInline.fieldName = fieldName;
  1118. }
  1119. if (analysisState !== undefined) {
  1120. this.formInline.analysisState = analysisState;
  1121. }
  1122. if (errState !== undefined) {
  1123. this.formInline.errState = errState;
  1124. }
  1125. if (!this.loading) {
  1126. if (this.firstLoad && (analysisState || errState || fieldName)) {
  1127. // this.getTableList();
  1128. this.startPolling();
  1129. this.fetchData();
  1130. }
  1131. //
  1132. }
  1133. },
  1134. rowStyle() {
  1135. return "text-align:center";
  1136. },
  1137. // 重置
  1138. reset(formName) {
  1139. this.$refs[formName].resetFields();
  1140. this.formInline.fieldName = "";
  1141. this.formInline.analysisName = "";
  1142. this.formInline.analysisState = "";
  1143. this.formInline.errState = "";
  1144. this.fetchData();
  1145. },
  1146. // fetchData 方法在轮询中调用
  1147. async fetchData() {
  1148. if (
  1149. this.formInline.fieldName ||
  1150. this.formInline.analysisState ||
  1151. this.formInline.errState
  1152. ) {
  1153. this.firstLoad = false;
  1154. }
  1155. try {
  1156. const result = await analysisResultList({
  1157. ...this.formInline,
  1158. totalSize: undefined,
  1159. });
  1160. this.tableData = result.data.list;
  1161. this.formInline.totalSize = result.data.totalSize;
  1162. } catch (error) {
  1163. this.$message({
  1164. type: "error",
  1165. message: "请检查是否连接网络",
  1166. });
  1167. }
  1168. },
  1169. stopPolling() {
  1170. // 停止轮询
  1171. if (this.intervalId) {
  1172. clearInterval(this.intervalId);
  1173. this.intervalId = null;
  1174. }
  1175. this.isPolling = false;
  1176. },
  1177. // 启动轮询时,避免重复请求
  1178. startPolling() {
  1179. this.startTime = new Date().getTime();
  1180. this.isPolling = true;
  1181. this.intervalId = setInterval(() => {
  1182. const currentTime = new Date().getTime();
  1183. if (currentTime - this.startTime >= this.maxPollingTime) {
  1184. this.stopPolling();
  1185. } else {
  1186. // 轮询期间不重复请求,检查是否可以调用 fetchData
  1187. if (!this.loading) {
  1188. this.fetchData();
  1189. }
  1190. }
  1191. }, 10000); // 每10秒检查一次
  1192. },
  1193. //创建分析
  1194. Newanalyse() {
  1195. this.addDialogVisible = true;
  1196. this.getQueryCodeNumList();
  1197. },
  1198. examine() {
  1199. const targetUrl = this.$router.resolve({ name: "transition" }).href;
  1200. window.open(targetUrl, "_blank");
  1201. },
  1202. },
  1203. mounted() {
  1204. this.startPolling();
  1205. },
  1206. beforeDestroy() {
  1207. this.stopPolling();
  1208. // 销毁消息监听器
  1209. window.removeEventListener("message", this.handleMessage); //江
  1210. },
  1211. };
  1212. </script>
  1213. <style lang="scss" scoped>
  1214. @keyframes striped-flow {
  1215. from {
  1216. background-position: 0 100px;
  1217. }
  1218. to {
  1219. background-position: 1.25em 1.25em;
  1220. }
  1221. }
  1222. .general {
  1223. display: flex;
  1224. flex-wrap: wrap;
  1225. .condition {
  1226. width: 50%;
  1227. display: flex;
  1228. p {
  1229. width: 100px;
  1230. text-align: right;
  1231. line-height: 40px;
  1232. }
  1233. span {
  1234. line-height: 40px;
  1235. padding-left: 20px;
  1236. }
  1237. .el-select {
  1238. width: 100%;
  1239. margin-bottom: 20px;
  1240. }
  1241. .el-input {
  1242. margin-bottom: 20px;
  1243. }
  1244. }
  1245. }
  1246. .progress {
  1247. display: flex;
  1248. align-items: center;
  1249. position: fixed;
  1250. top: 25px;
  1251. right: 300px;
  1252. .progressText {
  1253. font-size: 14px;
  1254. color: #606266;
  1255. }
  1256. .el-progress {
  1257. width: 300px;
  1258. }
  1259. }
  1260. .attachment {
  1261. display: flex;
  1262. padding-top: 10px;
  1263. p {
  1264. margin-right: 20px;
  1265. color: #409eff;
  1266. }
  1267. }
  1268. .add-ruleForm {
  1269. .el-select {
  1270. width: 100%;
  1271. }
  1272. }
  1273. .addition {
  1274. display: flex;
  1275. justify-content: flex-end;
  1276. margin-bottom: 10px;
  1277. }
  1278. .demo-ruleForm {
  1279. .el-form-item {
  1280. margin-bottom: 25px;
  1281. }
  1282. }
  1283. ::v-deep .animated-progress .el-progress-bar__outer {
  1284. height: 15px; /* Adjust height as needed */
  1285. background-color: rgb(235, 238, 245);
  1286. background-image: linear-gradient(
  1287. 45deg,
  1288. rgba(0, 0, 0, 0.1) 25%,
  1289. transparent 25%,
  1290. transparent 50%,
  1291. rgba(0, 0, 0, 0.1) 50%,
  1292. rgba(0, 0, 0, 0.1) 75%,
  1293. transparent 75%,
  1294. transparent
  1295. );
  1296. background-size: 1.25em 1.25em;
  1297. animation: striped-flow 3s linear infinite;
  1298. }
  1299. .reportItemVal {
  1300. display: flex;
  1301. justify-content: space-between;
  1302. align-items: center;
  1303. .reportLeft {
  1304. margin-right: 50px;
  1305. }
  1306. }
  1307. ::v-deep .pdfDialog .el-dialog {
  1308. height: 100vh;
  1309. display: flex;
  1310. flex-direction: column;
  1311. margin: 0 auto !important;
  1312. .el-dialog__body {
  1313. // height: 100% !important;
  1314. flex: 1;
  1315. background: #fff;
  1316. .pdf-container {
  1317. display: flex;
  1318. justify-content: center;
  1319. align-items: center;
  1320. height: 100% !important;
  1321. }
  1322. }
  1323. }
  1324. canvas {
  1325. border: 1px solid #dcdfe6;
  1326. }
  1327. .right-align {
  1328. white-space: nowrap;
  1329. }
  1330. </style>