|
@@ -1,6 +1,6 @@
|
|
|
<template>
|
|
|
<div class="table-box">
|
|
|
- <ProTable ref="proTable" :columns="columns" row-key="id" :request-api="listBizProcessApi">
|
|
|
+ <ProTable ref="proTable" :columns="columns" row-key="id" :data="bizProcessList">
|
|
|
<!-- 表格 header 按钮 -->
|
|
|
<template #tableHeader="scope">
|
|
|
<el-button type="primary" v-auth="['task:bizProcess:add']" icon="CirclePlus" @click="openDialog(1, '算法业务处理新增')"> 新增 </el-button>
|
|
@@ -16,6 +16,7 @@
|
|
|
>
|
|
|
批量删除
|
|
|
</el-button>
|
|
|
+ <el-button type="primary" v-auth="['task:bizProcess:add']" icon="View" @click="contrastResults()"> 对比结果 </el-button>
|
|
|
</template>
|
|
|
<!-- 表格操作 -->
|
|
|
<template #operation="scope">
|
|
@@ -26,18 +27,72 @@
|
|
|
编辑
|
|
|
</el-button>
|
|
|
<el-button type="primary" link icon="Delete" v-auth="['task:bizProcess:remove']" @click="deleteBizProcess(scope.row)"> 删除 </el-button>
|
|
|
+ <el-button type="primary" link icon="View" v-auth="['task:bizProcess:query']" @click="viewLog(scope.row)"> 查看日志 </el-button>
|
|
|
</template>
|
|
|
</ProTable>
|
|
|
<FormDialog ref="formDialogRef" />
|
|
|
<ImportExcel ref="dialogRef" />
|
|
|
+ <el-dialog v-model="dialogVisible" title="日志" width="70%">
|
|
|
+ <div class="log">
|
|
|
+ <div class="p" v-for="(item, index) in logInfo" :key="index">{{ item }}</div>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+ <el-dialog v-model="resultVisible" title="对比结果" width="70%">
|
|
|
+ <div style="width: 100%" class="resultShow">
|
|
|
+ <el-row class="headerRow">
|
|
|
+ <el-col class="col" :span="4" v-for="(agloName, index) in resultsData['agNameList']" :key="index">
|
|
|
+ <span>{{ agloName }}</span>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-row class="row">
|
|
|
+ <el-col class="col" :span="4" v-for="(RCurveUrl, index) in resultsData['rcureList']" :key="index">
|
|
|
+ <div v-if="index !== 1" class="oneCol">{{ RCurveUrl }}</div>
|
|
|
+ <ImagePreview
|
|
|
+ class="img"
|
|
|
+ v-else
|
|
|
+ :width="100"
|
|
|
+ :height="100"
|
|
|
+ :src="'/api/profile' + RCurveUrl"
|
|
|
+ :preview-src-list="['/api/profile' + RCurveUrl]"
|
|
|
+ />
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-row class="row">
|
|
|
+ <el-col class="col" :span="4" v-for="(PCurveUrl, index) in resultsData['pcureList']" :key="index">
|
|
|
+ <div v-if="index !== 1" class="oneCol">{{ PCurveUrl }}</div>
|
|
|
+ <ImagePreview
|
|
|
+ class="img"
|
|
|
+ v-else
|
|
|
+ :width="100"
|
|
|
+ :height="100"
|
|
|
+ :src="'/api/profile' + PCurveUrl"
|
|
|
+ :preview-src-list="['/api/profile' + PCurveUrl]"
|
|
|
+ />
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-row class="row">
|
|
|
+ <el-col class="col" :span="4" v-for="(F1CurveUrl, index) in resultsData['f1cureList']" :key="index">
|
|
|
+ <div v-if="index !== 1" class="oneCol">{{ F1CurveUrl }}</div>
|
|
|
+ <ImagePreview
|
|
|
+ class="img"
|
|
|
+ v-else
|
|
|
+ :width="100"
|
|
|
+ :height="100"
|
|
|
+ :src="'/api/profile' + F1CurveUrl"
|
|
|
+ :preview-src-list="['/api/profile' + F1CurveUrl]"
|
|
|
+ />
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="tsx" name="BizProcess">
|
|
|
-import { ref, reactive } from 'vue'
|
|
|
+import { ref, reactive, onMounted, onUnmounted, nextTick, watch } from 'vue'
|
|
|
import { useHandleData } from '@/hooks/useHandleData'
|
|
|
import { useDownload } from '@/hooks/useDownload'
|
|
|
-import { ElMessageBox } from 'element-plus'
|
|
|
+import { ElMessageBox, ElMessage } from 'element-plus'
|
|
|
import ProTable from '@/components/ProTable/index.vue'
|
|
|
import ImportExcel from '@/components/ImportExcel/index.vue'
|
|
|
import FormDialog from '@/components/FormDialog/index.vue'
|
|
@@ -50,12 +105,51 @@ import {
|
|
|
importTemplateApi,
|
|
|
importBizProcessDataApi,
|
|
|
exportBizProcessApi,
|
|
|
- getBizProcessApi
|
|
|
+ getBizProcessApi,
|
|
|
+ getTrainResultApi,
|
|
|
+ getVerifyResultApi,
|
|
|
+ getTestResultApi
|
|
|
} from '@/api/modules/task/bizProcess'
|
|
|
-
|
|
|
+import { getSubtaskApi } from '@/api/modules/task/subtask'
|
|
|
+import { getDictsApi } from '@/api/modules/system/dictData'
|
|
|
+import { useRoute } from 'vue-router'
|
|
|
+import ImagePreview from '@/components/ImagePreview/index.vue'
|
|
|
+const route = useRoute()
|
|
|
+const subTaskId = route.query.id as string
|
|
|
// ProTable 实例
|
|
|
const proTable = ref<ProTableInstance>()
|
|
|
+const dialogVisible = ref(false)
|
|
|
+const resultVisible = ref(false)
|
|
|
+let resultsData = ref({})
|
|
|
+let logList = ref()
|
|
|
+let logInfo = ref([] as string[])
|
|
|
+let taskType = ref()
|
|
|
+let taskStatus = ref()
|
|
|
|
|
|
+let bizProcessList = ref()
|
|
|
+// 每隔10秒请求一下列表
|
|
|
+const timer = ref() // 定时器
|
|
|
+const refreshList = () => {
|
|
|
+ setTimeout(() => {
|
|
|
+ listBizProcessApi({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 100,
|
|
|
+ subTaskId
|
|
|
+ }).then(res => {
|
|
|
+ bizProcessList.value = res.data['list']
|
|
|
+ })
|
|
|
+ }, 0)
|
|
|
+}
|
|
|
+onMounted(() => {
|
|
|
+ getSubtaskApi(subTaskId).then(res => {
|
|
|
+ taskType.value = res.data.type
|
|
|
+ taskStatus.value = res.data.status
|
|
|
+ })
|
|
|
+ refreshList()
|
|
|
+ timer.value = setInterval(() => {
|
|
|
+ refreshList()
|
|
|
+ }, 100000)
|
|
|
+})
|
|
|
// 删除算法业务处理信息
|
|
|
const deleteBizProcess = async (params: any) => {
|
|
|
await useHandleData(delBizProcessApi, params.id, '删除【' + params.id + '】算法业务处理')
|
|
@@ -88,6 +182,97 @@ const batchAdd = () => {
|
|
|
dialogRef.value?.acceptParams(params)
|
|
|
}
|
|
|
|
|
|
+// 对比结果
|
|
|
+const contrastResults = () => {
|
|
|
+ // if (taskStatus.value !== '3') {
|
|
|
+ // ElMessage.warning(`算法状态为${taskStatus.value},暂无对比结果`)
|
|
|
+ // return
|
|
|
+ // }
|
|
|
+ switch (taskType.value) {
|
|
|
+ case '1':
|
|
|
+ getTrainResultApi(subTaskId).then(res => {
|
|
|
+ handleResultData(res.data)
|
|
|
+ })
|
|
|
+ break
|
|
|
+ case '2':
|
|
|
+ getVerifyResultApi(subTaskId).then(res => {
|
|
|
+ handleResultData(res.data)
|
|
|
+ })
|
|
|
+ break
|
|
|
+ case '3':
|
|
|
+ getTestResultApi(subTaskId).then(res => {
|
|
|
+ console.log('333', res)
|
|
|
+ })
|
|
|
+ break
|
|
|
+ default:
|
|
|
+ break
|
|
|
+ }
|
|
|
+ resultVisible.value = true
|
|
|
+}
|
|
|
+const handleResultData = data => {
|
|
|
+ resultsData.value = data
|
|
|
+ resultsData.value['agNameList'].unshift('')
|
|
|
+ resultsData.value['rcureList'].unshift('R_curve')
|
|
|
+ resultsData.value['pcureList'].unshift('P_curve')
|
|
|
+ resultsData.value['f1cureList'].unshift('F1_curve')
|
|
|
+}
|
|
|
+// 查看日志
|
|
|
+const viewLog = row => {
|
|
|
+ // if (taskStatus.value !== '0') {
|
|
|
+ // ElMessage.warning('算法状态为待处理,暂无日志')
|
|
|
+ // return
|
|
|
+ // }
|
|
|
+ console.log(row.log)
|
|
|
+ const url = '/api/profile/task/log.log'
|
|
|
+ fetchLogFile(url)
|
|
|
+ .then(text => {
|
|
|
+ logList.value = text.split('\n')
|
|
|
+ // console.log('logList.value', logList.value)
|
|
|
+ // if (taskStatus.value === '1') {
|
|
|
+ // info(logList.value)
|
|
|
+ // dialogVisible.value = true
|
|
|
+ // } else if (taskStatus.value === '2') {
|
|
|
+ // logInfo.value = logList.value
|
|
|
+ // dialogVisible.value = true
|
|
|
+ // }
|
|
|
+ info(logList.value)
|
|
|
+ dialogVisible.value = true
|
|
|
+ })
|
|
|
+ .catch(error => {
|
|
|
+ console.error('Failed to fetch the log file:', error)
|
|
|
+ ElMessage.error('日志读取错误')
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const fetchLogFile = async url => {
|
|
|
+ try {
|
|
|
+ const response = await fetch(url, { method: 'GET' })
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error(`HTTP error! status: ${response.status}`)
|
|
|
+ }
|
|
|
+ return await response.text()
|
|
|
+ } catch (error) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+}
|
|
|
+let timer2 = ref()
|
|
|
+const info = logText => {
|
|
|
+ let index = 0
|
|
|
+ const logContainer = document.querySelector('.log')
|
|
|
+ timer2.value = setInterval(() => {
|
|
|
+ if (index < logText.length) {
|
|
|
+ logInfo.value.push(logText[index])
|
|
|
+ index++
|
|
|
+ nextTick(() => {
|
|
|
+ if (logContainer) {
|
|
|
+ logContainer.scrollTop = logContainer.scrollHeight
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ clearInterval(timer2.value)
|
|
|
+ }
|
|
|
+ }, 300)
|
|
|
+}
|
|
|
const formDialogRef = ref<InstanceType<typeof FormDialog> | null>(null)
|
|
|
// 打开弹框的功能
|
|
|
const openDialog = async (type: number, title: string, row?: any) => {
|
|
@@ -108,7 +293,19 @@ const openDialog = async (type: number, title: string, row?: any) => {
|
|
|
}
|
|
|
formDialogRef.value?.openDialog(params)
|
|
|
}
|
|
|
-
|
|
|
+onUnmounted(() => {
|
|
|
+ clearInterval(timer.value)
|
|
|
+ timer.value = null
|
|
|
+})
|
|
|
+watch(
|
|
|
+ () => dialogVisible.value,
|
|
|
+ val => {
|
|
|
+ if (!val) {
|
|
|
+ clearInterval(timer2.value)
|
|
|
+ timer2.value = null
|
|
|
+ }
|
|
|
+ }
|
|
|
+)
|
|
|
// 表格配置项
|
|
|
const columns = reactive<ColumnProps<any>[]>([
|
|
|
{ type: 'selection', fixed: 'left', width: 70 },
|
|
@@ -140,10 +337,13 @@ const columns = reactive<ColumnProps<any>[]>([
|
|
|
{
|
|
|
prop: 'status',
|
|
|
label: '任务状态',
|
|
|
+ tag: true,
|
|
|
+ enum: () => getDictsApi('biz_task_status'),
|
|
|
search: {
|
|
|
- el: 'input'
|
|
|
+ el: 'tree-select'
|
|
|
},
|
|
|
- width: 120
|
|
|
+ width: 100,
|
|
|
+ fieldNames: { label: 'dictLabel', value: 'dictValue' }
|
|
|
},
|
|
|
{
|
|
|
prop: 'algorithmId',
|
|
@@ -197,6 +397,8 @@ const columns = reactive<ColumnProps<any>[]>([
|
|
|
},
|
|
|
{ prop: 'operation', label: '操作', width: 230, fixed: 'right' }
|
|
|
])
|
|
|
+// 结果表格配置项
|
|
|
+// const resultColumns = reactive<ColumnProps<any>[]>([])
|
|
|
// 表单配置项
|
|
|
let itemsOptions: ProForm.ItemsOptions[] = []
|
|
|
const setItemsOptions = () => {
|
|
@@ -226,7 +428,11 @@ const setItemsOptions = () => {
|
|
|
label: '任务状态',
|
|
|
prop: 'status',
|
|
|
compOptions: {
|
|
|
- placeholder: '请输入任务状态'
|
|
|
+ elTagName: 'select',
|
|
|
+ labelKey: 'dictLabel',
|
|
|
+ valueKey: 'dictValue',
|
|
|
+ enum: () => getDictsApi('biz_task_status'),
|
|
|
+ placeholder: '请选择任务状态'
|
|
|
}
|
|
|
},
|
|
|
{
|
|
@@ -310,3 +516,46 @@ const setItemsOptions = () => {
|
|
|
]
|
|
|
}
|
|
|
</script>
|
|
|
+<style scoped lang="scss">
|
|
|
+.log {
|
|
|
+ width: 90%;
|
|
|
+ height: 60vh; /* 根据需要调整 */
|
|
|
+ padding: 10px;
|
|
|
+
|
|
|
+ // padding-bottom: 80px;
|
|
|
+ margin-left: 50px;
|
|
|
+ overflow-y: auto;
|
|
|
+ font-family: 'Courier New', monospace;
|
|
|
+ color: #4aff84;
|
|
|
+ background-color: #1e1e1e;
|
|
|
+}
|
|
|
+.p {
|
|
|
+ padding-left: 10px;
|
|
|
+ margin-bottom: 5px;
|
|
|
+ border-left: 3px solid #4aff84;
|
|
|
+}
|
|
|
+.resultShow {
|
|
|
+ width: 100%;
|
|
|
+ height: 60vh;
|
|
|
+ overflow: hidden;
|
|
|
+ overflow: scroll scroll;
|
|
|
+ .headerRow {
|
|
|
+ height: 50px;
|
|
|
+ font-size: 1.5rem;
|
|
|
+ line-height: 50px;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+ .row {
|
|
|
+ .col {
|
|
|
+ text-align: center;
|
|
|
+ .oneCol {
|
|
|
+ margin-top: 45px;
|
|
|
+ font-size: 1.2rem;
|
|
|
+ }
|
|
|
+ .img {
|
|
|
+ margin: 10px 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|