index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. <template>
  2. <div class="view-table-content">
  3. <div class="view-dataSpecies-left">
  4. <MenuTree :currentNodeKey="currentNodeKey" nodeKey="id" :treedata="menuTreeData" @TreeNodeclick="treeNodeClick" v-bind="treeObj"> </MenuTree>
  5. </div>
  6. <div class="view-dataSpecies-right" v-loading="loading">
  7. <div class="view-dataType-title">
  8. <div class="view-dataType-title-btn"></div>
  9. <div class="view-dataType-title-search">
  10. <el-input placeholder="请输入架次号" v-model="keyWordData" class="input1">
  11. <el-button slot="append" icon="el-icon-search" @click="searchClick"></el-button>
  12. </el-input>
  13. </div>
  14. </div>
  15. <div class="view-dataType-table">
  16. <LTable ref="table" @selection-change="selection" :defaultFetch="false" :fetch="fetch" :columns="columns" :dataSource="tableData" :options="options" :pagination="tableRequset"></LTable>
  17. </div>
  18. <el-dialog title="诊断结果" :visible.sync="resultVisible" width="1200px">
  19. <LTable ref="resultTable" :showColumnSetting="false" :defaultFetch="false" :columns="resultColumns" :dataSource="resultTableData" :options="resultOptions" :pagination="resultTableRequset"></LTable>
  20. </el-dialog>
  21. <el-dialog title="执行进度" :visible.sync="progressVisible" width="800px">
  22. <el-progress :text-inside="true" :stroke-width="24" :percentage="percentage" status="success"></el-progress>
  23. </el-dialog>
  24. <el-dialog title="结果展示" :visible.sync="resultShowVisible" :before-close="resultShowDialogClose" width="800px">
  25. <el-descriptions border :column="1">
  26. <el-descriptions-item label="评分">
  27. <div style="display: flex; align-items: center">
  28. <el-rate v-model="changeScore" disabled text-color="#ff9900" score-template="{value}"> </el-rate>
  29. <span style="margin-left: 3px; color: #f7ba2a; font-size: 1.2rem">{{ diagnosisResult.score }}</span>
  30. </div>
  31. </el-descriptions-item>
  32. <el-descriptions-item label="退化结果">
  33. <el-tag class="fault" style="margin-right: 20px" type="danger" v-for="(item, index) in diagnosisResult.degradation" :key="index" @click="handelQA(item)">{{ item }}</el-tag>
  34. </el-descriptions-item>
  35. <el-descriptions-item label="故障结果">
  36. <el-tag class="fault" style="margin-right: 20px" type="danger" v-for="(item, index) in diagnosisResult.fault" :key="index" @click="handelQA(item)">{{ item }}</el-tag>
  37. </el-descriptions-item>
  38. </el-descriptions>
  39. <span slot="footer" class="dialog-footer">
  40. <el-button type="primary" @click="resultShowDialogClose">确 定</el-button>
  41. </span>
  42. </el-dialog>
  43. <el-dialog title="问答结果" :visible.sync="QAVisible" width="1000px" :before-close="QADialogClose">
  44. <div style="color: white; font-size: 20px; margin-bottom: 20px">
  45. {{ QAData.graphAnswer.answer }}
  46. </div>
  47. <graphECharts :width="950" :height="400" :graphData="QAData.graphAnswer.graph"></graphECharts>
  48. <span slot="footer" class="dialog-footer">
  49. <el-button type="primary" @click="QAVisible = false">确 定</el-button>
  50. </span>
  51. </el-dialog>
  52. </div>
  53. </div>
  54. </template>
  55. <script>
  56. import store from '@/store'
  57. import { getDataImport } from '@/api/als/dataImport'
  58. import { getFaultDiagnosisResult } from '@/api/als/faultDiagnosisResult'
  59. import { getAircaftCatalogTree } from '@/api/als/sideTree'
  60. import { getAircaftCatalogAll } from '@/api/als/aircraft'
  61. import { deepClone, debounce } from '@/utils/index'
  62. import { handleTree, flattenTree } from '../utils/common'
  63. import { getAirConfiguration } from '@/api/als/airConfiguration'
  64. import { executeFault } from '@/api/als/algorithm'
  65. import { getListByIdsApi } from '@/api/als/oss'
  66. import { handlerQAndA } from '@/api/als/intelligentQA'
  67. import graphECharts from '@/views/als/components/Charts/graph.vue'
  68. export default {
  69. name: 'FaultDiagnosis',
  70. components: { graphECharts },
  71. data() {
  72. // 这里存放数据
  73. return {
  74. loading: false,
  75. resultVisible: false,
  76. progressVisible: false,
  77. resultShowVisible: false,
  78. QAVisible: false,
  79. keyWordData: '',
  80. aircaftModelIdList: [],
  81. currentNodeKey: '',
  82. currentNode: {},
  83. menuTreeData: [],
  84. treeObj: {
  85. title: '所属机种',
  86. activityheight: '275px',
  87. searchIcon: false,
  88. configure: {
  89. children: 'children',
  90. label: 'label'
  91. }
  92. },
  93. typeTree: {
  94. children: 'children',
  95. label: 'label'
  96. },
  97. searchValue: '',
  98. columns: [
  99. {
  100. prop: 'aircraftId',
  101. label: '编目',
  102. render: (h, params) => {
  103. const matchedItem = this.aircaftCatalogAll.find((item) => params.row.aircraftId.trim() === item.aircaftCatalogId.trim())
  104. if (matchedItem) {
  105. return h('span', matchedItem.aircaftCatalogCode)
  106. } else {
  107. return h('span', {}, '')
  108. }
  109. }
  110. },
  111. {
  112. prop: 'sortieNo',
  113. label: '架次号'
  114. },
  115. {
  116. prop: 'flightDate',
  117. label: '飞行时间'
  118. },
  119. {
  120. prop: 'source',
  121. label: '数据源',
  122. render: (h, params) => {
  123. if (params.row.source == 1) {
  124. return h('span', '飞参数据')
  125. } else {
  126. return h('span', 'MDC数据')
  127. }
  128. }
  129. },
  130. {
  131. prop: 'status',
  132. label: '状态',
  133. // 1 未处理,2 已处理
  134. render: (h, params) => {
  135. if (params.row.status == '1') {
  136. return h('span', '未处理')
  137. } else if (params.row.status == '2') {
  138. return h('span', { class: 'success-state' }, '已处理')
  139. } else {
  140. return h('span', { class: 'warning-state' }, '异常')
  141. }
  142. }
  143. },
  144. {
  145. button: true,
  146. label: '操作',
  147. width: '240px',
  148. group: [
  149. {
  150. name: '故障诊断',
  151. type: 'text',
  152. round: false,
  153. plain: false,
  154. onClick: (row, index, scope) => {
  155. this.faultExecute(row)
  156. }
  157. },
  158. {
  159. name: '查看',
  160. type: 'text',
  161. statusKey: 'status',
  162. unDisableKey: '2',
  163. round: false,
  164. plain: false,
  165. onClick: (row, index, scope) => {
  166. this.checkRelustList(row)
  167. }
  168. }
  169. ]
  170. }
  171. ],
  172. options: {
  173. stripe: false, // 斑马纹
  174. mutiSelect: true, // 多选框
  175. index: false, // 显示序号, 多选则 mutiSelect
  176. loading: false, // 表格动画
  177. initTable: false, // 是否一挂载就加载数据
  178. border: true,
  179. height: 'calc(100vh - 300px)'
  180. },
  181. tableCheckItems: [],
  182. tableData: [],
  183. tableRequset: {
  184. total: 0,
  185. pageIndex: 1,
  186. pageSize: 20,
  187. searchValue: ''
  188. },
  189. resultColumns: [
  190. {
  191. prop: 'modelType',
  192. label: '算法名称'
  193. },
  194. {
  195. prop: 'createTime',
  196. label: '执行时间',
  197. render: (h, params) => {
  198. return h('span', params.row.createTime.split(' ')[0])
  199. }
  200. },
  201. {
  202. prop: 'status',
  203. label: '状态',
  204. render: (h, params) => {
  205. return h('span', { class: 'success-state' }, '成功')
  206. }
  207. },
  208. {
  209. button: true,
  210. label: '结果',
  211. width: '240px',
  212. group: [
  213. {
  214. name: '查看结果',
  215. type: 'text',
  216. round: false,
  217. plain: false,
  218. onClick: (row, index, scope) => {
  219. this.checkRelustShow(row)
  220. }
  221. }
  222. ]
  223. }
  224. ],
  225. resultOptions: {
  226. stripe: false, // 斑马纹
  227. mutiSelect: true, // 多选框
  228. index: false, // 显示序号, 多选则 mutiSelect
  229. loading: false, // 表格动画
  230. initTable: false, // 是否一挂载就加载数据
  231. border: true,
  232. height: 'calc(100vh - 600px)'
  233. },
  234. resultTableCheckItems: [],
  235. resultTableData: [],
  236. resultTableRequset: {
  237. total: 0,
  238. pageIndex: 1,
  239. pageSize: 10,
  240. searchValue: ''
  241. },
  242. debounceFn: debounce(this.fetch, 500),
  243. aircaftCatalogAll: [],
  244. form: {
  245. id: '',
  246. sortieNo: '',
  247. ossId: '',
  248. aircraftId: '',
  249. aircraftType: '',
  250. flightDate: '',
  251. status: '',
  252. result: '',
  253. partId: null
  254. },
  255. currentSortieNo: '',
  256. partsData: [],
  257. allAirConfig: [],
  258. percentage: 0,
  259. resultShowData: {
  260. url: '',
  261. result: ''
  262. },
  263. diagnosisResult: {
  264. degradation: [],
  265. fault: [],
  266. score: null
  267. },
  268. changeScore: null,
  269. QAData: {
  270. userId: '',
  271. graphAnswer: {}
  272. }
  273. }
  274. },
  275. watch: {
  276. keyWord() {
  277. this.tableRequset.pageIndex = 1
  278. this.debounceFn()
  279. }
  280. },
  281. computed: {},
  282. mounted() {
  283. this.getAircaftCatalogTreeAPI()
  284. },
  285. methods: {
  286. async getAircaftCatalogTreeAPI(params) {
  287. try {
  288. const { data } = await getAircaftCatalogTree(params)
  289. this.menuTreeData = data
  290. const getAircaftCatalogAllParams = {
  291. keyWord: '',
  292. aircaftModelIdList: []
  293. }
  294. const { data: data2 } = await getAircaftCatalogAll(getAircaftCatalogAllParams)
  295. this.aircaftCatalogAll = data2
  296. const { data: airConfigData } = await getAirConfiguration()
  297. this.allAirConfig = airConfigData
  298. if (data.length) {
  299. this.currentNodeKey = data[0].id
  300. this.currentNode = data[0]
  301. this.aircaftModelIdList = this.getTreeLeafData(data[0]?.children)
  302. .map((e) => e.id)
  303. .toString()
  304. this.getDataImportAPI({ aircraftId: this.aircaftModelIdList })
  305. }
  306. } catch (error) {}
  307. },
  308. getTreeLeafData(list) {
  309. const newArr = []
  310. function getLeaf(data, arr) {
  311. data.forEach((e) => {
  312. if (e.type === 2) {
  313. arr.push(e)
  314. }
  315. if (e.children.length) {
  316. getLeaf(e.children, arr)
  317. }
  318. })
  319. }
  320. getLeaf(list, newArr)
  321. return newArr
  322. },
  323. async getFaultDiagnosisResultAPI(params) {
  324. if (this.$refs.resultTable) this.$refs.resultTable.clearSelection()
  325. const { pageSize, pageIndex } = this.resultTableRequset
  326. const {
  327. data: { list, total }
  328. } = await getFaultDiagnosisResult({ pageSize, pageNum: pageIndex, ...params })
  329. this.resultTableData = list
  330. this.resultTableRequset.total = total
  331. },
  332. async getDataImportAPI(params) {
  333. if (this.$refs.table) this.$refs.table.clearSelection()
  334. const { keyWord } = this
  335. const { pageSize, pageIndex } = this.tableRequset
  336. const {
  337. data: { list, total }
  338. } = await getDataImport({ pageSize, pageNum: pageIndex, ...params, source: 1 })
  339. this.tableData = list
  340. this.tableRequset.total = total
  341. },
  342. fetch() {
  343. this.getDataImportAPI({ aircraftId: this.aircaftModelIdList })
  344. },
  345. async searchClick() {
  346. this.getDataImportAPI({ aircraftId: this.aircaftModelIdList, sortieNo: this.keyWordData })
  347. },
  348. treeNodeClick(data) {
  349. this.$refs.table.clearSelection()
  350. this.currentNodeKey = data.id
  351. this.currentNode = data
  352. this.aircaftModelIdList = this.getTreeLeafData(data.children.length ? data.children : [data])
  353. .map((e) => e.id)
  354. .toString()
  355. if (!this.aircaftModelIdList) {
  356. this.aircaftModelIdList = '#'
  357. }
  358. this.getDataImportAPI({ aircraftId: this.aircaftModelIdList })
  359. },
  360. async getAirConfigurationAPI(params) {
  361. try {
  362. const { data } = await getAirConfiguration(params)
  363. const treeData = handleTree(data, 'id')
  364. this.partsData = treeData
  365. } catch (error) {}
  366. },
  367. faultExecute(row) {
  368. this.form = deepClone(row)
  369. const allAir = flattenTree(this.menuTreeData)
  370. const item = allAir.find((item) => item.id === this.form.aircraftId)
  371. this.form.aircraftType = item.parentId
  372. this.currentSortieNo = row.sortieNo
  373. this.beginExecute(row)
  374. },
  375. partIdSelect(node) {
  376. this.form.partId = node.id
  377. },
  378. normalizer(node) {
  379. if (node.children && !node.children.length) {
  380. delete node.children
  381. }
  382. return {
  383. id: node.id,
  384. label: node.name,
  385. children: node.children
  386. }
  387. },
  388. handleClose() {
  389. this.currentSortieNo = ''
  390. this.form = {
  391. id: '',
  392. sortieNo: '',
  393. ossId: '',
  394. aircraftId: '',
  395. aircraftType: '',
  396. flightDate: '',
  397. status: '',
  398. result: '',
  399. partId: null
  400. }
  401. },
  402. resultShowDialogClose() {
  403. this.resultShowVisible = false
  404. this.diagnosisResult = {
  405. degradation: [],
  406. fault: [],
  407. score: null
  408. }
  409. this.changeScore = null
  410. },
  411. submit() {
  412. this.beginExecute(row)
  413. },
  414. selection(val) {
  415. this.tableCheckItems = val
  416. },
  417. async checkRelustList(row) {
  418. this.getFaultDiagnosisResultAPI({ diagnosisId: row.id })
  419. this.resultVisible = true
  420. },
  421. checkRelustShow(row) {
  422. const resData = JSON.parse(row.resultContent)
  423. this.changeScore = resData.score / 20
  424. this.diagnosisResult = resData
  425. this.resultShowVisible = true
  426. },
  427. async getImgUrl(ossId) {
  428. const { data } = await getListByIdsApi(ossId)
  429. const newUrl = data[0].url
  430. return newUrl
  431. },
  432. async beginExecute(row) {
  433. this.progressVisible = true
  434. let myTimer = setInterval(() => {
  435. if (this.percentage < 100) {
  436. if (this.percentage === 99) {
  437. this.percentage = 99
  438. } else {
  439. this.percentage += 1
  440. }
  441. }
  442. }, 30)
  443. try {
  444. this.form.dataId = row.id
  445. const res = await executeFault(this.form)
  446. clearInterval(myTimer)
  447. if (res?.code === 200) {
  448. this.percentage = 100
  449. this.$message({
  450. type: 'success',
  451. message: '执行成功!'
  452. })
  453. const resData = JSON.parse(res.data)
  454. this.changeScore = resData.score / 20
  455. this.diagnosisResult = resData
  456. // this.resultVisible = true
  457. this.resultShowVisible = true
  458. this.getDataImportAPI({ aircraftId: this.aircaftModelIdList })
  459. this.handleClose()
  460. }
  461. } catch (error) {
  462. clearInterval(myTimer)
  463. } finally {
  464. this.progressVisible = false
  465. this.percentage = 0
  466. }
  467. },
  468. async handelQA(question) {
  469. this.loading = true
  470. const sendInput = {
  471. question: question,
  472. userId: String(store.state.user.userInfo.user.userId)
  473. }
  474. try {
  475. if (question.trim() === '') {
  476. return
  477. }
  478. // const { code, data } = await handlerQAndA(sendInput)
  479. const { code, data } = {
  480. code: 200,
  481. msg: '',
  482. data: {
  483. userId: 'user',
  484. graphAnswer: {
  485. answer: '解决办法为:更换电池或遥控器',
  486. fileName: '排故手册',
  487. ossId: '227701077942149120', //pdf
  488. // ossID: '227692224508796928', //word
  489. filePage: 2,
  490. graph: {
  491. data: [
  492. { name: '202310150010', category: 'HMC' },
  493. { name: '电视', category: '成品' },
  494. { name: '电视遥控器失灵', category: '故障描述' },
  495. { name: '家用电器', category: '系统' },
  496. { name: '更换电池或遥控器', category: '维修策略' }
  497. ],
  498. links: [
  499. { source: '202310150010', target: '电视', value: '成品' },
  500. { source: '202310150010', target: '电视遥控器失灵', value: '故障描述' },
  501. { source: '202310150010', target: '家用电器', value: '系统' },
  502. { source: '202310150010', target: '更换电池或遥控器', value: '维修策略' }
  503. ]
  504. }
  505. }
  506. }
  507. }
  508. if (code == 200) {
  509. // const newData = this.handleData(JSON.parse(data))
  510. this.QAData = this.handleData(data)
  511. this.loading = false
  512. this.QAVisible = true
  513. }
  514. } catch (error) {}
  515. },
  516. handleData(data) {
  517. if (data.graphAnswer?.graph) {
  518. // const graphAnswer = eval('(' + data.graphAnswer.graph + ')')
  519. // data.graphAnswer.graph = graphAnswer
  520. const categories = []
  521. data.graphAnswer.graph.data.forEach((node) => {
  522. const flag = categories.find((item) => {
  523. return item.name === node.category
  524. })
  525. if (!flag) {
  526. categories.push({ name: node.category })
  527. }
  528. })
  529. data.graphAnswer.graph.categories = categories
  530. }
  531. return data
  532. },
  533. QADialogClose() {
  534. this.QAData = {
  535. userId: '',
  536. graphAnswer: {}
  537. }
  538. this.QAVisible = false
  539. }
  540. }
  541. }
  542. </script>
  543. <style lang="scss" scoped>
  544. @import '../index.scss';
  545. .fault {
  546. cursor: pointer;
  547. }
  548. </style>