index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. <template>
  2. <div class="home" v-loading="loading">
  3. <div class="second">
  4. <div class="topPanel"></div>
  5. <div class="step">
  6. <div class="yuan">
  7. <div class="img yuanBg odd" @click="switchHandle('0')">
  8. <div class="tag">故障注入</div>
  9. </div>
  10. </div>
  11. <dv-decoration-6 style="width:150px;height:30px;"/>
  12. <div class="one">
  13. <div class="img oneBg even">
  14. <div class="tag">加噪</div>
  15. </div>
  16. </div>
  17. <dv-decoration-6 style="width:150px;height:30px;"/>
  18. <div class="three" @click="switchHandle('1')">
  19. <div class="img threeBg even">
  20. <div class="tag">功能验证</div>
  21. <div class="tag2">算法评估</div>
  22. </div>
  23. </div>
  24. <dv-decoration-6 style="width:150px;height:30px;"/>
  25. <div class="four">
  26. <div class="img fourBg">
  27. <div class="tag">结果分析</div>
  28. </div>
  29. </div>
  30. </div>
  31. <div class="bottomPanel">
  32. <div class="vanel"></div>
  33. <div class="bPanel">
  34. <!-- 第二个表格:显示noData数组内容 -->
  35. <el-table size="mini" :data="tableData2">
  36. <el-table-column
  37. prop="processedDataName"
  38. label="加噪后数据"
  39. align="center"
  40. >
  41. <template slot-scope="scope">
  42. <el-tooltip
  43. class="item"
  44. effect="dark"
  45. :content="scope.row.processedDataName"
  46. placement="top"
  47. >
  48. <span class="beforeFile" @click="dowloadfile(scope.row.processedDataName)">{{ scope.row.processedDataName }}</span>
  49. </el-tooltip>
  50. </template>
  51. </el-table-column>
  52. <el-table-column
  53. prop="resultDataName"
  54. label="处理后数据"
  55. align="center"
  56. >
  57. <template slot-scope="scope">
  58. <el-tooltip
  59. class="item"
  60. effect="dark"
  61. :content="scope.row.resultDataName"
  62. placement="top"
  63. >
  64. <span class="file" @click="dowloadfile(scope.row.resultDataName)" >{{ scope.row.resultDataName }}</span>
  65. </el-tooltip>
  66. </template>
  67. </el-table-column>
  68. <el-table-column
  69. prop="processStatus"
  70. label="状态"
  71. align="center"
  72. width="60"
  73. >
  74. <template slot-scope="scope">
  75. <dict-tag
  76. :options="dict.type.biz_process_status"
  77. :value="scope.row.processStatus"
  78. />
  79. </template>
  80. </el-table-column>
  81. </el-table>
  82. </div>
  83. <div class="bPanel">
  84. <el-table size="mini" :data="tableData1">
  85. <el-table-column
  86. prop="resultDataName"
  87. label="处理后数据"
  88. align="center"
  89. >
  90. <template slot-scope="scope">
  91. <el-tooltip
  92. class="item"
  93. effect="dark"
  94. :content="scope.row.resultDataName"
  95. placement="top"
  96. >
  97. <span class="file" @click="dowloadfile(scope.row.resultDataName)">{{ scope.row.resultDataName }}</span>
  98. </el-tooltip>
  99. </template>
  100. </el-table-column>
  101. <el-table-column
  102. prop="processStatus"
  103. label="状态"
  104. align="center"
  105. width="60"
  106. >
  107. <template slot-scope="scope">
  108. <dict-tag
  109. :options="dict.type.biz_process_status"
  110. :value="scope.row.processStatus"
  111. />
  112. </template>
  113. </el-table-column>
  114. </el-table>
  115. </div>
  116. <div class="vanel"></div>
  117. </div>
  118. </div>
  119. <div class="table-index" style="width: 100%;height: 500px;margin-top: 100px">
  120. <el-row style="padding: 10px" :gutter="10" class="mb8">
  121. <el-col :span="1.5">
  122. <el-button
  123. type="danger"
  124. plain
  125. icon="el-icon-delete"
  126. size="mini"
  127. :disabled="multiple"
  128. @click="handleDelete"
  129. v-hasPermi="['test:perf:remove']"
  130. >删除</el-button>
  131. </el-col>
  132. <el-col :span="1.5">
  133. <el-button
  134. type="warning"
  135. plain
  136. icon="el-icon-download"
  137. size="mini"
  138. @click="handleExport"
  139. :disabled="!canCompare"
  140. v-hasPermi="['test:perf:export']"
  141. >综合比对</el-button>
  142. </el-col>
  143. <right-toolbar
  144. :showSearch.sync="showSearch"
  145. @queryTable="getList"
  146. ></right-toolbar>
  147. </el-row>
  148. <el-table
  149. v-loading="loading"
  150. :data="perfList"
  151. v-show="showSearch"
  152. @selection-change="handleSelectionChange"
  153. >
  154. <el-table-column type="selection" width="55" align="center" />
  155. <el-table-column label="任务名称" align="center" prop="name" />
  156. <el-table-column
  157. label="噪声生成算法"
  158. align="center"
  159. prop="noseModelName"
  160. />
  161. <el-table-column
  162. label="故障诊断算法"
  163. align="center"
  164. prop="fdAlgorithmName"
  165. />
  166. <el-table-column label="文件结果" align="center" prop="resultFilePath">
  167. <template slot-scope="scope">
  168. <span @click="dowloadfile(scope.row.resultFilePath)">点击下载</span>
  169. </template>
  170. </el-table-column>
  171. <el-table-column label="图片结果" align="center" prop="resultImagePath">
  172. <template slot-scope="scope">
  173. <span @click="showimages(scope.row.resultImagePath)">查看图片</span>
  174. </template>
  175. </el-table-column>
  176. <el-table-column label="文本结果" align="center" prop="resultText" >
  177. <template slot-scope="scope">
  178. <el-input type="textarea" disabled v-model="scope.row.resultText" />
  179. </template>
  180. </el-table-column>
  181. <el-table-column
  182. label="开始时间"
  183. align="center"
  184. prop="startTime"
  185. width="180"
  186. >
  187. <template slot-scope="scope">
  188. <span>{{scope.row.startTime}}</span>
  189. </template>
  190. </el-table-column>
  191. <el-table-column
  192. label="结束时间"
  193. align="center"
  194. prop="endTime"
  195. width="180"
  196. >
  197. <template slot-scope="scope">
  198. <span>{{scope.row.endTime}}</span>
  199. </template>
  200. </el-table-column>
  201. <el-table-column
  202. label="操作"
  203. align="center"
  204. class-name="small-padding fixed-width"
  205. >
  206. <template slot-scope="scope">
  207. <el-button
  208. size="mini"
  209. type="text"
  210. icon="el-icon-video-play"
  211. @click="handleRun(scope.row)"
  212. v-hasPermi="['test:ddAlgorithm:edit']"
  213. >运行</el-button>
  214. <el-button
  215. size="mini"
  216. type="text"
  217. icon="el-icon-delete"
  218. @click="handleDelete(scope.row)"
  219. v-hasPermi="['test:perf:remove']"
  220. >删除</el-button>
  221. </template>
  222. </el-table-column>
  223. </el-table>
  224. </div>
  225. <form-model-view v-model="dialogVisible"
  226. @message="handleMessage"
  227. @allMessages="handleAllMessages"
  228. @callback="handleRowData"/>
  229. <!-- 比对结果对话框 -->
  230. <el-dialog
  231. fullscreen
  232. title="综合比对结果"
  233. :visible.sync="compareDialogVisible"
  234. width="80%"
  235. :before-close="handleCompareDialogClose"
  236. >
  237. <info-data :data-info="compareResult" />
  238. <template #footer>
  239. <span class="dialog-footer">
  240. <el-button @click="handleCompareDialogClose">关闭</el-button>
  241. <el-button type="primary" @click="exportCompareResult">导出结果</el-button>
  242. </span>
  243. </template>
  244. </el-dialog>
  245. </div>
  246. </template>
  247. <script>
  248. import CountTo from 'vue-count-to'
  249. import RingChart from '@/views/homePage/ringChart'
  250. import PreCharts from '@/views/homePage/preCharts'
  251. import CurveCharts from '@/views/homePage/curveCharts'
  252. import BarChart from '@/views/dashboard/BarChart'
  253. import infoData from './form.vue'
  254. import FormModelView from './add.vue'
  255. import FileTable from '@/views/fileTable.vue'
  256. import {
  257. listPerf,
  258. getPerf,
  259. delPerf,
  260. run,
  261. } from "@/api/test/perf";
  262. import dowloadService from '@/plugins/download'
  263. export default {
  264. name: 'Index',
  265. dicts: ['biz_alg_type', 'biz_process_status'],
  266. components: {
  267. FileTable,
  268. CountTo,
  269. RingChart,
  270. BarChart,
  271. PreCharts,
  272. CurveCharts,
  273. FormModelView,
  274. infoData
  275. },
  276. data() {
  277. return {
  278. showSearch: true,
  279. dialogVisible: false,
  280. loading: false,
  281. initFileData: {},
  282. messages: [],
  283. perfList: [],
  284. tableData1: [],
  285. tableData2: [],
  286. tableData3: [],
  287. queryParams: {
  288. pageNum: 1,
  289. pageSize: 10,
  290. },
  291. total: 0,
  292. ids: [],
  293. names: [],
  294. single: false,
  295. multiple: false,
  296. rowImageData: [],
  297. infoOpen: false,
  298. fileShowVisible: false,
  299. canCompare: false, // 控制综合比对按钮是否可用
  300. compareDialogVisible: false, // 比对结果对话框可见性
  301. compareResult: [] // 比对结果数据
  302. }
  303. },
  304. mounted() {
  305. this.$watch('messages', (newVal) => {
  306. if (newVal && newVal.length > 0) {
  307. this.parseMessagesData()
  308. }
  309. }, { deep: true })
  310. },
  311. created() {
  312. this.getList()
  313. },
  314. methods: {
  315. handleExport(){
  316. if (this.ids.length < 2) {
  317. this.$message({
  318. message: '请至少选择两条数据进行比对',
  319. type: 'warning'
  320. })
  321. return
  322. }
  323. try {
  324. // 合并所有选中行的resultText数据
  325. const allResults = []
  326. this.ids.forEach(id => {
  327. const row = this.perfList.find(item => item.id === id)
  328. if (row && row.resultText) {
  329. try {
  330. const resultItems = JSON.parse(row.resultText)
  331. allResults.push(...resultItems)
  332. console.log('allResults',allResults)
  333. } catch (e) {
  334. this.$message({
  335. message: `解析数据失败:${row.name}`,
  336. type: 'error'
  337. })
  338. }
  339. }
  340. })
  341. if (allResults.length === 0) {
  342. this.$message({
  343. message: '没有可比对的数据',
  344. type: 'warning'
  345. })
  346. return
  347. }
  348. // 去重处理(如果需要)
  349. const uniqueResults = this.removeDuplicates(allResults)
  350. // 保存比对结果并显示对话框
  351. this.compareResult = uniqueResults
  352. this.compareDialogVisible = true
  353. } catch (error) {
  354. console.error('综合比对失败', error)
  355. this.$message({
  356. message: '综合比对失败,请重试',
  357. type: 'error'
  358. })
  359. }
  360. },
  361. // 去重处理(根据filename和snr判断是否重复)
  362. removeDuplicates(data) {
  363. const seen = new Set()
  364. return data.filter(item => {
  365. const key = `${item.filename}_${item.snr}`
  366. if (seen.has(key)) {
  367. return false
  368. }
  369. seen.add(key)
  370. return true
  371. })
  372. },
  373. // 导出比对结果
  374. exportCompareResult() {
  375. if (this.compareResult.length === 0) {
  376. this.$message({
  377. message: '没有可导出的比对结果',
  378. type: 'warning'
  379. })
  380. return
  381. }
  382. // 创建CSV内容
  383. const headers = '文件名,模型,信噪比,准确率(%),精确率,召回率,F1分数,测试时间(ms),不确定性\n'
  384. const csvContent = headers + this.compareResult.map(item =>
  385. `${item.filename},${item.model},${item.snr},${item.accuracy},${item.precision},${item.recall},${item.f1_score},${item.test_time_ms},${item.uncertainty}`
  386. ).join('\n')
  387. // 创建Blob并下载
  388. const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })
  389. const url = URL.createObjectURL(blob)
  390. const link = document.createElement('a')
  391. link.setAttribute('href', url)
  392. link.setAttribute('download', `比对结果_${new Date().getTime()}.csv`)
  393. link.style.visibility = 'hidden'
  394. document.body.appendChild(link)
  395. link.click()
  396. document.body.removeChild(link)
  397. },
  398. handleCompareDialogClose() {
  399. this.compareDialogVisible = false
  400. },
  401. getList() {
  402. this.loading = true
  403. listPerf(this.queryParams).then((response) => {
  404. this.perfList = response.rows || [];
  405. this.total = response.total || 0;
  406. this.loading = false;
  407. }).catch(() => {
  408. this.loading = false;
  409. });
  410. },
  411. handleRun(data) {
  412. // 保存比对结果并显示对话框
  413. this.compareResult = JSON.parse(data.resultText)
  414. this.compareDialogVisible = true
  415. },
  416. handleSelectionChange(selection) {
  417. this.ids = selection.map((item) => item.id);
  418. this.names = selection.map((item) => item.name);
  419. this.single = selection.length !== 1;
  420. this.multiple = !selection.length;
  421. // 更新比对按钮状态
  422. this.canCompare = selection.length >= 2
  423. },
  424. dowloadfile(fileurl) {
  425. console.log('下载文件', fileurl);
  426. dowloadService.resource(fileurl)
  427. },
  428. showimages(data) {
  429. this.rowImageData = data ? JSON.parse(data) : [];
  430. this.infoOpen = true;
  431. },
  432. handleDelete(row) {
  433. const ids = row.id || this.ids;
  434. const names = row.name || this.names;
  435. this.$modal
  436. .confirm('是否确认删除算法性能评估名称为"' + names + '"的数据项?')
  437. .then(function () {
  438. return delPerf(ids);
  439. })
  440. .then(() => {
  441. this.getList();
  442. this.$modal.msgSuccess("删除成功");
  443. })
  444. .catch(() => {});
  445. },
  446. handleMessage(message) {
  447. this.messages.push(message);
  448. console.log('父组件接收到消息:', message);
  449. this.parseMessagesData()
  450. },
  451. handleAllMessages(allMessages) {
  452. this.messages = allMessages;
  453. console.log('父组件接收到所有消息:', allMessages);
  454. this.parseMessagesData()
  455. },
  456. handleDialogClose(visible) {
  457. this.dialogVisible = visible;
  458. },
  459. handleRowData(row) {
  460. this.dialogVisible = false
  461. this.getList();
  462. console.log('接收到文件管理的行数据:', row)
  463. this.initFileData = row
  464. },
  465. switchHandle(dataType) {
  466. switch (dataType) {
  467. case '0':
  468. this.dialogVisible = true
  469. break
  470. case '1':
  471. this.fileShowVisible = true
  472. break
  473. case '2':
  474. this.fileShowVisible = true
  475. this.$nextTick(() => {
  476. })
  477. break
  478. }
  479. },
  480. parseMessagesData() {
  481. try {
  482. // 清空之前的数据
  483. this.tableData1 = [];
  484. this.tableData2 = [];
  485. // 确保tableData1存在且为数组
  486. if (Array.isArray(this.messages) && this.messages.length > 0) {
  487. // 解析第一个元素:多个.mat文件URL
  488. const matUrlsString = this.messages[0];
  489. if (matUrlsString) {
  490. // 去除首尾方括号并按逗号分割
  491. const matUrls = matUrlsString.replace(/^\[|]$/g, '').split(',').map(url => url.trim());
  492. // 处理每个.mat文件URL,绑定到第二个表格(处理前数据)
  493. matUrls.forEach((url, index) => {
  494. this.tableData2.push({
  495. processedDataName: url,
  496. resultDataName: `处理后_${index + 1}`, // 假设的处理后数据,可根据实际情况修改
  497. processStatus: '1' // 假设状态为"已完成",可根据实际情况调整
  498. });
  499. });
  500. }
  501. // 解析第二个元素:.json文件URL
  502. const jsonUrl = this.messages[1];
  503. if (jsonUrl) {
  504. // 绑定到第一个表格(处理后数据)
  505. this.tableData1.push({
  506. resultDataName: jsonUrl,
  507. processStatus: '1' // 假设状态为"已完成"
  508. });
  509. }
  510. }
  511. } catch (error) {
  512. console.error('数据解析失败', error);
  513. this.tableData1 = [];
  514. this.tableData2 = [];
  515. }
  516. }
  517. }
  518. }
  519. </script>
  520. <style scoped lang="scss">
  521. @import "./index.scss";
  522. </style>