index.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. <template>
  2. <div class="table-box">
  3. <ProTable ref="proTable" :columns="columns" row-key="id" :request-api="listMatchApi">
  4. <!-- 表格 header 按钮 -->
  5. <template #tableHeader="scope">
  6. <el-button type="primary" @click="openCreateDialog" v-show="true || scope">创建任务</el-button>
  7. <!-- <el-button type="primary" v-auth="['demo:match:add']" icon="CirclePlus" @click="openDialog(1, '异源图像匹配新增')">-->
  8. <!-- 新增-->
  9. <!-- </el-button>-->
  10. <!-- <el-button type="primary" v-auth="['demo:match:import']" icon="Upload" plain @click="batchAdd">-->
  11. <!-- 导入-->
  12. <!-- </el-button>-->
  13. <!-- <el-button type="primary" v-auth="['demo:match:export']" icon="Download" plain @click="downloadFile">-->
  14. <!-- 导出-->
  15. <!-- </el-button>-->
  16. <!-- <el-button-->
  17. <!-- type="danger"-->
  18. <!-- v-auth="['demo:match:remove']"-->
  19. <!-- icon="Delete"-->
  20. <!-- plain-->
  21. <!-- :disabled="!scope.isSelected"-->
  22. <!-- @click="batchDelete(scope.selectedListIds)"-->
  23. <!-- >-->
  24. <!-- 批量删除-->
  25. <!-- </el-button>-->
  26. </template>
  27. <!-- 表格操作 -->
  28. <template #operation="scope">
  29. <el-button type="primary" icon="View" link @click="doExecute(scope.row)">开始任务</el-button>
  30. <el-button type="primary" icon="View" link @click="showData(scope.row)">执行结果</el-button>
  31. <el-button type="primary" icon="View" link @click="showLog(scope.row)">查看日志</el-button>
  32. <el-button type="primary" icon="View" link @click="showResult(scope.row)">查看指标</el-button>
  33. <!-- <el-button-->
  34. <!-- type="primary"-->
  35. <!-- link-->
  36. <!-- icon="View"-->
  37. <!-- v-auth="['demo:match:query']"-->
  38. <!-- @click="openDialog(3, '异源图像匹配查看', scope.row)"-->
  39. <!-- >-->
  40. <!-- 查看-->
  41. <!-- </el-button>-->
  42. <!-- <el-button-->
  43. <!-- type="primary"-->
  44. <!-- link-->
  45. <!-- icon="EditPen"-->
  46. <!-- v-auth="['demo:match:edit']"-->
  47. <!-- @click="openDialog(2, '异源图像匹配编辑', scope.row)"-->
  48. <!-- >-->
  49. <!-- 编辑-->
  50. <!-- </el-button>-->
  51. <el-button type="primary" link icon="Delete" v-auth="['demo:match:remove']" @click="deleteMatch(scope.row)"> 删除 </el-button>
  52. </template>
  53. </ProTable>
  54. <FormDialog ref="formDialogRef" />
  55. <ImportExcel ref="dialogRef" />
  56. <el-dialog v-if="dialogVisible" v-model="dialogVisible" title="创建任务">
  57. <el-container>
  58. <span class="span_class">任务名称</span>
  59. <el-input v-model="formData.name" placeholder="请输入任务名称"></el-input>
  60. </el-container>
  61. <el-container style="margin-top: 20px">
  62. <span class="span_class">任务文件</span>
  63. <file @update:model-value="updateFile" :file-size="2048" :file-type="['zip']"></file>
  64. </el-container>
  65. <el-button type="primary" @click="doCreateTask">创建</el-button>
  66. </el-dialog>
  67. <el-dialog v-model="dataDialogVisible" title="执行结果">
  68. <el-container direction="vertical">
  69. <el-container direction="horizontal">
  70. <el-container direction="vertical">
  71. <span>hw</span>
  72. <el-image :src="resultData.url1Prefix + resultData.url1 + results[pageination]" />
  73. </el-container>
  74. <el-container direction="vertical">
  75. <span>kjg</span>
  76. <el-image :src="resultData.url1Prefix + resultData.url2 + results[pageination]" />
  77. </el-container>
  78. </el-container>
  79. <el-container direction="horizontal" style="margin-top: 20px">
  80. <el-container direction="vertical">
  81. <span>overlay_before_registration</span>
  82. <el-image :src="resultData.url2Prefix + resultData.url3 + results[pageination]" />
  83. </el-container>
  84. <el-container direction="vertical">
  85. <span>overlay_after_registration</span>
  86. <el-image :src="resultData.url2Prefix + resultData.url4 + results[pageination]" />
  87. </el-container>
  88. </el-container>
  89. <el-container direction="horizontal" style="margin-top: 20px">
  90. <el-container direction="vertical">
  91. <span>IR_VIS_obj_in_IR</span>
  92. <el-image :src="resultData.url2Prefix + resultData.url5 + results[pageination]" />
  93. </el-container>
  94. <el-container direction="vertical">
  95. <span>VIS_obj_in_VIS</span>
  96. <el-image :src="resultData.url2Prefix + resultData.url6 + results[pageination]" />
  97. </el-container>
  98. </el-container>
  99. <el-container direction="vertical" style="margin-top: 20px">
  100. <span>coordinates_in_IR.txt</span>
  101. <el-container v-for="(item, index) in txtData" :key="index">
  102. {{ item }}
  103. </el-container>
  104. </el-container>
  105. </el-container>
  106. <el-pagination layout="prev, pager, next" :page-count="results.length" @change="changePage"></el-pagination>
  107. </el-dialog>
  108. <el-dialog v-model="logVisible" title="查看日志">
  109. <el-container direction="vertical">
  110. <el-container v-for="(item, index) in logData" :key="index">
  111. {{ item }}
  112. </el-container>
  113. </el-container>
  114. </el-dialog>
  115. <ResultDialog ref="ResultDialogRef" />
  116. </div>
  117. </template>
  118. <script setup lang="tsx" name="Match">
  119. import { ref, reactive } from 'vue'
  120. import { useHandleData } from '@/hooks/useHandleData'
  121. import { useDownload } from '@/hooks/useDownload'
  122. import { ElMessage, ElMessageBox } from 'element-plus'
  123. import ProTable from '@/components/ProTable/index.vue'
  124. import ImportExcel from '@/components/ImportExcel/index.vue'
  125. import FormDialog from '@/components/FormDialog/index.vue'
  126. import { ProTableInstance, ColumnProps } from '@/components/ProTable/interface'
  127. import {
  128. listMatchApi,
  129. delMatchApi,
  130. addMatchApi,
  131. updateMatchApi,
  132. importTemplateApi,
  133. importMatchDataApi,
  134. exportMatchApi,
  135. getMatchApi,
  136. createTask,
  137. execute,
  138. getResult
  139. } from '@/api/modules/demo/match'
  140. import File from '@/components/Upload/File.vue'
  141. import { getDictsApi } from '@/api/modules/system/dictData'
  142. import ResultDialog from '@/components/ResultDialog/ResultDialog.vue'
  143. import http from '@/api'
  144. const logVisible = ref(false)
  145. const logData = ref([])
  146. const showLog = async function (row) {
  147. let arr = row.resultPath.split('ObjectDetection_Web')
  148. let res = await http.get('/profile' + arr[arr.length - 1] + '/log.log')
  149. logData.value = res.split('\n')
  150. logVisible.value = true
  151. }
  152. const resultData = ref({
  153. url1Prefix: '',
  154. url2Prefix: '',
  155. url1: 'hw/',
  156. url2: 'kjg/',
  157. url3: '/overlay_before_registration/',
  158. url4: '/overlay_after_registration/',
  159. url5: '/IR_VIS_obj_in_IR/',
  160. url6: '/VIS_obj_in_VIS/'
  161. })
  162. const changePage = function (data) {
  163. pageination.value = data - 1
  164. }
  165. const pageination = ref(0)
  166. const results = ref([])
  167. const dataDialogVisible = ref(false)
  168. const txtData = ref([])
  169. const showData = function (row) {
  170. getResult({ taskId: row.id }).then(res => {
  171. if (res.code === 200) {
  172. let arr = row.resultPath.split('/ObjectDetection_Web')
  173. resultData.value.url2Prefix = '/api/profile' + arr[arr.length - 1]
  174. arr = row.preprocessPath.split('/ObjectDetection_Web')
  175. resultData.value.url1Prefix = '/api/profile' + arr[arr.length - 1] + '/input/'
  176. results.value = res.data
  177. pageination.value = 0
  178. http
  179. .get(resultData.value.url2Prefix.replace('/api', '') + '/coordinates_in_IR.txt')
  180. .then(res => {
  181. txtData.value = res.split('\n')
  182. dataDialogVisible.value = true
  183. })
  184. .catch(err => {
  185. ElMessage.error('获取coordinates_in_IR.txt失败')
  186. })
  187. console.log(resultData.value)
  188. } else {
  189. ElMessage.error('获取结果失败!')
  190. }
  191. })
  192. }
  193. const ResultDialogRef = ref<InstanceType<typeof ResultDialog> | null>(null)
  194. const showResult = async function (row) {
  195. let path = row.resultPath.split('ObjectDetection_Web')
  196. path = path[path.length - 1]
  197. let result = await http.get('/profile' + path + '/result.json')
  198. ResultDialogRef.value.openDialog(result)
  199. }
  200. const doExecute = function (row) {
  201. execute({ taskId: row.id }).then(res => {
  202. console.log(res)
  203. })
  204. }
  205. const dialogVisible = ref(false)
  206. const openCreateDialog = function () {
  207. formData.value = {
  208. name: '',
  209. file: null
  210. }
  211. dialogVisible.value = true
  212. }
  213. const formData = ref({
  214. name: '',
  215. file: null
  216. })
  217. const doCreateTask = function () {
  218. createTask(formData.value).then(res => {
  219. if (res.code === 200) {
  220. dialogVisible.value = false
  221. ElMessage.success('创建成功')
  222. proTable.value.getTableList()
  223. } else {
  224. ElMessage.error('创建失败,' + res.msg)
  225. }
  226. })
  227. }
  228. const updateFile = function (fileId) {
  229. // console.log('catch')
  230. formData.value.file = fileId
  231. }
  232. // ProTable 实例
  233. const proTable = ref<ProTableInstance>()
  234. // 删除异源图像匹配信息
  235. const deleteMatch = async (params: any) => {
  236. await useHandleData(delMatchApi, params.id, '删除【' + params.id + '】异源图像匹配')
  237. proTable.value?.getTableList()
  238. }
  239. // 批量删除异源图像匹配信息
  240. const batchDelete = async (ids: string[]) => {
  241. await useHandleData(delMatchApi, ids, '删除所选异源图像匹配信息')
  242. proTable.value?.clearSelection()
  243. proTable.value?.getTableList()
  244. }
  245. // 导出异源图像匹配列表
  246. const downloadFile = async () => {
  247. ElMessageBox.confirm('确认导出异源图像匹配数据?', '温馨提示', { type: 'warning' }).then(() =>
  248. useDownload(exportMatchApi, '异源图像匹配列表', proTable.value?.searchParam)
  249. )
  250. }
  251. // 批量添加异源图像匹配
  252. const dialogRef = ref<InstanceType<typeof ImportExcel> | null>(null)
  253. const batchAdd = () => {
  254. const params = {
  255. title: '异源图像匹配',
  256. tempApi: importTemplateApi,
  257. importApi: importMatchDataApi,
  258. getTableList: proTable.value?.getTableList
  259. }
  260. dialogRef.value?.acceptParams(params)
  261. }
  262. const formDialogRef = ref<InstanceType<typeof FormDialog> | null>(null)
  263. // 打开弹框的功能
  264. const openDialog = async (type: number, title: string, row?: any) => {
  265. let res = { data: {} }
  266. if (row?.id) {
  267. res = await getMatchApi(row?.id || null)
  268. }
  269. // 重置表单
  270. setItemsOptions()
  271. const params = {
  272. title,
  273. width: 580,
  274. isEdit: type !== 3,
  275. itemsOptions: itemsOptions,
  276. model: type == 1 ? {} : res.data,
  277. api: type == 1 ? addMatchApi : updateMatchApi,
  278. getTableList: proTable.value?.getTableList
  279. }
  280. formDialogRef.value?.openDialog(params)
  281. }
  282. // 表格配置项
  283. const columns = reactive<ColumnProps<any>[]>([
  284. { type: 'selection', fixed: 'left', width: 70 },
  285. { prop: 'id', label: '主键ID' },
  286. {
  287. prop: 'name',
  288. label: '任务名称',
  289. search: {
  290. el: 'input'
  291. },
  292. width: 120
  293. },
  294. {
  295. prop: 'status',
  296. label: '任务状态',
  297. search: {
  298. el: 'input'
  299. },
  300. width: 120,
  301. tag: true,
  302. enum: () => getDictsApi('biz_task_status'),
  303. fieldNames: { label: 'dictLabel', value: 'dictValue' }
  304. },
  305. {
  306. prop: 'parameters',
  307. label: '调用算法时所用的参数',
  308. search: {
  309. el: 'input'
  310. },
  311. width: 120
  312. },
  313. {
  314. prop: 'preprocessPath',
  315. label: '预处理数据路径',
  316. search: {
  317. el: 'input'
  318. },
  319. width: 120
  320. },
  321. {
  322. prop: 'resultPath',
  323. label: '结果数据路径',
  324. search: {
  325. el: 'input'
  326. },
  327. width: 120
  328. },
  329. {
  330. prop: 'startTime',
  331. label: '开始时间',
  332. search: {
  333. el: 'date-picker',
  334. props: { type: 'datetimerange', valueFormat: 'YYYY-MM-DD HH:mm:ss' }
  335. },
  336. width: 120
  337. },
  338. {
  339. prop: 'endTime',
  340. label: '结束时间',
  341. search: {
  342. el: 'date-picker',
  343. props: { type: 'datetimerange', valueFormat: 'YYYY-MM-DD HH:mm:ss' }
  344. },
  345. width: 120
  346. },
  347. {
  348. prop: 'costSecond',
  349. label: '耗时',
  350. search: {
  351. el: 'input'
  352. },
  353. width: 120
  354. },
  355. {
  356. prop: 'remarks',
  357. label: '备注',
  358. search: {
  359. el: 'input'
  360. },
  361. width: 120
  362. },
  363. { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
  364. ])
  365. // 表单配置项
  366. let itemsOptions: ProForm.ItemsOptions[] = []
  367. const setItemsOptions = () => {
  368. itemsOptions = [
  369. {
  370. label: '任务名称',
  371. prop: 'name',
  372. rules: [{ required: true, message: '任务名称不能为空', trigger: 'blur' }],
  373. compOptions: {
  374. placeholder: '请输入任务名称'
  375. }
  376. },
  377. {
  378. label: '任务状态',
  379. prop: 'status',
  380. rules: [{ required: true, message: '任务状态不能为空', trigger: 'blur' }],
  381. compOptions: {
  382. placeholder: '请输入任务状态'
  383. }
  384. },
  385. {
  386. label: '调用算法时所用的参数',
  387. prop: 'parameters',
  388. rules: [{ required: true, message: '调用算法时所用的参数不能为空', trigger: 'blur' }],
  389. compOptions: {
  390. type: 'textarea',
  391. clearable: true,
  392. placeholder: '请输入内容'
  393. }
  394. },
  395. {
  396. label: '预处理数据路径',
  397. prop: 'preprocessPath',
  398. rules: [{ required: true, message: '预处理数据路径不能为空', trigger: 'blur' }],
  399. compOptions: {
  400. placeholder: '请输入预处理数据路径'
  401. }
  402. },
  403. {
  404. label: '结果数据路径',
  405. prop: 'resultPath',
  406. rules: [{ required: true, message: '结果数据路径不能为空', trigger: 'blur' }],
  407. compOptions: {
  408. placeholder: '请输入结果数据路径'
  409. }
  410. },
  411. {
  412. label: '开始时间',
  413. prop: 'startTime',
  414. rules: [{ required: true, message: '开始时间不能为空', trigger: 'change' }],
  415. compOptions: {
  416. elTagName: 'date-picker',
  417. type: 'date',
  418. placeholder: '请选择开始时间'
  419. }
  420. },
  421. {
  422. label: '结束时间',
  423. prop: 'endTime',
  424. rules: [{ required: true, message: '结束时间不能为空', trigger: 'change' }],
  425. compOptions: {
  426. elTagName: 'date-picker',
  427. type: 'date',
  428. placeholder: '请选择结束时间'
  429. }
  430. },
  431. {
  432. label: '耗时',
  433. prop: 'costSecond',
  434. rules: [{ required: true, message: '耗时不能为空', trigger: 'blur' }],
  435. compOptions: {
  436. placeholder: '请输入耗时'
  437. }
  438. },
  439. {
  440. label: '备注',
  441. prop: 'remarks',
  442. rules: [{ required: true, message: '备注不能为空', trigger: 'blur' }],
  443. compOptions: {
  444. placeholder: '请输入备注'
  445. }
  446. }
  447. ]
  448. }
  449. </script>
  450. <style scoped>
  451. .span_class {
  452. display: flex;
  453. align-self: center;
  454. justify-content: center;
  455. width: 120px;
  456. font-size: 13px;
  457. }
  458. </style>