assetssMag.vue 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365
  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 + "/" + itemField.fieldEngineName ||
  598. itemField.engineTypeCode + ".jpg"
  599. : itemField.engineTypeCode
  600. ? urlType + itemField.engineTypeCode + ".jpg"
  601. : urlType + itemField.fieldEngineName + ".jpg";
  602. console.log(
  603. objectname,
  604. "objectname",
  605. itemAnalysis.analysisTypeName,
  606. itemField.engineTypeCode,
  607. itemAnalysis,
  608. );
  609. // const res = await axios.post(
  610. // `/downLoadChart/chartServer/charts/${urlType}`,
  611. // {
  612. // fieldEngineCode: itemField.fieldEngineCode,
  613. // bucketName: "bucket-zhzn",
  614. // engineTypeCode: itemField.machineTypeCode,
  615. // objectName:
  616. // `charts/${row.fieldCode}/${row.batchCode}/${itemAnalysis.analysisTypeCode}/` +
  617. // objectname,
  618. // fieldInfo: this.fieldInfo,
  619. // fileAddr: itemField.fileAddr,
  620. // chartType:
  621. // filterAnalysis.typeDocxName === "production_indicator_unit"
  622. // ? "radar"
  623. // : urlType,
  624. // },
  625. // );
  626. // // 每完成 10% 提示一次(可调)
  627. // const percent = Math.floor(
  628. // (this.progress.current / this.progress.total) * 100,
  629. // );
  630. // if (percent % 5 === 0 && !this._shownPercents?.includes(percent)) {
  631. // this._shownPercents = this._shownPercents || [];
  632. // this._shownPercents.push(percent);
  633. // this.$notify.info(
  634. // `📈 已完成 ${percent}%/${this.progress.current}张,共 ${this.progress.total} 张图表`,
  635. // );
  636. // }
  637. // let key = `zn-techcn-replace-tags-${filterAnalysis.typeDocxName}-${typeChart}`;
  638. // if (urlType === "yawErrorBarSumChart") {
  639. // key = `zn-techcn-replace-tags-${filterAnalysis.typeDocxName}-generalFiles2`;
  640. // if (!this.fileDataList["yawErrorRows"]) {
  641. // this.$set(this.fileDataList, "yawErrorRows", []); // Vue 2 中响应式设置对象属性
  642. // }
  643. // this.fileDataList["yawErrorRows"] = res?.data?.data?.data;
  644. // } else if (urlType === "yawErrorChart") {
  645. // key = `zn-techcn-replace-tags-${filterAnalysis.typeDocxName}-generalFiles1`;
  646. // }
  647. // if (filterAnalysis.typeDocxName === "production_indicator_all") {
  648. // if (!this.fileDataList["rows"]) {
  649. // this.$set(this.fileDataList, "rows", []); // Vue 2 中响应式设置对象属性
  650. // }
  651. // this.fileDataList["rows"] = res?.data?.data?.data;
  652. // }
  653. // if (itemField.engineTypeCode === "total_fault_result") {
  654. // if (!this.fileDataList["faultRows"]) {
  655. // this.$set(this.fileDataList, "faultRows", []); // Vue 2 中响应式设置对象属性
  656. // }
  657. // this.fileDataList["faultRows"] = res?.data?.data?.data;
  658. // }
  659. // if (itemField.engineTypeCode === "turbine_fault_result") {
  660. // if (!this.fileDataList["windTurbineRows"]) {
  661. // this.$set(this.fileDataList, "windTurbineRows", []); // Vue 2 中响应式设置对象属性
  662. // }
  663. // this.fileDataList["windTurbineRows"] = res?.data?.data?.data;
  664. // }
  665. // if (filterAnalysis.typeDocxName === "production_indicator_unit") {
  666. // if (!this.fileDataList[key]) {
  667. // this.$set(this.fileDataList, key, []); // Vue 2 中响应式设置对象属性
  668. // }
  669. // res?.data?.data?.imageUrls.map((imgval) => {
  670. // this.fileDataList[key].push(imgval);
  671. // });
  672. // } else {
  673. // if (!this.fileDataList[key]) {
  674. // this.$set(this.fileDataList, key, []); // Vue 2 中响应式设置对象属性
  675. // }
  676. // this.fileDataList[key].push(res?.data?.data?.imageUrl);
  677. // }
  678. } catch (err) {
  679. console.error("生成失败:", err);
  680. }
  681. },
  682. async handleDownLoadChart(row) {
  683. this.progress.current = 0;
  684. this.progress.total = 0;
  685. this.fileDataList = {};
  686. this.setDownloadDisabled(true);
  687. this.$notify.warning("开始生成 Word 文档...");
  688. try {
  689. await this.getAllAnalysis(row.batchCode);
  690. await this.getFieldDetail(row.batchCode);
  691. this.$message.info("开始生成word文档");
  692. const limit = pLimit(5); // 限制同时并发的请求数量为 5
  693. const tasks = [];
  694. for (const itemAnalysis of this.allAnalysis) {
  695. const filterAnalysis = allAnalysisType.filter(
  696. (itemType) => itemType.typeName === itemAnalysis.analysisTypeName,
  697. )[0];
  698. if (itemAnalysis.generalFiles) {
  699. //这里过滤的是发电机温度的类型 在url 中是否能找到filterFileAddr
  700. for (const itemField of filterAnalysis.filterFileAddr
  701. ? itemAnalysis.generalFiles
  702. .filter((item) => item.fileAddr.endsWith(".json"))
  703. .filter((item) =>
  704. item.fileAddr.includes(filterAnalysis.filterFileAddr),
  705. ) || []
  706. : itemAnalysis.generalFiles) {
  707. //静态偏航误差 --通过allAnalysisType.js文件配置实现需求
  708. if (Array.isArray(filterAnalysis.generalFiles.urlType)) {
  709. filterAnalysis.generalFiles.urlType.map(
  710. (itemUrlType, indUrlType) => {
  711. tasks.push(
  712. limit(async () => {
  713. await this.postChartData(
  714. itemUrlType,
  715. row,
  716. itemAnalysis,
  717. itemField,
  718. filterAnalysis,
  719. "generalFiles",
  720. );
  721. this.progress.current++;
  722. }),
  723. );
  724. },
  725. );
  726. } else if (filterAnalysis.typeCode === "fault") {
  727. if (itemField.fileAddr.includes("turbine_fault_result")) {
  728. if (itemField.engineTypeCode === "turbine_fault_result") {
  729. tasks.push(
  730. limit(async () => {
  731. await this.postChartData(
  732. "faultUnitChart",
  733. row,
  734. itemAnalysis,
  735. itemField,
  736. filterAnalysis,
  737. "generalFiles",
  738. );
  739. this.progress.current++;
  740. }),
  741. );
  742. }
  743. } else {
  744. if (itemField.engineTypeCode === "total_fault_result") {
  745. tasks.push(
  746. limit(async () => {
  747. await this.postChartData(
  748. "faultAllChart",
  749. row,
  750. itemAnalysis,
  751. itemField,
  752. filterAnalysis,
  753. "generalFiles",
  754. );
  755. this.progress.current++;
  756. }),
  757. );
  758. }
  759. }
  760. } else if (filterAnalysis.typeCode === "production_indicator") {
  761. //总图全场
  762. if (
  763. itemField.fileAddr.includes(
  764. filterAnalysis.generalFiles.FileTypeFromUrl,
  765. )
  766. ) {
  767. tasks.push(
  768. limit(async () => {
  769. await this.postChartData(
  770. filterAnalysis.generalFiles.urlType,
  771. row,
  772. itemAnalysis,
  773. itemField,
  774. filterAnalysis,
  775. "generalFiles",
  776. );
  777. this.progress.current++;
  778. // 每完成 10% 提示一次(可调)
  779. }),
  780. );
  781. } else {
  782. tasks.push(
  783. limit(async () => {
  784. await this.postChartData(
  785. "radarChart",
  786. row,
  787. itemAnalysis,
  788. itemField,
  789. filterAnalysis,
  790. "generalFiles",
  791. );
  792. this.progress.current++;
  793. }),
  794. );
  795. }
  796. } else {
  797. tasks.push(
  798. limit(async () => {
  799. await this.postChartData(
  800. filterAnalysis.generalFiles.urlType,
  801. row,
  802. itemAnalysis,
  803. itemField,
  804. filterAnalysis,
  805. "generalFiles",
  806. );
  807. this.progress.current++;
  808. }),
  809. );
  810. }
  811. }
  812. }
  813. if (itemAnalysis.diagramRelations) {
  814. for (const itemField of filterAnalysis.filterFileAddr
  815. ? itemAnalysis.diagramRelations
  816. .filter((item) => item.fileAddr.endsWith(".json"))
  817. .filter((item) =>
  818. item.fileAddr.includes(filterAnalysis.filterFileAddr),
  819. ) || []
  820. : itemAnalysis.diagramRelations) {
  821. const urlType = Array.isArray(
  822. filterAnalysis.diagramRelations.urlType,
  823. )
  824. ? this.getFileTypeFromUrl(
  825. itemField.fileAddr,
  826. filterAnalysis.diagramRelations.FileTypeFromUrl,
  827. ) === filterAnalysis.diagramRelations.FileTypeFromUrl
  828. ? filterAnalysis.diagramRelations.urlType[0]
  829. : filterAnalysis.diagramRelations.urlType[1]
  830. : filterAnalysis.diagramRelations.urlType;
  831. tasks.push(
  832. limit(async () => {
  833. await this.postChartData(
  834. urlType,
  835. row,
  836. itemAnalysis,
  837. itemField,
  838. filterAnalysis,
  839. "diagramRelations",
  840. );
  841. this.progress.current++;
  842. }),
  843. );
  844. }
  845. }
  846. }
  847. this.progress.total = tasks.length;
  848. await Promise.all(tasks);
  849. const engineTypeList = await this.getEngineTypeList(
  850. this.fieldInfo.engineMillTypes,
  851. row.batchCode,
  852. );
  853. this.$notify.success("✅ 图表全部生成完成,开始生成 Word 文档...");
  854. const wordFilePath = await axios.post(
  855. "/downLoadChart/chartServer/charts/CopyFileCsv",
  856. {
  857. fieldInfo: this.fieldInfo,
  858. dataTime: `${this.analysisInfo.dataStartTime}-${this.analysisInfo.dataEndTime}`,
  859. bucketName: "bucket-zhzn",
  860. objectName: `charts/${row.fieldCode}/${row.batchCode}`,
  861. engineTypeList: engineTypeList,
  862. ...this.fileDataList,
  863. },
  864. );
  865. // //下载minio 文件
  866. downloadDocx(
  867. wordFilePath.data.data.url,
  868. wordFilePath.data.data.fileName,
  869. );
  870. this.$notify.success("🎉 Word 文档生成并已下载!");
  871. this.setDownloadDisabled(false);
  872. } catch (error) {
  873. console.log(error, "error");
  874. this.$notify.error("🎉 Word 文档生成并下载失败!");
  875. this.setDownloadDisabled(false);
  876. }
  877. },
  878. async getEngineTypeList(typeList, batchCode) {
  879. return await Promise.all(
  880. typeList.map((item) => this.getEngineMillList(item, batchCode)),
  881. );
  882. },
  883. // 查询
  884. async getEngineMillList(machineTypeCode, batchCode) {
  885. let dataArr = {
  886. fieldCode: this.fieldInfo.fieldCode,
  887. batchCode: batchCode,
  888. };
  889. const fieldRes = await getWindEngineGroupByFieldCode(dataArr);
  890. const map = new Map();
  891. const uniqueList = [];
  892. for (const item of fieldRes.data.windEngineGroupVoList) {
  893. if (!map.has(item.millTypeCode)) {
  894. map.set(item.millTypeCode, true);
  895. uniqueList.push(item);
  896. }
  897. }
  898. let paramsData = {
  899. machineTypeCode: machineTypeCode || undefined,
  900. pageNum: 1,
  901. pageSize: 10,
  902. };
  903. this.loading = true;
  904. const res = await windEngineMillPage(paramsData);
  905. const filterMill = uniqueList.filter(
  906. (item) => item.millTypeCode === res.data.list[0].millTypeCode,
  907. );
  908. return { ...res.data.list[0], ratedPower: filterMill[0].ratedCapacity };
  909. },
  910. getFileTypeFromUrl(url, keyword) {
  911. return url.includes(keyword) ? keyword : "Unknown";
  912. },
  913. async getFieldDetail(batchCode) {
  914. const res = await getFieldInfo({ batchCode });
  915. this.fieldInfo = res.data.fieldInfo; //风场信息
  916. this.analysisInfo = res.data.analysisInfo;
  917. },
  918. //获取所有分析类型,分析结果接口
  919. async getAllAnalysis(batchCode) {
  920. const res = await analysisDetail({ batchCode });
  921. // console.log(res.data, "分析全部结果");
  922. this.allAnalysis = res.data;
  923. },
  924. //自动分析列表页面跳转
  925. handleAutoAsstessList() {
  926. window.open(
  927. this.$router.resolve({ path: "/home/performance/autoAssetss" }).href,
  928. "_blank",
  929. );
  930. },
  931. // 创建分析时请求
  932. async addRuleFormSubmit() {
  933. this.$refs.addRuleForm.validate(async (valid) => {
  934. if (valid) {
  935. try {
  936. const res = await addAnalysisResult(this.addRuleForm);
  937. if (res.code === 200) {
  938. this.$message({
  939. type: "success",
  940. message: "创建成功",
  941. });
  942. this.addDialogVisible = false;
  943. this.loading = false;
  944. this.isPolling = false;
  945. await this.fetchData();
  946. let obj = this.fieldCodeList.filter((itemS) => {
  947. if (itemS.codeNumber === this.addRuleForm.fieldCode) {
  948. return itemS;
  949. }
  950. });
  951. this.$router.push({
  952. path: "/home/performance/editAssets",
  953. query: {
  954. batchCode: this.tableData[0].batchCode,
  955. analysisTypeCode: this.tableData[0].analysisTypeCode,
  956. fieldEngineCode: this.tableData[0].fieldCode,
  957. fieldName: obj[0].fieldName,
  958. analysisName: this.addRuleForm.analysisName,
  959. },
  960. });
  961. }
  962. } catch (err) {
  963. console.error(err);
  964. }
  965. }
  966. });
  967. },
  968. AddHandleCloses(done) {
  969. this.$confirm("确认关闭?")
  970. .then((_) => {
  971. this.addDialogVisible = false;
  972. done();
  973. })
  974. .catch((_) => {});
  975. },
  976. //获取风场列表
  977. async getQueryCodeNumList() {
  978. this.loading = true;
  979. try {
  980. const result = await queryCodeNum();
  981. this.fieldCodeList = result.data.fieldCodeList;
  982. this.loading = false;
  983. } catch (error) {
  984. console.error(error);
  985. this.loading = false;
  986. }
  987. },
  988. handleCloses(done) {
  989. this.$confirm("确认关闭?")
  990. .then((_) => {
  991. done();
  992. })
  993. .catch((_) => {});
  994. },
  995. //查看pdf 文件
  996. detailReportAssetss(row) {
  997. this.dialogReportVisible = true;
  998. this.pdfUrl = row.reportAddr;
  999. },
  1000. //下载pdf 文件
  1001. downLoadeAssetss(row) {
  1002. downloadPDF(row.reportAddr, row.reportName);
  1003. },
  1004. //插队接口
  1005. async insertQueue(row, index) {
  1006. this.$confirm(`确认插队?`, "提示", {
  1007. confirmButtonText: "确定",
  1008. cancelButtonText: "取消",
  1009. type: "warning",
  1010. })
  1011. .then(async () => {
  1012. const formData = new FormData();
  1013. formData.append("batchCode", row.batchCode);
  1014. formData.append("priority", index);
  1015. const result = await editPriority(formData);
  1016. if (result.code === 200) {
  1017. this.$message({
  1018. type: "success",
  1019. message: "插队成功",
  1020. });
  1021. await this.fetchData();
  1022. }
  1023. })
  1024. .catch(() => {});
  1025. },
  1026. //分析
  1027. handleAssetss(row) {
  1028. this.$router.push({
  1029. path: "/home/performance/editAssets",
  1030. query: {
  1031. batchCode: row.batchCode,
  1032. analysisTypeCode: row.analysisTypeCode,
  1033. fieldEngineCode: row.fieldCode,
  1034. fieldName: row.fieldName,
  1035. analysisName: row.analysisName,
  1036. },
  1037. });
  1038. },
  1039. //分析详情
  1040. handleAssetssDetail(row, state) {
  1041. const navigateToDetails = () => {
  1042. this.$router.push({
  1043. path: "/home/performance/overview",
  1044. query: {
  1045. batchCode: row.batchCode,
  1046. // analysisTypeCode: row.analysisTypeCode,
  1047. fieldCode: row.fieldCode,
  1048. },
  1049. });
  1050. };
  1051. if (state === "0") {
  1052. // 分析状态为分析中
  1053. this.$confirm(
  1054. "当前查看的分析记录为历史分析结果,最新分析记录还未分析完成不展示!",
  1055. )
  1056. .then(() => {
  1057. navigateToDetails();
  1058. })
  1059. .catch(() => {});
  1060. } else {
  1061. navigateToDetails();
  1062. }
  1063. },
  1064. abnormalDialog(row, title) {
  1065. this.dialogVisible = true;
  1066. if (title === "异常详情") {
  1067. this.errorInfo = row.errInfo;
  1068. this.rowInfo = {};
  1069. } else if (title === "机组异常记录") {
  1070. this.errorInfo = "";
  1071. this.rowInfo = { ...row };
  1072. } else if (title === "上传报告") {
  1073. this.errorInfo = "";
  1074. this.rowInfo = {};
  1075. this.rowInfo.batchCode = row.batchCode;
  1076. }
  1077. this.title = title;
  1078. },
  1079. handleConfirm() {
  1080. this.dialogVisible = false;
  1081. },
  1082. // 页码变化时才触发查询
  1083. handleCurrentChange(val) {
  1084. this.formInline.pageNum = val;
  1085. this.fetchData();
  1086. },
  1087. // 修改 getTableList 方法,避免重复请求
  1088. async getTableList() {
  1089. // 如果正在请求中,跳过此次调用
  1090. if (this.loading || this.isPolling) return;
  1091. this.loading = true;
  1092. try {
  1093. const params = { ...this.formInline, totalSize: undefined };
  1094. // 传递条件参数
  1095. if (this.formInline.analysisState !== undefined) {
  1096. params.analysisState = this.formInline.analysisState;
  1097. }
  1098. if (this.formInline.errState !== undefined) {
  1099. params.errState = this.formInline.errState;
  1100. }
  1101. const result = await analysisResultList(params);
  1102. this.tableData = result.data.list;
  1103. this.formInline.totalSize = result.data.totalSize;
  1104. } catch (error) {
  1105. this.$message({
  1106. type: "error",
  1107. message: "请检查是否连接网络",
  1108. });
  1109. } finally {
  1110. this.loading = false;
  1111. }
  1112. },
  1113. // 改进 handleMessage,避免频繁请求
  1114. handleMessage(event) {
  1115. // 确保消息来自当前域
  1116. if (event.origin !== window.location.origin) {
  1117. return;
  1118. }
  1119. const { fieldName, analysisState, errState } = event.data;
  1120. // 更新表单字段
  1121. if (fieldName !== undefined) {
  1122. this.formInline.fieldName = fieldName;
  1123. }
  1124. if (analysisState !== undefined) {
  1125. this.formInline.analysisState = analysisState;
  1126. }
  1127. if (errState !== undefined) {
  1128. this.formInline.errState = errState;
  1129. }
  1130. if (!this.loading) {
  1131. if (this.firstLoad && (analysisState || errState || fieldName)) {
  1132. // this.getTableList();
  1133. this.startPolling();
  1134. this.fetchData();
  1135. }
  1136. //
  1137. }
  1138. },
  1139. rowStyle() {
  1140. return "text-align:center";
  1141. },
  1142. // 重置
  1143. reset(formName) {
  1144. this.$refs[formName].resetFields();
  1145. this.formInline.fieldName = "";
  1146. this.formInline.analysisName = "";
  1147. this.formInline.analysisState = "";
  1148. this.formInline.errState = "";
  1149. this.fetchData();
  1150. },
  1151. // fetchData 方法在轮询中调用
  1152. async fetchData() {
  1153. if (
  1154. this.formInline.fieldName ||
  1155. this.formInline.analysisState ||
  1156. this.formInline.errState
  1157. ) {
  1158. this.firstLoad = false;
  1159. }
  1160. try {
  1161. const result = await analysisResultList({
  1162. ...this.formInline,
  1163. totalSize: undefined,
  1164. });
  1165. this.tableData = result.data.list;
  1166. this.formInline.totalSize = result.data.totalSize;
  1167. } catch (error) {
  1168. this.$message({
  1169. type: "error",
  1170. message: "请检查是否连接网络",
  1171. });
  1172. }
  1173. },
  1174. stopPolling() {
  1175. // 停止轮询
  1176. if (this.intervalId) {
  1177. clearInterval(this.intervalId);
  1178. this.intervalId = null;
  1179. }
  1180. this.isPolling = false;
  1181. },
  1182. // 启动轮询时,避免重复请求
  1183. startPolling() {
  1184. this.startTime = new Date().getTime();
  1185. this.isPolling = true;
  1186. this.intervalId = setInterval(() => {
  1187. const currentTime = new Date().getTime();
  1188. if (currentTime - this.startTime >= this.maxPollingTime) {
  1189. this.stopPolling();
  1190. } else {
  1191. // 轮询期间不重复请求,检查是否可以调用 fetchData
  1192. if (!this.loading) {
  1193. this.fetchData();
  1194. }
  1195. }
  1196. }, 10000); // 每10秒检查一次
  1197. },
  1198. //创建分析
  1199. Newanalyse() {
  1200. this.addDialogVisible = true;
  1201. this.getQueryCodeNumList();
  1202. },
  1203. examine() {
  1204. const targetUrl = this.$router.resolve({ name: "transition" }).href;
  1205. window.open(targetUrl, "_blank");
  1206. },
  1207. },
  1208. mounted() {
  1209. this.startPolling();
  1210. },
  1211. beforeDestroy() {
  1212. this.stopPolling();
  1213. // 销毁消息监听器
  1214. window.removeEventListener("message", this.handleMessage); //江
  1215. },
  1216. };
  1217. </script>
  1218. <style lang="scss" scoped>
  1219. @keyframes striped-flow {
  1220. from {
  1221. background-position: 0 100px;
  1222. }
  1223. to {
  1224. background-position: 1.25em 1.25em;
  1225. }
  1226. }
  1227. .general {
  1228. display: flex;
  1229. flex-wrap: wrap;
  1230. .condition {
  1231. width: 50%;
  1232. display: flex;
  1233. p {
  1234. width: 100px;
  1235. text-align: right;
  1236. line-height: 40px;
  1237. }
  1238. span {
  1239. line-height: 40px;
  1240. padding-left: 20px;
  1241. }
  1242. .el-select {
  1243. width: 100%;
  1244. margin-bottom: 20px;
  1245. }
  1246. .el-input {
  1247. margin-bottom: 20px;
  1248. }
  1249. }
  1250. }
  1251. .progress {
  1252. display: flex;
  1253. align-items: center;
  1254. position: fixed;
  1255. top: 25px;
  1256. right: 300px;
  1257. .progressText {
  1258. font-size: 14px;
  1259. color: #606266;
  1260. }
  1261. .el-progress {
  1262. width: 300px;
  1263. }
  1264. }
  1265. .attachment {
  1266. display: flex;
  1267. padding-top: 10px;
  1268. p {
  1269. margin-right: 20px;
  1270. color: #409eff;
  1271. }
  1272. }
  1273. .add-ruleForm {
  1274. .el-select {
  1275. width: 100%;
  1276. }
  1277. }
  1278. .addition {
  1279. display: flex;
  1280. justify-content: flex-end;
  1281. margin-bottom: 10px;
  1282. }
  1283. .demo-ruleForm {
  1284. .el-form-item {
  1285. margin-bottom: 25px;
  1286. }
  1287. }
  1288. ::v-deep .animated-progress .el-progress-bar__outer {
  1289. height: 15px; /* Adjust height as needed */
  1290. background-color: rgb(235, 238, 245);
  1291. background-image: linear-gradient(
  1292. 45deg,
  1293. rgba(0, 0, 0, 0.1) 25%,
  1294. transparent 25%,
  1295. transparent 50%,
  1296. rgba(0, 0, 0, 0.1) 50%,
  1297. rgba(0, 0, 0, 0.1) 75%,
  1298. transparent 75%,
  1299. transparent
  1300. );
  1301. background-size: 1.25em 1.25em;
  1302. animation: striped-flow 3s linear infinite;
  1303. }
  1304. .reportItemVal {
  1305. display: flex;
  1306. justify-content: space-between;
  1307. align-items: center;
  1308. .reportLeft {
  1309. margin-right: 50px;
  1310. }
  1311. }
  1312. ::v-deep .pdfDialog .el-dialog {
  1313. height: 100vh;
  1314. display: flex;
  1315. flex-direction: column;
  1316. margin: 0 auto !important;
  1317. .el-dialog__body {
  1318. // height: 100% !important;
  1319. flex: 1;
  1320. background: #fff;
  1321. .pdf-container {
  1322. display: flex;
  1323. justify-content: center;
  1324. align-items: center;
  1325. height: 100% !important;
  1326. }
  1327. }
  1328. }
  1329. canvas {
  1330. border: 1px solid #dcdfe6;
  1331. }
  1332. .right-align {
  1333. white-space: nowrap;
  1334. }
  1335. </style>