Kaynağa Gözat

fix: 修复数据扩增的bug

Eureka 8 ay önce
ebeveyn
işleme
c31512f35e

+ 97 - 0
src/api/modules/task/bizAmplify.ts

@@ -0,0 +1,97 @@
+import http from '@/api'
+/**
+ * @name 查询算法业务处理列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listAmplifyApi = (query: any) => {
+  return http.get<any[]>('/task/dataAmplificationTask/list', query, { loading: false })
+}
+
+export const getImgList = (query: any) => {
+  return http.get<any[]>('/identification/identificationSubtaskDetails/getImgList', query, { loading: false })
+}
+
+/**
+ * @name 查询算法业务处理详细
+ * @param id id
+ * @returns returns
+ */
+export const getAmplifyApi = (id: string | number) => {
+  return http.get<any>(`/task/dataAmplificationTask/${id}`)
+}
+
+/**
+ * @name 新增算法业务处理
+ * @param data data
+ * @returns returns
+ */
+export const addAmplifyApi = (data: any) => {
+  return http.post<any>('/task/dataAmplificationTask/', data, { loading: false })
+}
+
+/**
+ * @name 修改算法业务处理
+ * @param data data
+ * @returns returns
+ */
+export const updateAmplifyApi = (data: any) => {
+  return http.put<any>('/task/dataAmplificationTask/', data, { loading: false })
+}
+
+/**
+ * @name 删除算法业务处理
+ * @param id id
+ * @returns returns
+ */
+export const delBizProcessApi = (id: string | number | Array<string | number>) => {
+  return http.delete<any>(`/identification/identificationSubtaskDetails/${id}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/identification/identificationSubtaskDetails/importTemplate', {})
+}
+
+/**
+ * @name 导入数据
+ * @returns returns
+ */
+export const importBizProcessDataApi = (data: any) => {
+  return http.post('/identification/identificationSubtaskDetails/importData', data)
+}
+
+/**
+ * @name 导出数据
+ * @returns returns
+ */
+export const exportBizProcessApi = (data: any) => {
+  return http.downloadPost('/identification/identificationSubtaskDetails/export', data)
+}
+
+/**
+ * @name 查看训练结果
+ * @returns returns
+ */
+export const getTrainResultApi = (subtaskId: string | number) => {
+  return http.get(`/identification/identificationSubtaskDetails/getTrainResult/${subtaskId}`)
+}
+
+/**
+ * @name 查看验证结果
+ * @returns returns
+ */
+export const getVerifyResultApi = (subtaskId: string | number) => {
+  return http.get(`/identification/identificationSubtaskDetails/getVerifyResult/${subtaskId}`)
+}
+
+/**
+ * @name 查看测试结果
+ * @returns returns
+ */
+export const getTestResultApi = (subtaskId: string | number) => {
+  return http.get(`/identification/identificationSubtaskDetails/getTestResult/${subtaskId}`)
+}

+ 14 - 0
src/routers/modules/routerData.json

@@ -60,6 +60,20 @@
         "activeMenu": "/demo/data"
       }
     },
+    {
+      "name": "amplifyDetail",
+      "path": "/task/amplify/",
+      "hidden": false,
+      "component": "task/amplify/index",
+      "meta": {
+        "title": "数据扩增处理",
+        "icon": "",
+        "full": false,
+        "affix": false,
+        "noCache": false,
+        "link": null
+      }
+    },
     {
       "path": "/logPage/:flag",
       "name": "logPage",

+ 7 - 9
src/views/demo/data/AmplifyForm.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="amplify-main">
     <ProForm :items-options="items" :model="model"></ProForm>
-    <el-button type="primary" style="margin-left: 50px" @click="showDataSelectionDialog()">选择批次</el-button>
+    <el-button type="primary" v-if="showSelectBatchButton" style="margin-left: 50px" @click="showDataSelectionDialog()">选择批次</el-button>
 
     <el-dialog v-model="dataDialogVisible" title="选择数据批次" style="width: 70vw">
       <el-container>
@@ -54,6 +54,8 @@ let tempDeselectedBatchDataList = ref(reactive([] as any[]))
 let parameList = ref(reactive([] as any[]))
 let queryBatchData = ref(reactive([] as any[]))
 
+const props = defineProps({ showSelectBatchButton: Boolean })
+
 onMounted(() => {
   batchListDataApi().then(res => {
     queryBatchData.value = reactive(res.data)
@@ -66,11 +68,11 @@ onMounted(() => {
         label: item.name,
         prop: item.agName,
         span: 12,
-        rules: [{ required: item.required, message: '不能为空' }],
+        rules: [{ required: item.required === 'true', message: item.name + '不能为空' }],
         compOptions: {
           elTagName: 'input',
           clearable: true,
-          placeholder: '请输入..'
+          placeholder: '请输入' + item.name
         }
       })
       model[`${item.agName}`] = item.defaultValue
@@ -98,9 +100,7 @@ const clickSelectData = () => {
     selectedBatchDataList.value.push(batch)
   })
 
-  batchDataList.value = reactive(
-    batchDataList.value.filter(batch => !set.has(batch.batchNum))
-  )
+  batchDataList.value = reactive(batchDataList.value.filter(batch => !set.has(batch.batchNum)))
   emit('updateData', selectedBatchDataList.value)
 }
 
@@ -113,9 +113,7 @@ const clickDeselectData = () => {
     batchDataList.value.push(batch)
   })
 
-  selectedBatchDataList.value = reactive(
-    selectedBatchDataList.value.filter(batch => !set.has(batch.batchNum))
-  )
+  selectedBatchDataList.value = reactive(selectedBatchDataList.value.filter(batch => !set.has(batch.batchNum)))
   emit('updateData', selectedBatchDataList.value)
 }
 

+ 7 - 7
src/views/demo/data/amplify.vue

@@ -1,36 +1,35 @@
 <template>
   <div class="amplify-container">
-    <AmplifyForm @updateData="updateBatchData" @updateModel="updateModelData" @updateParams="updateParamsList" />
+    <AmplifyForm @update-data="updateBatchData" @update-model="updateModelData" @update-params="updateParamsList" :show-select-batch-button="true" />
 
     <div style="margin: 0 auto">
       <el-footer>
         <el-button class="submit" type="primary" @click="handleSubmit">提交</el-button>
       </el-footer>
     </div>
-
   </div>
 </template>
 
 <script setup lang="tsx">
-import {ref} from 'vue'
+import { ref } from 'vue'
 import AmplifyForm from './AmplifyForm.vue'
-import {amplifyApi} from '@/api/modules/demo/data'
+import { amplifyApi } from '@/api/modules/demo/data'
 
 let selectedBatchDataList = ref([] as any[])
 let model = ref({})
 let parameList = ref([] as any[])
 
 // 监听 AmplifyForm 组件传递的数据
-const updateBatchData = (data) => {
+const updateBatchData = data => {
   selectedBatchDataList.value = data
 }
 
-const updateModelData = (data) => {
+const updateModelData = data => {
   model.value = data
 }
 
 // 监听 parameList 更新
-const updateParamsList = (data) => {
+const updateParamsList = data => {
   parameList.value = data
 }
 
@@ -45,6 +44,7 @@ const handleSubmit = () => {
 
   const data = {
     batchNum,
+    augmentationType: model.value.augmentationType,
     taskName: model.value.taskName,
     otherParams: parameList.value
   }

+ 27 - 29
src/views/taais/homePage/task/index.vue

@@ -49,8 +49,8 @@
         <el-container style="display: flex; flex-direction: column">
           <el-container v-for="(item, index) in formData.data" :key="index" style="margin-top: 5px">
             <el-button v-show="formData.data" @click="showDataSelectionDialog(index, true)"> 选择批次 </el-button>
-            <span v-if="!item || item.length === 0" class="span_class" style=" font-size: 15px;color: red">未完成</span>
-            <span v-else class="span_class" style=" font-size: 15px;color: greenyellow">已选择</span>
+            <span v-if="!item || item.length === 0" class="span_class" style="font-size: 15px; color: red">未完成</span>
+            <span v-else class="span_class" style="font-size: 15px; color: greenyellow">已选择</span>
             <el-button v-show="formData.data.length > 1" style="margin-left: 20px" @click="removeDataItem(index, true)"> 删除数据 </el-button>
             <el-button
               v-show="formData.taskType === '2' && index + 1 === formData.data.length"
@@ -69,8 +69,8 @@
         <el-container style="display: flex; flex-direction: column">
           <el-container v-for="(item, index) in formData.testData" :key="index" style="margin-top: 5px">
             <el-button v-show="formData.testData" @click="showDataSelectionDialog(index, false)"> 选择批次 </el-button>
-            <span v-if="!item || item.length === 0" class="span_class" style=" font-size: 15px;color: red">未完成</span>
-            <span v-else class="span_class" style=" font-size: 15px;color: greenyellow">已选择</span>
+            <span v-if="!item || item.length === 0" class="span_class" style="font-size: 15px; color: red">未完成</span>
+            <span v-else class="span_class" style="font-size: 15px; color: greenyellow">已选择</span>
             <el-button v-show="formData.testData.length > 1" style="margin-left: 20px" @click="removeDataItem(index, false)"> 删除数据 </el-button>
             <el-button
               v-show="formData.taskType === '2' && index + 1 === formData.testData.length"
@@ -90,7 +90,7 @@
         <el-button v-show="formData.expandData" style="margin-left: 20px" @click="showExpandDataSuperParameterConfig"> 超参配置 </el-button>
       </el-container>
 
-      <el-form-item style=" margin-top: 20px;margin-left: 30px">
+      <el-form-item style="margin-top: 20px; margin-left: 30px">
         <el-button type="primary" @click="submit"> 提交 </el-button>
 
         <el-button @click="cancel"> 取消 </el-button>
@@ -101,12 +101,17 @@
 
     <el-dialog v-model="expandDataDialogVisible" title="数据扩增超参配置">
       <!--      <span style="font-size: 16px; color: darkorange; font-weight: bold"> 数据扩增超参 </span>-->
-<!--      <el-container v-for="(item, index) in expandDataConfig" :key="index" style="margin-top: 5px">-->
-<!--        <span class="span_class"> {{ item.name }}</span>-->
-<!--        <el-input style="width: 300px" type="text" :placeholder="'请输入' + item.name" v-model="item.defaultValue"> </el-input>-->
-<!--      </el-container>-->
-      <el-container style="margin-top: 5px;">
-        <AmplifyForm @updateData="updateBatchData" @updateModel="updateModelData" @updateParams="updateParamsList" />
+      <!--      <el-container v-for="(item, index) in expandDataConfig" :key="index" style="margin-top: 5px">-->
+      <!--        <span class="span_class"> {{ item.name }}</span>-->
+      <!--        <el-input style="width: 300px" type="text" :placeholder="'请输入' + item.name" v-model="item.defaultValue"> </el-input>-->
+      <!--      </el-container>-->
+      <el-container style="margin-top: 5px">
+        <AmplifyForm
+          @update-data="updateBatchData"
+          @update-model="updateModelData"
+          @update-params="updateParamsList"
+          :show-select-batch-button="false"
+        />
       </el-container>
       <el-container style="height: 10px"></el-container>
 
@@ -152,7 +157,7 @@
           <el-table-column prop="batchSize" label="数量" width="80"> </el-table-column>
         </el-table>
 
-        <el-container style=" display: flex; flex-direction: column; justify-content: center; margin-right: 10px;margin-left: 10px">
+        <el-container style="display: flex; flex-direction: column; justify-content: center; margin-right: 10px; margin-left: 10px">
           <el-button type="primary" :disabled="!canSelect" @click="clickSelectData"> {{ '=>' }} </el-button>
           <el-container style="height: 10px"></el-container>
           <el-button type="primary" :disabled="!canDeselect" @click="clickDeselectData"> {{ '<=' }} </el-button>
@@ -181,26 +186,26 @@ import { createTaskApi } from '@/api/modules/task/task'
 import FormDialog from '@/components/FormDialog/index.vue'
 import { useRouter } from 'vue-router'
 import { listTaskConfigurationApi } from '@/api/modules/task/taskConfiguration'
-import {amplifyApi, batchListDataApi} from '@/api/modules/demo/data'
+import { amplifyApi, batchListDataApi } from '@/api/modules/demo/data'
 import { listDataApi } from '@/api/modules/system/dictData'
 import { ElMessage } from 'element-plus'
-import AmplifyForm from "@/views/demo/data/AmplifyForm.vue";
+import AmplifyForm from '@/views/demo/data/AmplifyForm.vue'
 
 let selectedBatchDataList1 = ref([] as any[])
 let model = ref({})
 let parameList = ref([] as any[])
 
 // 监听 AmplifyForm 组件传递的数据
-const updateBatchData = (data) => {
+const updateBatchData = data => {
   selectedBatchDataList1.value = data
 }
 
-const updateModelData = (data) => {
+const updateModelData = data => {
   model.value = data
 }
 
 // 监听 parameList 更新
-const updateParamsList = (data) => {
+const updateParamsList = data => {
   parameList.value = data
 }
 
@@ -309,12 +314,7 @@ const submit = () => {
       o3.push(__trained)
     }
 
-    obj.params =
-      JSON.stringify(o1) +
-      ';;;' +
-      JSON.stringify(o2) +
-      ';;;' +
-      JSON.stringify(o3)
+    obj.params = JSON.stringify(o1) + ';;;' + JSON.stringify(o2) + ';;;' + JSON.stringify(o3)
     __idx++
   })
   // console.log('submit', params)
@@ -360,7 +360,6 @@ const showExpandDataSuperParameterConfig = () => {
 }
 // 数据扩增超参修改保存
 const submitExpandDataConfigDialog = () => {
-  handleSubmit()
   expandDataDialogVisible.value = false
 }
 
@@ -537,18 +536,17 @@ const onAlgorithmModelSelect = index => {
 
 const formDialogRef = ref<InstanceType<typeof FormDialog> | null>(null)
 
-
 let UPDATE_INDEX = ref({ id: null, idx: null })
 const showAddModelDialog = (item, index) => {
   let _id = null
   try {
     _id = item.id
   } catch (e) {
-    ElMessage.error("请先选择算法模型")
+    ElMessage.error('请先选择算法模型')
     return
   }
   if (!_id || _id.length === 0) {
-    ElMessage.error("请先选择算法模型")
+    ElMessage.error('请先选择算法模型')
     return
   }
   UPDATE_INDEX.value = {
@@ -601,10 +599,10 @@ const showAddModelDialog = (item, index) => {
 // 获取算法模型绑定列表
 const updateModelList = (id, index) => {
   // 获取算法列表?
-  queryModelList({id: id}).then(res => {
+  queryModelList({ id: id }).then(res => {
     console.log('algorithm task model get: ', res)
     if (res.code === 200) {
-      formData.algoModelList[index] = [ {id: null, modelName: '未选择'} , ...res.data]
+      formData.algoModelList[index] = [{ id: null, modelName: '未选择' }, ...res.data]
     }
   })
 }

+ 908 - 0
src/views/task/amplify/index.vue

@@ -0,0 +1,908 @@
+<template>
+  <div class="table-box">
+    <ProTable ref="proTable" :columns="columns" row-key="id" :data="amplifyList">
+      <!-- 表格 header 按钮 -->
+      <template #tableHeader="scope">
+        <el-button type="primary" v-auth="['identification:identificationSubtaskDetails:export']" icon="Download" plain @click="downloadFile">
+          导出
+        </el-button>
+        <el-button
+          type="danger"
+          v-auth="['identification:identificationSubtaskDetails:remove']"
+          icon="Delete"
+          plain
+          :disabled="!scope.isSelected"
+          @click="batchDelete(scope.selectedListIds)"
+        >
+          批量删除
+        </el-button>
+        <!--        <el-button type="primary" icon="View" @click="showCompareResult"> 验证指标对比</el-button>-->
+        <!--        <el-button type="primary" icon="View" @click="showValResult(true)"> 验证结果</el-button>-->
+        <!--        <el-button type="primary" icon="View" @click="showValResult(false)"> 测试结果</el-button>-->
+        <!--        <el-button type="primary" icon="View" @click="showValResult(true)"> 验证结果</el-button>-->
+      </template>
+      <!-- 表格操作 -->
+      <template #operation="scope">
+        <!--        <el-button-->
+        <!--            type="primary"-->
+        <!--            link-->
+        <!--            icon="View"-->
+        <!--            @click="openDialog(3, '扩增算法业务处理查看', scope.row)"-->
+        <!--        >-->
+        <!--          查看详情-->
+        <!--        </el-button>-->
+
+        <!--        <el-button type="primary" link icon="finished" @click="showResult(scope.row)"> 执行结果</el-button>-->
+
+        <el-button type="primary" link icon="Refresh" @click="startTask(scope.row)"> 开始训练</el-button>
+
+        <!--        <el-button type="primary" link icon="Refresh" @click="exportData(scope.row)"> 导出结果</el-button>-->
+
+        <el-button type="primary" link icon="document" @click="viewLog(scope.row)"> 查看日志 </el-button>
+      </template>
+    </ProTable>
+    <FormDialog ref="formDialogRef" />
+    <ImportExcel ref="dialogRef" />
+
+    <el-dialog v-model="executedTimeVisible" title="执行时间统计" width="70%">
+      <el-container v-for="(item, index) in executedTimeData" :key="index">
+        <el-container style="display: flex; flex-direction: column">
+          <h4 v-if="index === 0">单幅图像最短运行时间</h4>
+          <h4 v-else-if="index === 1">单幅图像最短运行时间</h4>
+          <h4 v-else-if="index === 2">单幅图像最短运行时间</h4>
+          <div style="display: flex; flex-direction: row">
+            <h5>前处理用时: {{ item['preprocess'] }}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</h5>
+            <h5>推理用时: {{ item['inference'] }}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</h5>
+            <h5>后处理用时: {{ item['postprocess'] }}</h5>
+          </div>
+        </el-container>
+      </el-container>
+    </el-dialog>
+
+    <el-dialog v-model="dialogVisible" title="日志" width="70%">
+      <div class="log" ref="logRef">
+        <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 v-if="!resultsFlag" class="resultShow">
+        <el-row class="headerRow">
+          <el-col class="col" :span="spanNum" 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="spanNum" v-for="(RCurveUrl, index) in resultsData['rcureList']" :key="index">
+            <div v-if="index === 0" :span="4" 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="spanNum" v-for="(PCurveUrl, index) in resultsData['pcureList']" :key="index">
+            <div v-if="index === 0" 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="spanNum" v-for="(F1CurveUrl, index) in resultsData['f1cureList']" :key="index">
+            <div v-if="index === 0" 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>
+      <div v-if="resultsFlag" class="resultShow">
+        <el-row class="headerRow">
+          <el-col class="col" :span="spanNum" v-for="(agloName, index) in testResultsData['agNameList']" :key="index">
+            <span>{{ agloName }}</span>
+          </el-col>
+        </el-row>
+        <el-row class="row" v-for="(item, index) in testResultsData['resultList']" :key="index">
+          <el-col class="col" :span="spanNum" v-for="(url, index1) in item" :key="index1">
+            <!-- <span>{{ url }}</span> -->
+            <ImagePreview class="img" :width="100" :height="100" :src="'/api/profile' + url" :preview-src-list="['/api/profile' + url]" />
+          </el-col>
+        </el-row>
+      </div>
+    </el-dialog>
+
+    <el-dialog v-model="resultDialogVisible" title="执行结果">
+      <!--      style="width: 70vw"-->
+      <el-card :body-style="{ padding: '0px' }">
+        <div style="padding: 14px">
+          <span>P_curve</span>
+        </div>
+        <el-image :src="PATH_PREFIX + refSelectData.outputImagePath + '/P_curve.png'"></el-image>
+      </el-card>
+
+      <el-card :body-style="{ padding: '0px' }" style="margin-top: 10px">
+        <div style="padding: 14px">
+          <span>R_curve</span>
+        </div>
+        <el-image :src="PATH_PREFIX + refSelectData.outputImagePath + '/R_curve.png'"></el-image>
+      </el-card>
+
+      <el-card :body-style="{ padding: '0px' }" style="margin-top: 10px">
+        <div style="padding: 14px">
+          <span>PR_curve</span>
+        </div>
+        <el-image :src="PATH_PREFIX + refSelectData.outputImagePath + '/PR_curve.png'"></el-image>
+      </el-card>
+
+      <el-card :body-style="{ padding: '0px' }" style="margin-top: 10px">
+        <div style="padding: 14px">
+          <span>F1_curve</span>
+        </div>
+        <el-image :src="PATH_PREFIX + refSelectData.outputImagePath + '/F1_curve.png'"></el-image>
+      </el-card>
+    </el-dialog>
+
+    <el-dialog v-model="compareDialogVisible" title="验证指标对比">
+      <!--      style="width: 70vw"-->
+      <el-container style="display: flex; flex-direction: row">
+        <el-container v-for="(item, index) in valListData" :key="index" style="display: flex; flex-direction: column">
+          <!--          <el-button @click="console.log(item)">test</el-button>-->
+          <span style="font-size: 18px"> {{ item.name }} </span>
+          <el-card :body-style="{ padding: '0px' }" style="margin-top: 3px">
+            <div style="padding: 14px">
+              <span>P_curve</span>
+            </div>
+            <el-image :src="PATH_PREFIX + item.outputImagePath + '/P_curve.png'"></el-image>
+          </el-card>
+
+          <el-card :body-style="{ padding: '0px' }" style="margin-top: 10px">
+            <div style="padding: 14px">
+              <span>R_curve</span>
+            </div>
+            <el-image :src="PATH_PREFIX + item.outputImagePath + '/R_curve.png'"></el-image>
+          </el-card>
+
+          <el-card :body-style="{ padding: '0px' }" style="margin-top: 10px">
+            <div style="padding: 14px">
+              <span>PR_curve</span>
+            </div>
+            <el-image :src="PATH_PREFIX + item.outputImagePath + '/PR_curve.png'"></el-image>
+          </el-card>
+
+          <el-card :body-style="{ padding: '0px' }" style="margin-top: 10px">
+            <div style="padding: 14px">
+              <span>F1_curve</span>
+            </div>
+            <el-image :src="PATH_PREFIX + item.outputImagePath + '/F1_curve.png'"></el-image>
+          </el-card>
+        </el-container>
+      </el-container>
+    </el-dialog>
+
+    <el-dialog v-model="valDialogVisible" :title="titleMsg" style="width: 85vw; height: 85vh">
+      <!--      style="width: 70vw"-->
+      <el-container style="display: flex; flex-direction: row">
+        <el-container v-for="(item, index) in imgDataList" :key="index" style="display: flex; flex-direction: column">
+          <!--          <el-button @click="console.log(item)">test</el-button>-->
+
+          <el-container v-for="(_item, _index) in item" :key="_index">
+            <span
+              v-if="_item.name"
+              :style="{
+                color: _item.color ? _item.color : '#ffffff',
+                width: '80px',
+                'margin-right': '20px'
+              }"
+            >
+              {{ _item.name }}
+            </span>
+            <el-image v-if="_item.srcUrl" :src="_item.srcUrl" style="width: 200px; height: 200px"></el-image>
+            <span v-if="_item.imgUrl">标签</span>
+            <ImgMaker
+              :canvas-id="_item.name + '_' + _index"
+              style="width: 200px; height: 200px"
+              ref="imgMaker"
+              v-if="_item.imgUrl"
+              :is-pic-only="true"
+              :src="_item.imgUrl"
+              :width="200"
+              :height="200"
+              :c-width="200"
+              :c-height="200"
+              :class-def="typeDefs"
+              :json-data="_item.jsonData"
+            ></ImgMaker>
+            <el-image v-if="_item.resUrl" :src="_item.resUrl" style="width: 200px; height: 200px"></el-image>
+          </el-container>
+        </el-container>
+      </el-container>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="tsx" name="BizProcess">
+import { ref, reactive, onMounted, onUnmounted, watch, nextTick } from 'vue'
+import { useHandleData } from '@/hooks/useHandleData'
+import { useDownload } from '@/hooks/useDownload'
+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'
+import { ProTableInstance, ColumnProps } from '@/components/ProTable/interface'
+import ImgMaker from '../../demo/components/img-maker'
+import {
+  delBizProcessApi,
+  exportBizProcessApi,
+  getBizProcessApi,
+  getTrainResultApi,
+  getVerifyResultApi,
+  getTestResultApi,
+  getImgList
+} from '@/api/modules/task/bizProcessNew'
+// getTrainResultApi,getVerifyResultApi,getTestResultApi
+import { getSubtaskApi } from '@/api/modules/task/subtask'
+import { getDictsApi, listDataApi as listDictDataApi } from '@/api/modules/system/dictData'
+import { useRoute } from 'vue-router'
+import ImagePreview from '@/components/ImagePreview/index.vue'
+import http from '@/api'
+import { addAmplifyApi, getAmplifyApi, listAmplifyApi, updateAmplifyApi } from '@/api/modules/task/bizAmplify'
+
+const route = useRoute()
+const PATH_PREFIX = 'api/profile/task'
+let resultDialogVisible = ref(false)
+let refSelectData = ref(reactive({}))
+
+const startTask = row => {
+  http.post<any>('/demo/data/amplifyForData?id=' + row.id, {}, { loading: false }).then(res => {
+    if (res.code !== 200) {
+      ElMessage.error(res.msg)
+    } else {
+      ElMessage.success('启动成功')
+    }
+  })
+}
+const typeDefs = ref(reactive([]))
+
+const exportData = row => {
+  http.get<any>('/identification/identificationSubtaskDetails/resultZip', { taskId: row.id }, { loading: false }).then(res => {
+    console.log(res)
+    if (res.code === 200) {
+      window.open(res.msg, '_blank')
+    }
+  })
+}
+
+let executedTimeVisible = ref(false)
+let executedTimeData = ref([])
+const showExecutedTime = row => {
+  try {
+    executedTimeData.value = JSON.parse(row.remarks)
+  } catch (e) {
+    ElMessage.error('解析JSON错误,请检查任务是否已完成')
+    return
+  }
+  executedTimeVisible.value = true
+}
+
+let imgDataList = ref(reactive([]))
+let titleMsg = ref('')
+let valDialogVisible = ref(false)
+const showValResult = async isVal => {
+  let hasInit = false
+  titleMsg.value = isVal ? '验证结果对比' : '测试结果对比'
+  imgDataList.value = reactive([])
+  for (let i = 0; i < listData.value.length; i++) {
+    if (listData.value[i].name.indexOf(isVal ? '验证' : '测试') !== -1) {
+      console.log(listData.value[i])
+      if (!hasInit) {
+        hasInit = true
+        let res = await getImgList({
+          taskId: listData.value[i].inputImagePath.substring(1).split('/')[0],
+          subPath: 'images'
+        })
+        console.log('res data', res)
+        imgDataList.value.push([])
+        for (let j = 0; j < res.data.length; j++) {
+          let jList = res.data[j].split('.')
+          jList[jList.length - 1] = 'txt'
+          let obj = {
+            name: res.data[j],
+            srcUrl: 'api/profile/task' + listData.value[i].inputImagePath + (isVal ? '/images/' : '/') + res.data[j]
+            // imgUrl: 'api/profile/task' + listData.value[i].inputImagePath + '/images/' + res.data[j],
+            // labelUrl: 'api/profile/task' + listData.value[i].inputImagePath + '/labels/' + jList.join('.')
+          }
+
+          imgDataList.value[imgDataList.value.length - 1].push(obj)
+          if (isVal) {
+            obj.imgUrl = 'api/profile/task' + listData.value[i].inputImagePath + '/images/' + res.data[j]
+            obj.labelUrl = '/profile/task' + listData.value[i].inputImagePath + '/labels/' + jList.join('.')
+            console.log('url is', obj.labelUrl)
+            setDetail(obj)
+          }
+        }
+      }
+      let res = await getImgList({
+        taskId: listData.value[i].inputImagePath.substring(1).split('/')[0],
+        subPath: 'images'
+      })
+      console.log(res.data)
+      if (isVal) {
+        await loadVerifyResult(listData.value[i].name, '/profile/task' + listData.value[i].inputImagePath + '/result/verify_result.txt')
+      }
+      console.log('load result', verifyResult.value)
+      imgDataList.value.push([])
+      for (let j = 0; j < res.data.length; j++) {
+        console.log('temp log', verifyResult.value)
+        let jList = res.data[j].split('.')
+        jList[jList - 1] = 'txt'
+        imgDataList.value[imgDataList.value.length - 1].push({
+          resUrl: 'api/profile/task' + listData.value[i].outputImagePath + '/' + res.data[j],
+          name: listData.value[i].name,
+          picName: res.data[j],
+          color: verifyResult.value[res.data[j]] ? '#00ff00' : '#ff0000'
+        })
+      }
+    }
+  }
+  console.log('datalist', imgDataList)
+  valDialogVisible.value = true
+}
+
+const verifyResult = ref({})
+const loadVerifyResult = async (name, filepath) => {
+  // console.log('filepath', filepath)
+  try {
+    verifyResult.value = {}
+    let res = await http.get(filepath)
+    console.log(res)
+    // verifyResult.value[name] = {}
+    let arr = res.replace('\r', '').split('\n')
+    arr.forEach(str => {
+      let vals = str.split(' ')
+      verifyResult.value[vals[0]] = vals[1] === '1'
+    })
+    console.log('verifyResult', verifyResult.value)
+  } catch (e) {
+    verifyResult.value = {}
+  }
+}
+
+const setDetail = obj => {
+  http.get<any>(obj.labelUrl).then(res => {
+    obj.jsonData = []
+    // console.log('result', res)
+    let arr = res.replace('\r', '').split('\n')
+    // console.log(arr)
+    for (let i = 0; i < arr.length; i++) {
+      let subArr = arr[i].split(' ')
+      // console.log(subArr)
+      let cssVal = '#000000'
+      let label = '-1'
+      for (let j = 0; j < typeDefs.value.length; j++) {
+        if (typeDefs.value[j].label === subArr[0]) {
+          cssVal = typeDefs.value[j].color
+          label = typeDefs.value[j].label
+          break
+        }
+      }
+      const ww = 200
+      const hh = 200
+      obj.jsonData.push({
+        subArr: subArr,
+        pathString:
+          'M ' +
+          subArr[1] * ww +
+          ' ' +
+          subArr[2] * hh +
+          ' L ' +
+          subArr[3] * ww +
+          ' ' +
+          subArr[4] * hh +
+          ' L ' +
+          subArr[5] * ww +
+          ' ' +
+          subArr[6] * hh +
+          ' L ' +
+          subArr[7] * ww +
+          ' ' +
+          subArr[8] * hh +
+          ' z',
+        // left: 0,
+        // top: 0,
+        fill: '',
+        stroke: cssVal,
+        strokeWidth: 5,
+        label: label
+      })
+    }
+  })
+}
+
+let compareDialogVisible = ref(false)
+const valListData = ref([])
+let listData = ref(reactive([]))
+const showCompareResult = () => {
+  console.log(listData.value)
+  valListData.value = listData.value.filter(item => {
+    return item.name.includes('验证')
+  })
+  compareDialogVisible.value = true
+  console.log('vallist', valListData.value)
+}
+const showResult = row => {
+  refSelectData.value = reactive(row)
+  resultDialogVisible.value = true
+  console.log(row)
+}
+const subTaskId = route.query.id as string
+// ProTable 实例
+const proTable = ref<ProTableInstance>()
+const dialogVisible = ref(false)
+const resultVisible = ref(false)
+let resultsData = ref({})
+let testResultsData = ref({})
+let resultsFlag = ref(false)
+let spanNum = ref<number>(4)
+// let logList = ref()
+const logRef = ref<HTMLElement | null>(null) // 显式声明 logRef 的类型;
+let logInfo = ref([] as any[])
+let taskType = ref()
+let taskStatus = ref()
+
+let amplifyList = ref()
+// 每隔10秒请求一下列表
+const timer = ref() // 定时器
+const refreshList = () => {
+  setTimeout(() => {
+    listAmplifyApi({
+      pageNum: 1,
+      pageSize: 100,
+      subTaskId: subTaskId
+    }).then(res => {
+      amplifyList.value = res.data['list'].sort((a, b) => b.index - a.index)
+      listData.value = reactive(res.data['list'].sort((a, b) => b.index - a.index))
+    })
+  }, 0)
+}
+onMounted(() => {
+  listDictDataApi({
+    pageNum: 1,
+    pageSize: 10,
+    dictType: 'class_definition'
+  }).then(res => {
+    // console.log(res)
+    for (let i = 0; i < res.data.list.length; i++) {
+      typeDefs.value.push({
+        name: res.data.list[i].dictLabel,
+        color: res.data.list[i].cssClass,
+        label: res.data.list[i].dictValue
+      })
+    }
+  })
+
+  getSubtaskApi(subTaskId).then(res => {
+    taskType.value = res.data.type
+    taskStatus.value = res.data.status
+  })
+  refreshList()
+  timer.value = setInterval(() => {
+    refreshList()
+  }, 10000)
+  // 组件挂载后,logRef 将指向实际的 DOM 元素
+  if (logRef.value) {
+    // 操作 logRef 对应的 DOM 元素
+    logRef.value.scrollTop = logRef.value.scrollHeight
+  }
+})
+// 删除算法业务处理信息
+const deleteBizProcess = async (params: any) => {
+  await useHandleData(delBizProcessApi, params.id, '删除【' + params.id + '】算法业务处理')
+  proTable.value?.getTableList()
+}
+
+// 批量删除算法业务处理信息
+const batchDelete = async (ids: string[]) => {
+  await useHandleData(delBizProcessApi, ids, '删除所选算法业务处理信息')
+  proTable.value?.clearSelection()
+  proTable.value?.getTableList()
+}
+
+// 导出算法业务处理列表
+const downloadFile = async () => {
+  ElMessageBox.confirm('确认导出算法业务处理数据?', '温馨提示', { type: 'warning' }).then(() =>
+    useDownload(exportBizProcessApi, '算法业务处理列表', proTable.value?.searchParam)
+  )
+}
+
+// 批量添加算法业务处理
+const dialogRef = ref<InstanceType<typeof ImportExcel> | null>(null)
+
+// 对比结果
+const contrastResults = () => {
+  const statusFlag = amplifyList.value.every(item => {
+    return item.status == '2'
+  })
+  if (statusFlag) {
+    switch (taskType.value) {
+      case '1':
+        getTrainResultApi(subTaskId).then(res => {
+          resultsFlag.value = false
+          handleResultData(res.data)
+          resultVisible.value = true
+        })
+        break
+      case '2':
+        getVerifyResultApi(subTaskId).then(res => {
+          resultsFlag.value = false
+          handleResultData(res.data)
+          resultVisible.value = true
+        })
+        break
+      case '3':
+        getTestResultApi(subTaskId).then(res => {
+          console.log('333', res)
+          resultsFlag.value = true
+          testResultsData.value = res.data as any
+          const num = testResultsData.value['agNameList'].length
+          spanNum.value = 24 / num <= 4 ? 4 : Math.floor(24 / num)
+          resultVisible.value = true
+        })
+        break
+      default:
+        break
+    }
+  } else {
+    ElMessage.warning(`所有算法状态为‘已完成’,才可以对比`)
+  }
+}
+const handleResultData = data => {
+  resultsData.value = data
+  resultsData.value['agNameList'].unshift('')
+  const num = resultsData.value['agNameList'].length + 1
+  spanNum.value = 24 / num <= 4 ? 4 : Math.floor(24 / num)
+  resultsData.value['rcureList'].unshift('R_curve')
+  resultsData.value['pcureList'].unshift('P_curve')
+  resultsData.value['f1cureList'].unshift('F1_curve')
+}
+// 查看日志
+let timer2 = ref()
+const viewLog = row => {
+  if (row.status === '0') {
+    ElMessage.warning('算法状态为待处理,暂无日志')
+    return
+  }
+  const paths = row.outputImagePath.split('\n')
+  for (let path of paths) {
+    const url = `/api/profile/task/log/bizType/` + row.id + '/log.log'
+    logShow(url)
+    dialogVisible.value = true
+    timer2.value = setInterval(() => {
+      if (dialogVisible.value) {
+        logShow(url)
+      }
+    }, 5000)
+  }
+}
+// 日志读取
+const logShow = (url: any) => {
+  fetchLogFile(url)
+    .then(text => {
+      logInfo.value = []
+      logInfo.value = text.split('\n')
+      nextTick(() => {
+        const logContainer = logRef.value
+        if (logContainer) {
+          ;(logContainer as HTMLElement).scrollTop = (logContainer as HTMLElement).scrollHeight
+        }
+      })
+    })
+    .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
+  }
+}
+const formDialogRef = ref<InstanceType<typeof FormDialog> | null>(null)
+// 打开弹框的功能
+const openDialog = async (type: number, title: string, row?: any) => {
+  let res = { data: {} }
+  if (row?.id) {
+    res = await getAmplifyApi(row?.id || null)
+  }
+  // 重置表单
+  setItemsOptions()
+  const params = {
+    title,
+    width: 580,
+    isEdit: type !== 3,
+    itemsOptions: itemsOptions,
+    model: type == 1 ? {} : res.data,
+    api: type == 1 ? addAmplifyApi : updateAmplifyApi,
+    getTableList: proTable.value?.getTableList
+  }
+  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 },
+  // { prop: 'id', label: '主键ID' },
+  // {
+  //   prop: 'subTaskId',
+  //   label: '子任务id',
+  //   search: {
+  //     el: 'input'
+  //   },
+  //   width: 120
+  // },
+  {
+    prop: 'name',
+    label: '任务名称',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  // {
+  //   prop: 'type',
+  //   label: '任务类型',
+  //   search: {
+  //     el: 'input'
+  //   },
+  //   width: 120
+  // },
+  {
+    prop: 'status',
+    label: '任务状态',
+    tag: true,
+    enum: () => getDictsApi('biz_task_status'),
+    search: {
+      el: 'tree-select'
+    },
+    width: 100,
+    fieldNames: { label: 'dictLabel', value: 'dictValue' }
+  },
+  // {
+  //   prop: 'algorithmId',
+  //   label: '算法',
+  //   width: 120
+  // },
+  // {
+  //   prop: 'modelId',
+  //   label: '模型',
+  //   width: 120
+  // },
+  {
+    prop: 'parameters',
+    label: '调用算法时所用的参数'
+  },
+  {
+    prop: 'inputImagePath',
+    label: '预处理数据路径'
+  },
+  {
+    prop: 'outputImagePath',
+    label: '结果数据路径'
+  },
+  {
+    prop: 'index',
+    label: '序号',
+    width: 120
+  },
+  {
+    prop: 'startTime',
+    label: '开始时间'
+  },
+  {
+    prop: 'endTime',
+    label: '结束时间'
+  },
+  {
+    prop: 'costSecond',
+    label: '耗时(ms)'
+  },
+  {
+    prop: 'log',
+    label: '日志'
+  },
+  { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
+])
+// 结果表格配置项
+// const resultColumns = reactive<ColumnProps<any>[]>([])
+// 表单配置项
+let itemsOptions: ProForm.ItemsOptions[] = []
+const setItemsOptions = () => {
+  itemsOptions = [
+    {
+      label: '子任务id',
+      prop: 'subTaskId',
+      compOptions: {
+        placeholder: '请输入子任务id'
+      }
+    },
+    {
+      label: '任务名称',
+      prop: 'name',
+      compOptions: {
+        placeholder: '请输入任务名称'
+      }
+    },
+    {
+      label: '任务类型',
+      prop: 'type',
+      compOptions: {
+        placeholder: '请输入任务类型'
+      }
+    },
+    {
+      label: '任务状态',
+      prop: 'status',
+      compOptions: {
+        elTagName: 'select',
+        labelKey: 'dictLabel',
+        valueKey: 'dictValue',
+        enum: () => getDictsApi('biz_task_status'),
+        placeholder: '请选择任务状态'
+      }
+    },
+    {
+      label: '算法',
+      prop: 'algorithmId',
+      compOptions: {
+        placeholder: '请输入算法'
+      }
+    },
+    {
+      label: '模型',
+      prop: 'modelId',
+      compOptions: {
+        placeholder: '请输入模型'
+      }
+    },
+    {
+      label: '调用算法时所用的参数',
+      prop: 'parameters',
+      compOptions: {
+        type: 'textarea',
+        clearable: true,
+        placeholder: '请输入内容'
+      }
+    },
+    {
+      label: '预处理数据路径',
+      prop: 'inputImagePath',
+      compOptions: {
+        placeholder: '请输入预处理数据路径'
+      }
+    },
+    {
+      label: '结果数据路径',
+      prop: 'outputImagePath',
+      compOptions: {
+        placeholder: '请输入结果数据路径'
+      }
+    },
+    {
+      label: '序号',
+      prop: 'index',
+      compOptions: {
+        placeholder: '请输入序号'
+      }
+    },
+    {
+      label: '开始时间',
+      prop: 'startTime',
+      compOptions: {
+        elTagName: 'date-picker',
+        type: 'date',
+        placeholder: '请选择开始时间'
+      }
+    },
+    {
+      label: '结束时间',
+      prop: 'endTime',
+      compOptions: {
+        elTagName: 'date-picker',
+        type: 'date',
+        placeholder: '请选择结束时间'
+      }
+    },
+    {
+      label: '耗时',
+      prop: 'costSecond',
+      compOptions: {
+        placeholder: '请输入耗时'
+      }
+    },
+    {
+      label: '日志',
+      prop: 'log',
+      compOptions: {
+        type: 'textarea',
+        clearable: true,
+        placeholder: '请输入内容'
+      }
+    }
+  ]
+}
+</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.2rem;
+    line-height: 50px;
+    text-align: center;
+  }
+  .row {
+    .col {
+      text-align: center;
+      .oneCol {
+        margin-top: 45px;
+        font-size: 1.2rem;
+      }
+      .img {
+        margin: 10px 0;
+      }
+    }
+  }
+}
+</style>

+ 5 - 1
src/views/task/subtask/index.vue

@@ -82,7 +82,11 @@ onMounted(() => {
 })
 // 查看详情
 const viewDetails = row => {
-  router.push({ path: `/task/bizProcess/`, query: { id: row.id } })
+  if (row.name === '数据扩增') {
+    router.push({ path: `/task/amplify/`, query: { id: row.id } })
+  } else {
+    router.push({ path: `/task/bizProcess/`, query: { id: row.id } })
+  }
 }
 // 删除算法子任务信息
 const deleteSubtask = async (params: any) => {

Dosya farkı çok büyük olduğundan ihmal edildi
+ 242 - 242
yarn.lock


Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor