Эх сурвалжийг харах

Merge remote-tracking branch 'origin/develop' into develop

allen 8 сар өмнө
parent
commit
140829ea97

+ 161 - 0
src/api/interface/demo/traceMerge.ts

@@ -0,0 +1,161 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface TraceMergeVO extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id: string | number
+
+  /**
+   * 任务名称
+   */
+  name: string
+
+  /**
+   * 任务状态
+   */
+  status: string
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters: string
+
+  /**
+   * 预处理数据路径
+   */
+  preprocessPath: string
+
+  /**
+   * 结果数据路径
+   */
+  resultPath: string
+
+  /**
+   * 开始时间
+   */
+  startTime: string
+
+  /**
+   * 结束时间
+   */
+  endTime: string
+
+  /**
+   * 耗时
+   */
+  costSecond: number
+
+  /**
+   * 备注
+   */
+  remarks: string
+}
+
+export interface TraceMergeForm {
+  /**
+   * 主键ID
+   */
+  id?: string | number
+
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters?: string
+
+  /**
+   * 预处理数据路径
+   */
+  preprocessPath?: string
+
+  /**
+   * 结果数据路径
+   */
+  resultPath?: string
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
+  /**
+   * 耗时
+   */
+  costSecond?: number
+
+  /**
+   * 备注
+   */
+  remarks?: string
+
+  /**
+   * 乐观锁
+   */
+  version?: number
+}
+
+export interface TraceMergeQuery extends PageQuery {
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters?: string
+
+  /**
+   * 预处理数据路径
+   */
+  preprocessPath?: string
+
+  /**
+   * 结果数据路径
+   */
+  resultPath?: string
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
+  /**
+   * 耗时
+   */
+  costSecond?: number
+
+  /**
+   * 备注
+   */
+  remarks?: string
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+}

+ 96 - 0
src/api/interface/system/importExport.ts

@@ -0,0 +1,96 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface ImportExportVO extends BaseEntity {
+  /**
+   * 唯一编码
+   */
+  id: string | number
+
+  /**
+   * 文件名称
+   */
+  name: string
+
+  /**
+   * 文件地址
+   */
+  url: string
+
+  /**
+   * 日志信息
+   */
+  logInfo: string
+
+  /**
+   * 状态(1正常  0异常)
+   */
+  status: string
+
+  /**
+   * 文件Id
+   */
+  ossId: number
+}
+
+export interface ImportExportForm {
+  /**
+   * 唯一编码
+   */
+  id?: string | number
+
+  /**
+   * 文件名称
+   */
+  name?: string
+
+  /**
+   * 文件地址
+   */
+  url?: string
+
+  /**
+   * 文件地址
+   */
+  ossId?: number
+
+  /**
+   * 日志信息
+   */
+  logInfo?: string
+
+  /**
+   * 状态(1正常  0异常)
+   */
+  status?: number
+
+  /**
+   * 乐观锁
+   */
+  version?: number
+}
+
+export interface ImportExportQuery extends PageQuery {
+  /**
+   * 文件名称
+   */
+  name?: string
+
+  /**
+   * 文件地址
+   */
+  url?: string
+
+  /**
+   * 日志信息
+   */
+  logInfo?: string
+
+  /**
+   * 状态(1正常  0异常)
+   */
+  status?: number
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+}

+ 4 - 0
src/api/modules/demo/dataAugmentation.ts

@@ -85,3 +85,7 @@ export const getCompareImageApi = (taskId: String, idx: String | Number) => {
 export const getCompareImageCountApi = (taskId: String | Number) => {
   return http.get('/demo/dataAugmentation/compare/num/' + taskId)
 }
+
+export const getDialogApi = (id: String | Number) => {
+  return http.get('/demo/dataAugmentation/log/' + id)
+}

+ 78 - 0
src/api/modules/demo/traceMerge.ts

@@ -0,0 +1,78 @@
+import http from '@/api'
+import { TraceMergeVO, TraceMergeForm, TraceMergeQuery } from '@/api/interface/demo/traceMerge'
+/**
+ * @name 查询多物体融合轨迹识别列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listTraceMergeApi = (query: TraceMergeQuery) => {
+  return http.get<TraceMergeVO[]>('/demo/traceMerge/list', query, { loading: true })
+}
+
+/**
+ * @name 查询多物体融合轨迹识别详细
+ * @param id id
+ * @returns returns
+ */
+export const getTraceMergeApi = (id: string | number) => {
+  return http.get<TraceMergeVO>(`/demo/traceMerge/${id}`)
+}
+
+/**
+ * @name 新增多物体融合轨迹识别
+ * @param data data
+ * @returns returns
+ */
+export const addTraceMergeApi = (data: TraceMergeForm) => {
+  return http.post<any>('/demo/traceMerge', data, { loading: false })
+}
+
+export const executeApi = data => {
+  return http.post<any>('/demo/traceMerge/execute', data, { loading: false })
+}
+
+export const getResApi = data => {
+  return http.get<any>('/demo/traceMerge/result', data, { loading: false })
+}
+
+/**
+ * @name 修改多物体融合轨迹识别
+ * @param data data
+ * @returns returns
+ */
+export const updateTraceMergeApi = (data: TraceMergeForm) => {
+  return http.put<any>('/demo/traceMerge', data, { loading: false })
+}
+
+/**
+ * @name 删除多物体融合轨迹识别
+ * @param id id
+ * @returns returns
+ */
+export const delTraceMergeApi = (id: string | number | Array<string | number>) => {
+  return http.delete<any>(`/demo/traceMerge/${id}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/demo/traceMerge/importTemplate', {})
+}
+
+/**
+ * @name 导入数据
+ * @returns returns
+ */
+export const importTraceMergeDataApi = (data: any) => {
+  return http.post('/demo/traceMerge/importData', data)
+}
+
+/**
+ * @name 导出数据
+ * @returns returns
+ */
+export const exportTraceMergeApi = (data: any) => {
+  return http.downloadPost('/demo/traceMerge/export', data)
+}

+ 4 - 0
src/api/modules/demo/videoStable.ts

@@ -85,3 +85,7 @@ export const getCompareImageApi = (taskId: String, idx: String | Number) => {
 export const getCompareImageCountApi = (taskId: String | Number) => {
   return http.get('/demo/videoStable/compare/num/' + taskId)
 }
+
+export const getImagesApi = (ossid: String | Number) => {
+  return http.get('/demo/videoStable/images/' + ossid)
+}

+ 19 - 0
src/api/modules/system/importExport.ts

@@ -0,0 +1,19 @@
+import http from '@/api'
+import { ImportExportVO, ImportExportQuery } from '@/api/interface/system/importExport'
+/**
+ * @name 查询导入导出日志列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listImportExportApi = (query: ImportExportQuery) => {
+  return http.get<ImportExportVO[]>('/system/importExport/list', query, { loading: false })
+}
+
+/**
+ * @name 查询导入导出日志详细
+ * @param id id
+ * @returns returns
+ */
+export const getImportExportApi = (id: string | number) => {
+  return http.get<ImportExportVO>(`/system/importExport/${id}`)
+}

+ 71 - 38
src/components/ImportPicDataset/index.vue

@@ -1,6 +1,6 @@
 <template>
   <el-dialog v-model="dialogVisible" :width="parameter.width" :top="parameter.top" :title="`${parameter.title}`" :destroy-on-close="true" draggable>
-    <el-form class="drawer-multiColumn-form" label-width="100px">
+    <el-form class="drawer-multiColumn-form" label-width="100px" :model="formModel" :rules="rules" ref="formRef">
       <el-form-item label="图片数据集压缩文件上传">
         <el-upload
           action="#"
@@ -78,7 +78,7 @@
 </template>
 
 <script setup lang="ts" name="ImportPicDataset">
-import { ref } from 'vue'
+import { ref, defineExpose, onMounted } from 'vue'
 import { ElNotification, UploadRequestOptions, UploadRawFile } from 'element-plus'
 
 export interface ParameterProps {
@@ -97,7 +97,6 @@ export interface ParameterProps {
 
 const formModel = ref({
   batchNum: '',
-  name: '',
   objectType: '',
   objectSubtype: '',
   scene: '',
@@ -107,11 +106,13 @@ const formModel = ref({
   dataType: '',
   labeled: false
 })
+
 const dataTypes = ref([
   { dictValue: '1', dictLabel: '训练' },
   { dictValue: '2', dictLabel: '测试' }
   // 添加更多数据类型
 ])
+
 const dialogVisible = ref(false)
 const parameter = ref<ParameterProps>({
   title: '',
@@ -124,12 +125,27 @@ const parameter = ref<ParameterProps>({
   ZipFileType: ['application/zip', 'application/x-zip-compressed', 'application/x-rar-compressed']
 })
 
+// 定义表单校验规则
+const rules = ref({
+  batchNum: [{ required: true, message: '批次号不能为空', trigger: 'blur' }],
+  objectType: [{ required: true, message: '目标类型不能为空', trigger: 'blur' }],
+  objectSubtype: [{ required: true, message: '目标子类型不能为空', trigger: 'blur' }],
+  scene: [{ required: true, message: '场景不能为空', trigger: 'blur' }],
+  dataSource: [{ required: true, message: '数据源不能为空', trigger: 'blur' }],
+  gatherSpot: [{ required: true, message: '采集地点不能为空', trigger: 'blur' }],
+  gatherTime: [{ required: true, message: '采集时间不能为空', trigger: 'change' }],
+  dataType: [{ required: true, message: '数据类型不能为空', trigger: 'change' }]
+})
+
+// 用于存储表单引用
+const formRef = ref(null)
+
+// 接收参数并初始化对话框
 const acceptParams = (params: ParameterProps) => {
   parameter.value = { ...parameter.value, ...params }
   dialogVisible.value = true
   formModel.value = {
     batchNum: '',
-    name: '',
     objectType: '',
     objectSubtype: '',
     scene: '',
@@ -140,41 +156,56 @@ const acceptParams = (params: ParameterProps) => {
     labeled: false
   }
 }
+
 const formData = new FormData()
+
 const handleSubmit = async () => {
-  const zipFile = formData.get('file')
-  console.log(zipFile)
-  if (!zipFile) {
-    ElNotification({
-      title: '温馨提示',
-      message: '请上传一个压缩文件!',
-      type: 'warning'
-    })
-    return
-  }
-  const formDataInfo = new FormData()
-  formDataInfo.append('file', zipFile)
-  for (const key in formModel.value) {
-    if (Object.prototype.hasOwnProperty.call(formModel.value, key)) {
-      formDataInfo.append(key, formModel.value[key])
+  // 先进行表单验证
+  formRef.value.validate(async valid => {
+    if (!valid) {
+      ElNotification({
+        title: '温馨提示',
+        message: '请检查表单的输入项!',
+        type: 'warning'
+      })
+      return
     }
-  }
-  try {
-    await parameter.value.importApi!(formDataInfo)
-    ElNotification({
-      title: '温馨提示',
-      message: `文件上传成功`,
-      type: 'success'
-    })
-    parameter.value.getTableList && parameter.value.getTableList()
-    dialogVisible.value = false
-  } catch (error) {
-    // ElNotification({
-    //   // title: '温馨提示',
-    //   // message: `文件上传失败,请重新上传`,
-    //   // type: 'error'
-    // })
-  }
+
+    const zipFile = formData.get('file')
+    if (!zipFile) {
+      ElNotification({
+        title: '温馨提示',
+        message: '请上传一个压缩文件!',
+        type: 'warning'
+      })
+      return
+    }
+
+    const formDataInfo = new FormData()
+    formDataInfo.append('file', zipFile)
+    for (const key in formModel.value) {
+      if (Object.prototype.hasOwnProperty.call(formModel.value, key)) {
+        formDataInfo.append(key, formModel.value[key])
+      }
+    }
+
+    try {
+      await parameter.value.importApi!(formDataInfo)
+      ElNotification({
+        title: '温馨提示',
+        message: `文件上传成功`,
+        type: 'success'
+      })
+      parameter.value.getTableList && parameter.value.getTableList()
+      dialogVisible.value = false
+    } catch (error) {
+      ElNotification({
+        title: '温馨提示',
+        message: `文件上传失败,请重新上传`,
+        type: 'error'
+      })
+    }
+  })
 }
 
 const uploadZip = (param: UploadRequestOptions) => {
@@ -184,13 +215,14 @@ const uploadZip = (param: UploadRequestOptions) => {
 const beforeZipUpload = (file: UploadRawFile) => {
   const isZip = parameter.value.ZipFileType!.includes(file.type as File.ZipMimeType)
   const fileSize = file.size / 1024 / 1024 < parameter.value.fileSize!
-  if (!isZip)
+  if (!isZip) {
     ElNotification({
       title: '温馨提示',
       message: '上传文件只能是 zip 格式!',
       type: 'warning'
     })
-  if (!fileSize)
+  }
+  if (!fileSize) {
     setTimeout(() => {
       ElNotification({
         title: '温馨提示',
@@ -198,6 +230,7 @@ const beforeZipUpload = (file: UploadRawFile) => {
         type: 'warning'
       })
     }, 0)
+  }
   return isZip && fileSize
 }
 

+ 69 - 0
src/components/TaskDialog/index.vue

@@ -0,0 +1,69 @@
+<template>
+  <el-dialog v-model="dialogVisible" :close-on-click-modal="false" :title="parameter.title" :destroy-on-close="true" width="600" top="8vh" draggable>
+    <div style="text-align: center" v-if="parameter.type === 'import'">
+      <h3>数据导入中...</h3>
+      <div class="info-text">关闭弹窗后可在[<el-link type="primary" @click="link">头像-我的导入导出-导入信息</el-link>] 中查看导入记录。</div>
+    </div>
+    <div style="text-align: center" v-else>
+      <h3>文件导出中...</h3>
+      <div class="info-text">关闭弹窗后可在[<el-link type="primary" @click="link">头像-我的导入导出-导出信息</el-link>] 下载查看。</div>
+    </div>
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button @click="handleCancel">关闭</el-button>
+      </span>
+    </template>
+  </el-dialog>
+  <IEDrawer ref="drawerRef" />
+</template>
+
+<script setup lang="ts" name="TaskDialog">
+import IEDrawer from '@/views/import-export/index.vue'
+import { ref } from 'vue'
+
+export interface DialogProps {
+  title: string // 标题
+  type: 'import' | 'export' // 导入导出类型
+}
+// dialog状态
+const dialogVisible = ref(false)
+// 父组件传过来的参数
+let parameter = ref<DialogProps>({
+  title: '导入信息',
+  type: 'import'
+})
+
+// 取消按钮,重置表单,关闭弹框
+const handleCancel = () => {
+  dialogVisible.value = false
+}
+const drawerRef = ref<InstanceType<typeof IEDrawer> | null>(null)
+const link = () => {
+  drawerRef.value?.acceptParams()
+  dialogVisible.value = false
+}
+// 接收父组件参数
+const openImportDialog = () => {
+  dialogVisible.value = true
+}
+const openExportDialog = () => {
+  dialogVisible.value = true
+  parameter.value = {
+    title: '导出信息',
+    type: 'export'
+  }
+}
+
+defineExpose({
+  openImportDialog,
+  openExportDialog,
+  handleCancel
+})
+</script>
+<style setup lang="scss">
+.info-text {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+</style>

+ 11 - 0
src/layouts/components/Header/components/Avatar.vue

@@ -11,6 +11,9 @@
         <el-dropdown-item @click="toProfile()">
           <el-icon><User /></el-icon>{{ $t('header.personalCenter') }}
         </el-dropdown-item>
+        <el-dropdown-item divided @click="openDrawer()">
+          <el-icon><Files /></el-icon>导入导出
+        </el-dropdown-item>
         <el-dropdown-item divided @click="logout">
           <el-icon><SwitchButton /></el-icon>{{ $t('header.logout') }}
         </el-dropdown-item>
@@ -19,6 +22,7 @@
   </el-dropdown>
   <InfoDialog ref="infoRef"></InfoDialog>
   <PasswordDialog ref="passwordRef"></PasswordDialog>
+  <IEDrawer ref="drawerRef" />
 </template>
 
 <script setup lang="ts">
@@ -26,8 +30,10 @@ import { LOGIN_URL } from '@/config'
 import { useRouter } from 'vue-router'
 import { useUserStore } from '@/stores/modules/user'
 import { ElMessageBox, ElMessage } from 'element-plus'
+import IEDrawer from '@/views/import-export/index.vue'
 import InfoDialog from './InfoDialog.vue'
 import PasswordDialog from './PasswordDialog.vue'
+import { ref } from 'vue'
 
 const router = useRouter()
 const userStore = useUserStore()
@@ -51,6 +57,11 @@ const logout = () => {
     ElMessage.success('退出登录成功!')
   })
 }
+// 打开 drawer(新增、查看、编辑)
+const drawerRef = ref<InstanceType<typeof IEDrawer> | null>(null)
+const openDrawer = () => {
+  drawerRef.value?.acceptParams()
+}
 </script>
 
 <style scoped lang="scss">

+ 9 - 0
src/views/ag/model/index.vue

@@ -25,6 +25,7 @@
         <el-button type="primary" link icon="EditPen" v-auth="['ag:model:edit']" @click="openDialog(2, '算法模型配置编辑', scope.row)">
           编辑
         </el-button>
+        <el-button type="primary" link icon="EditPen" @click="downloadPtFile(scope.row)"> 下载 </el-button>
         <el-button type="primary" link icon="Delete" v-auth="['ag:model:remove']" @click="deleteModel(scope.row)"> 删除 </el-button>
       </template>
     </ProTable>
@@ -54,6 +55,14 @@ import {
 } from '@/api/modules/ag/model'
 import { getAlgorithmOptionApi } from '@/api/modules/task/task'
 import { listTaskConfigurationApi } from '@/api/modules/task/taskConfiguration'
+import http from '@/api'
+
+const downloadPtFile = function (row) {
+  console.log(row)
+  if (row.modelAddress && row.modelAddress.length > 0) {
+    window.open('/api' + row.modelAddress, '_blank')
+  }
+}
 
 // ProTable 实例
 const proTable = ref<ProTableInstance>()

+ 9 - 1
src/views/demo/data/index.vue

@@ -3,7 +3,7 @@
     <el-image-viewer v-if="imgViewVisible" :url-list="['/api' + imageUrl]" @close="imgViewVisible = false" />
     <ProTable ref="proTable" :columns="columns" row-key="id" :request-api="listDataApi" :init-param="initParam">
       <template #yuan="scope">
-        <el-image style=" width: 200px;height: 200px" :src="'/api' + scope.row.url" @click="loadImg(scope.row.url)"></el-image>
+        <el-image style="width: 200px; height: 200px" :src="'/api' + scope.row.url" @click="loadImg(scope.row.url)"></el-image>
         <!--        <uploadImg :is-show-data="true" :disabled="true" :image-url="scope.row.url" @click="loadImg(scope.row.url)"/>-->
         <!--        <el-image style="width: 100px" :src="'/api' + scope.row.url" @click="markImg(scope.row)" />-->
       </template>
@@ -12,6 +12,8 @@
         <el-button type="primary" v-auth="['demo:data:add']" :icon="CirclePlus" @click="openDialog(1, '数据新增')"> 新增 </el-button>
         <el-button type="primary" v-auth="['demo:data:import']" :icon="Upload" plain @click="batchAdd"> 导入数据集 </el-button>
         <el-button type="primary" v-auth="['demo:data:export']" :icon="Download" plain @click="downloadFile(scope.selectedListIds)"> 导出 </el-button>
+        <el-button type="primary" v-auth="['system:user:add']" :icon="CirclePlus" @click="dataAmplify()"> 数据增广 </el-button>
+
         <el-button
           type="danger"
           v-auth="['demo:data:remove']"
@@ -77,6 +79,7 @@ import {
 import { listDataApi as listDictDataApi } from '@/api/modules/system/dictData'
 import { uploadPure } from '@/api/modules/upload'
 import http from '@/api'
+import { useRouter } from 'vue-router'
 
 onMounted(() => {
   state.cacheData.url = 'http://localhost:9090/profile/upload/2024/08/08/144745610/test.png'
@@ -358,6 +361,11 @@ const batchAdd = () => {
   dialogRef.value?.acceptParams(params)
 }
 
+const router = useRouter()
+const dataAmplify = () => {
+  router.push(`/data/amplify`)
+}
+
 const formDialogRef = ref<InstanceType<typeof FormDialog> | null>(null)
 // 打开弹框的功能
 const openDialog = async (type: number, title: string, row?: any) => {

+ 51 - 53
src/views/demo/dataAugmentation/index.vue

@@ -4,8 +4,8 @@
       <!-- 表格 header 按钮 -->
       <template #tableHeader="scope">
         <el-button type="primary" v-auth="['demo:DataAugmentation:add']" icon="CirclePlus" @click="openDialog(1, '任务新增')"> 新增 </el-button>
-        <!--        <el-button type="primary" v-auth="['demo:DataAugmentation:import']" icon="Upload" plain @click="batchAdd"> 导入</el-button>-->
-        <!--        <el-button type="primary" v-auth="['demo:DataAugmentation:export']" icon="Download" plain @click="downloadFile"> 导出 </el-button>-->
+        <!-- <el-button type="primary" v-auth="['demo:DataAugmentation:import']" icon="Upload" plain @click="batchAdd"> 导入</el-button> -->
+        <el-button type="primary" v-auth="['demo:DataAugmentation:export']" icon="Download" plain @click="downloadFile"> 导出 </el-button>
         <el-button
           type="danger"
           v-auth="['demo:DataAugmentation:remove']"
@@ -34,12 +34,10 @@
           </template>
         </el-popconfirm>
         <el-button type="primary" link icon="View" @click="compareDataAugmentation(scope.row)" v-if="scope.row.status == '2'"> 预览 </el-button>
-        <el-button type="primary" link icon="View" v-auth="['demo:DataAugmentation:query']" @click="openDialog(3, '视频去抖动查看', scope.row)">
+        <el-button type="primary" link icon="View" v-auth="['demo:DataAugmentation:query']" @click="openDialog(3, '任务查看', scope.row)">
           查看
         </el-button>
-        <!-- <el-button type="primary" link icon="EditPen" v-auth="['demo:DataAugmentation:edit']" @click="openDialog(2, '视频去抖动编辑', scope.row)">
-            编辑
-          </el-button> -->
+        <el-button type="primary" link icon="View" v-auth="['demo:DataAugmentation:query']" @click="openLogDialog(scope.row.id)"> 日志 </el-button>
         <el-button type="primary" link icon="Delete" v-auth="['demo:DataAugmentation:remove']" @click="deleteDataAugmentation(scope.row)">
           删除
         </el-button>
@@ -48,26 +46,23 @@
     <FormDialog ref="formDialogRef" />
     <ImportExcel ref="dialogRef" />
     <el-dialog v-model="dialogVisible" :title="dialogTitle" width="80%">
-      <div class="image-dialog" v-if="imageIdx >= 0">
-        <el-image
-          v-for="(image, index) in cacheImages[imageIdx].origin"
-          :key="index"
-          :src="'data:image/png;base64,' + image"
-          style="width: 45%"
-        ></el-image>
-        <el-tag>结果:</el-tag>
-        <el-image
-          v-for="(image, index) in cacheImages[imageIdx].stable"
-          :key="index"
-          :src="'data:image/png;base64,' + image"
-          style="width: 45%"
-        ></el-image>
+      <div class="image-dialog" v-if="imageIdx >= 0 && cacheImages[imageIdx]">
+        <div style="width: 50%">
+          <el-image v-for="(image, index) in cacheImages[imageIdx].origin" :key="index" :src="'data:image/png;base64,' + image"></el-image>
+          <!-- <el-tag>结果:</el-tag> -->
+        </div>
+        <div style="width: 50%">
+          <el-image v-for="(image, index) in cacheImages[imageIdx].stable" :key="index" :src="'data:image/png;base64,' + image"></el-image>
+        </div>
       </div>
       <div class="image-dialog-btn" v-if="imageFps == 0">
         <el-button type="primary" @click="pre_picture" :disabled="imageIdx <= 0">上一个</el-button>
         <el-button type="primary" @click="next_picture" :disabled="imageIdx >= fileCount - 1">下一个</el-button>
       </div>
     </el-dialog>
+    <el-dialog v-model="logDialogVisible" title="日志" width="80%">
+      <el-text class="mx-1">{{ logDialog }}</el-text>
+    </el-dialog>
   </div>
 </template>
 
@@ -92,9 +87,11 @@ import {
   startDataAugmentationApi,
   stopDataAugmentationApi,
   getCompareImageApi,
-  getCompareImageCountApi
+  getCompareImageCountApi,
+  getDialogApi
 } from '@/api/modules/demo/dataAugmentation'
 import { listDataApi } from '@/api/modules/system/dictData'
+import { S } from 'vite/dist/node/types.d-aGj9QkWt'
 const dialogVisible = ref(false)
 const taskId = ref('')
 const imageIdx = ref(0)
@@ -115,6 +112,13 @@ const taskTypeEnums: EnumProps[] = []
 
 const hyperparameterConfiguration = []
 const hyperparameter = ref('')
+const logDialogVisible = ref(false)
+const logDialog = ref('')
+const openLogDialog = async (id: string | number) => {
+  const res: any = await getDialogApi(id)
+  logDialog.value = res.data
+  logDialogVisible.value = true
+}
 const getTaskType = async () => {
   const res: any = await listDataApi({
     dictName: '',
@@ -195,7 +199,7 @@ const loadImageData = async (taskId: string, imageIdx: number) => {
 const compareDataAugmentation = async (params: any) => {
   taskId.value = params.id
   imageIdx.value = 0
-
+  cacheImages.value = {}
   const resCount: any = await getCompareImageCountApi(params.id)
   if (resCount.code === 200) {
     inFileCount.value = resCount.data.inFileCount
@@ -214,12 +218,14 @@ const compareDataAugmentation = async (params: any) => {
       continue
     }
     const res: any = await getCompareImageApi(taskId.value, idx - 1)
+    // console.log(res)
+
     cacheImages.value[idx - 1] = {
       origin: res.origin,
       stable: res.stable
     }
   }
-  console.log(cacheImages.value[0])
+  // console.log(cacheImages.value[0])
   dialogTitle.value = '预览: 第1个样本 共' + fileCount.value + '个样本'
   // next_picture()
 }
@@ -260,8 +266,8 @@ const batchDelete = async (ids: string[]) => {
 
 // 导出视频去抖动列表
 const downloadFile = async () => {
-  ElMessageBox.confirm('确认导出视频去抖动数据?', '温馨提示', { type: 'warning' }).then(() =>
-    useDownload(exportDataAugmentationApi, '视频去抖动列表', proTable.value?.searchParam)
+  ElMessageBox.confirm('确认导出任务数据?', '温馨提示', { type: 'warning' }).then(() =>
+    useDownload(exportDataAugmentationApi, '任务列表', proTable.value?.searchParam)
   )
 }
 
@@ -284,7 +290,9 @@ const openDialog = async (type: number, title: string, row?: any) => {
   let res = { data: {} }
   if (row?.id) {
     res = await getDataAugmentationApi(row?.id || null)
+    hyperparameter.value = res.data?.hyperparameterConfiguration
   }
+
   // 重置表单
   setItemsOptions()
   const params = {
@@ -292,7 +300,7 @@ const openDialog = async (type: number, title: string, row?: any) => {
     width: 580,
     isEdit: type !== 3,
     itemsOptions: itemsOptions,
-    model: type == 1 ? {} : res.data,
+    model: type == 1 ? model : res.data,
     api: type == 1 ? addDataAugmentationApi : updateDataAugmentationApi,
     getTableList: proTable.value?.getTableList
   }
@@ -337,7 +345,7 @@ const columns = reactive<ColumnProps<any>[]>([
   { prop: 'id', label: '主键ID', width: 180 },
   {
     prop: 'name',
-    label: '视频名称',
+    label: '任务名称',
     search: {
       el: 'input'
     },
@@ -403,7 +411,7 @@ const columns = reactive<ColumnProps<any>[]>([
 
   {
     prop: 'algorithmPath',
-    label: '算法路径',
+    label: '日志路径',
     width: 120
   },
   {
@@ -428,6 +436,7 @@ const columns = reactive<ColumnProps<any>[]>([
 ])
 // 表单配置项
 let itemsOptions: ProForm.ItemsOptions[] = []
+const model = ref({})
 const setItemsOptions = () => {
   itemsOptions = [
     {
@@ -447,20 +456,15 @@ const setItemsOptions = () => {
         placeholder: '请选择任务类型',
         enum: taskType,
         onChange: (value: string) => {
-          // itemsOptions.forEach(obj => {
-          //   if (obj.prop == "hyperparameterConfiguration") {
-          //     hyperparameterConfiguration.forEach(obj1 => {
-          //       if (value in obj1) {
-          //         obj.compOptions.value = obj1[value]
-          //         hyperparameter.value = obj1[value]
-          //       }
-          //     })
-
-          //   }
-          // })
           hyperparameterConfiguration.forEach(obj => {
             if (value in obj) {
               hyperparameter.value = obj[value]
+              // console.log(obj)
+              model.value['hyperparameterConfiguration'] = obj[value]
+              // itemsOptions[3]['compOptions']['value'] = obj[value]
+              //itemsOptions[3].compOptions.onChange(obj[value])
+              // let change = itemsOptions[3]['compOptions']['onChange']
+              // change(obj[value])
             }
           })
         }
@@ -469,7 +473,7 @@ const setItemsOptions = () => {
     {
       label: '图片集压缩包',
       prop: 'inputOssId',
-      rules: [{ required: true, message: '数据压缩包不能为空', trigger: 'blur' }],
+      rules: [{ required: true, message: '数据压缩包不能为空', trigger: 'change' }],
       compOptions: {
         elTagName: 'file-upload',
         fileSize: 4096,
@@ -477,26 +481,19 @@ const setItemsOptions = () => {
         placeholder: '请上传图片集压缩包'
       }
     },
-    // {
-    //   label: '算法路径',
-    //   prop: 'algorithmPath',
-    //   rules: [],
-    //   compOptions: {
-    //     type: 'input',
-    //     clearable: true,
-    //     placeholder: ''
-    //   }
-    // },
     {
       label: '超参配置',
       prop: 'hyperparameterConfiguration',
-      rules: [{ required: true, message: '超参配置不能为空', trigger: 'blur' }],
+      // rules: [{ required: true, message: '超参配置不能为空', trigger: 'blur' }],
+      rules: [{ required: false, trigger: 'blur' }],
       compOptions: {
         type: 'input',
         clearable: true,
         // placeholder: hyperparameter
-        value: hyperparameter
-        //value: hyperparameterConfiguration[itemsOptions.taskType]
+        value: hyperparameter,
+        onChange: (value: string) => {
+          hyperparameter.value = value
+        }
       }
     },
     {
@@ -519,6 +516,7 @@ const setItemsOptions = () => {
 <style lang="scss" scoped>
 .image-dialog {
   display: flex;
+  align-items: center;
   justify-content: center;
   .el-image {
     margin-right: 20px;

+ 401 - 0
src/views/demo/traceMerge/index.vue

@@ -0,0 +1,401 @@
+<template>
+  <div class="table-box">
+    <ProTable ref="proTable" :columns="columns" row-key="id" :request-api="listTraceMergeApi">
+      <!-- 表格 header 按钮 -->
+      <template #tableHeader="scope">
+        <el-button type="primary" v-auth="['demo:traceMerge:add']" icon="CirclePlus" @click="createTask"> 新增 </el-button>
+        <el-button type="primary" v-auth="['demo:traceMerge:import']" icon="Upload" plain @click="batchAdd"> 导入 </el-button>
+        <el-button type="primary" v-auth="['demo:traceMerge:export']" icon="Download" plain @click="downloadFile"> 导出 </el-button>
+        <el-button
+          type="danger"
+          v-auth="['demo:traceMerge:remove']"
+          icon="Delete"
+          plain
+          :disabled="!scope.isSelected"
+          @click="batchDelete(scope.selectedListIds)"
+        >
+          批量删除
+        </el-button>
+      </template>
+      <!-- 表格操作 -->
+      <template #operation="scope">
+        <el-button type="primary" link icon="View" v-auth="['demo:traceMerge:query']" @click="openDialog(3, '多物体融合轨迹识别查看', scope.row)">
+          查看
+        </el-button>
+        <!--        <el-button type="primary" link icon="EditPen" v-auth="['demo:traceMerge:edit']" @click="openDialog(2, '多物体融合轨迹识别编辑', scope.row)">-->
+        <!--          编辑-->
+        <!--        </el-button>-->
+        <!--        <el-button type="primary" link icon="Delete" v-auth="['demo:traceMerge:remove']" @click="deleteTraceMerge(scope.row)"> 删除 </el-button>-->
+        <el-button type="primary" link icon="View" @click="execute(scope.row)"> 执行任务 </el-button>
+        <el-button type="primary" link icon="View" @click="display(scope.row)"> 展示结果 </el-button>
+        <el-button type="primary" link icon="View" @click="showLog(scope.row)"> 查看日志 </el-button>
+      </template>
+    </ProTable>
+    <FormDialog ref="formDialogRef" />
+    <ImportExcel ref="dialogRef" />
+
+    <el-dialog v-model="createTaskDialogVisible" title="新增任务">
+      <el-container style="display: flex; flex-direction: column; justify-content: center">
+        <el-container>
+          <span style="min-width: 80px">任务名称</span>
+          <el-input v-model="params.name" placeholder="请输入任务名称"></el-input>
+        </el-container>
+        <el-container style="margin-top: 20px">
+          <span style="min-width: 80px">任务文件</span>
+          <file @update:model-value="updateFiles" :file-size="20" :file-type="['mat']"></file>
+        </el-container>
+      </el-container>
+      <span class="dialog-footer">
+        <el-button type="primary" @click="submitCreateTask">确 定</el-button>
+        <el-button @click="createTaskDialogVisible = false">取 消</el-button>
+      </span>
+    </el-dialog>
+
+    <el-dialog v-model="displayDialogVisible" title="执行结果">
+      <el-container direction="vertical">
+        <el-container v-for="(item, index) in resultData" :key="index" direction="horizontal" style="place-items: center center">
+          <span> {{ item.split('/')[item.split('/').length - 1] }} </span>
+          <el-image :src="'/api/profile' + item" style="max-width: 600px; max-height: 300px"></el-image>
+        </el-container>
+      </el-container>
+    </el-dialog>
+
+    <el-dialog v-model="logDialogVisible" title="查看日志">
+      <el-container direction="vertical">
+        <el-container v-for="(item, index) in logData" :key="index">
+          {{ item }}
+        </el-container>
+      </el-container>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="tsx" name="TraceMerge">
+import { reactive, ref } from 'vue'
+import { useHandleData } from '@/hooks/useHandleData'
+import { useDownload } from '@/hooks/useDownload'
+import { ElMessage, ElMessageBox } 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 { ColumnProps, ProTableInstance } from '@/components/ProTable/interface'
+import {
+  addTraceMergeApi,
+  delTraceMergeApi,
+  executeApi,
+  exportTraceMergeApi,
+  getResApi,
+  getTraceMergeApi,
+  importTemplateApi,
+  importTraceMergeDataApi,
+  listTraceMergeApi,
+  updateTraceMergeApi
+} from '@/api/modules/demo/traceMerge'
+import File from '@/components/Upload/File.vue'
+import { getDictsApi } from '@/api/modules/system/dictData'
+import http from '@/api'
+
+const logDialogVisible = ref(false)
+const logData = ref([])
+const showLog = async function (row) {
+  let path = row.resultPath.split('ObjectDetection_Web')
+  path = path[path.length - 1]
+  let res = await http.get('/profile' + path + '/fusion.log')
+  // let res = 'hello \r\n world!'
+  logData.value = res.split('\n')
+  logDialogVisible.value = true
+}
+const createTaskDialogVisible = ref(false)
+const params = ref({
+  preprocessPath: null,
+  name: ''
+})
+
+const resultData = ref([])
+const displayDialogVisible = ref(false)
+const display = function (row) {
+  // console.log(row)
+  getResApi({ taskId: row.id }).then(res => {
+    if (res.code !== 200) {
+      ElMessage.error(res.msg)
+      return
+    }
+    let arr = row.resultPath.split('ObjectDetection_Web')
+    let pathPrefix = arr[arr.length - 1]
+    resultData.value = []
+    for (let i = 1; i < res.data[0]; i++) {
+      resultData.value.push(pathPrefix + '/number' + i + '.png')
+    }
+    console.log('resultData', resultData.value)
+    displayDialogVisible.value = true
+  })
+}
+
+const execute = function (row) {
+  executeApi({ taskId: row.id }).then(res => {
+    console.log(res)
+    if (res.code == 200) {
+      ElMessage.success('开始执行!')
+    } else {
+      ElMessage.error('执行失败: ' + res.msg)
+    }
+  })
+}
+
+const createTask = function () {
+  createTaskDialogVisible.value = true
+}
+
+const submitCreateTask = function () {
+  if (params.value.preprocessPath == null || params.value.preprocessPath === '') {
+    ElMessage.error('请上传mat文件!')
+    return
+  } else if (params.value.name == null || params.value.name === '') {
+    ElMessage.error('请输入任务名称!')
+    return
+  }
+  addTraceMergeApi(params.value)
+    .then(res => {
+      console.log(res)
+      if (res.code === 200) {
+        ElMessage.success('创建成功!')
+        createTaskDialogVisible.value = false
+      } else {
+        ElMessage.error(res.msg)
+      }
+    })
+    .catch(err => {
+      console.log(err)
+      ElMessage.error('创建错误!')
+    })
+}
+
+const updateFiles = function (filePath) {
+  console.log('filepath', filePath)
+  params.value.preprocessPath = filePath
+}
+
+// ProTable 实例
+const proTable = ref<ProTableInstance>()
+
+// 删除多物体融合轨迹识别信息
+const deleteTraceMerge = async (params: any) => {
+  await useHandleData(delTraceMergeApi, params.id, '删除【' + params.id + '】多物体融合轨迹识别')
+  proTable.value?.getTableList()
+}
+
+// 批量删除多物体融合轨迹识别信息
+const batchDelete = async (ids: string[]) => {
+  await useHandleData(delTraceMergeApi, ids, '删除所选多物体融合轨迹识别信息')
+  proTable.value?.clearSelection()
+  proTable.value?.getTableList()
+}
+
+// 导出多物体融合轨迹识别列表
+const downloadFile = async () => {
+  ElMessageBox.confirm('确认导出多物体融合轨迹识别数据?', '温馨提示', { type: 'warning' }).then(() =>
+    useDownload(exportTraceMergeApi, '多物体融合轨迹识别列表', proTable.value?.searchParam)
+  )
+}
+
+// 批量添加多物体融合轨迹识别
+const dialogRef = ref<InstanceType<typeof ImportExcel> | null>(null)
+const batchAdd = () => {
+  const params = {
+    title: '多物体融合轨迹识别',
+    tempApi: importTemplateApi,
+    importApi: importTraceMergeDataApi,
+    getTableList: proTable.value?.getTableList
+  }
+  dialogRef.value?.acceptParams(params)
+}
+
+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 getTraceMergeApi(row?.id || null)
+  }
+  // 重置表单
+  setItemsOptions()
+  const params = {
+    title,
+    width: 580,
+    isEdit: type !== 3,
+    itemsOptions: itemsOptions,
+    model: type == 1 ? {} : res.data,
+    api: type == 1 ? addTraceMergeApi : updateTraceMergeApi,
+    getTableList: proTable.value?.getTableList
+  }
+  formDialogRef.value?.openDialog(params)
+}
+
+// 表格配置项
+const columns = reactive<ColumnProps<any>[]>([
+  { type: 'selection', fixed: 'left', width: 70 },
+  { prop: 'id', label: '主键ID' },
+  {
+    prop: 'name',
+    label: '任务名称',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'status',
+    label: '任务状态',
+    search: {
+      el: 'input'
+    },
+    width: 120,
+    tag: true,
+    enum: () => getDictsApi('biz_task_status'),
+    fieldNames: { label: 'dictLabel', value: 'dictValue' }
+  },
+  {
+    prop: 'parameters',
+    label: '调用算法时所用的参数',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'preprocessPath',
+    label: '预处理数据路径',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'resultPath',
+    label: '结果数据路径',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'startTime',
+    label: '开始时间',
+    search: {
+      el: 'date-picker',
+      props: { type: 'datetimerange', valueFormat: 'YYYY-MM-DD HH:mm:ss' }
+    },
+    width: 120
+  },
+  {
+    prop: 'endTime',
+    label: '结束时间',
+    search: {
+      el: 'date-picker',
+      props: { type: 'datetimerange', valueFormat: 'YYYY-MM-DD HH:mm:ss' }
+    },
+    width: 120
+  },
+  {
+    prop: 'costSecond',
+    label: '耗时',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'remarks',
+    label: '备注',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
+])
+// 表单配置项
+let itemsOptions: ProForm.ItemsOptions[] = []
+const setItemsOptions = () => {
+  itemsOptions = [
+    {
+      label: '任务名称',
+      prop: 'name',
+      rules: [{ required: true, message: '任务名称不能为空', trigger: 'blur' }],
+      compOptions: {
+        placeholder: '请输入任务名称'
+      }
+    },
+    {
+      label: '任务状态',
+      prop: 'status',
+      rules: [{ required: true, message: '任务状态不能为空', trigger: 'blur' }],
+      compOptions: {
+        placeholder: '请输入任务状态'
+      }
+    },
+    {
+      label: '调用算法时所用的参数',
+      prop: 'parameters',
+      rules: [{ required: true, message: '调用算法时所用的参数不能为空', trigger: 'blur' }],
+      compOptions: {
+        type: 'textarea',
+        clearable: true,
+        placeholder: '请输入内容'
+      }
+    },
+    {
+      label: '预处理数据路径',
+      prop: 'preprocessPath',
+      rules: [{ required: true, message: '预处理数据路径不能为空', trigger: 'blur' }],
+      compOptions: {
+        placeholder: '请输入预处理数据路径'
+      }
+    },
+    {
+      label: '结果数据路径',
+      prop: 'resultPath',
+      rules: [{ required: true, message: '结果数据路径不能为空', trigger: 'blur' }],
+      compOptions: {
+        placeholder: '请输入结果数据路径'
+      }
+    },
+    {
+      label: '开始时间',
+      prop: 'startTime',
+      rules: [{ required: true, message: '开始时间不能为空', trigger: 'change' }],
+      compOptions: {
+        elTagName: 'date-picker',
+        type: 'date',
+        placeholder: '请选择开始时间'
+      }
+    },
+    {
+      label: '结束时间',
+      prop: 'endTime',
+      rules: [{ required: true, message: '结束时间不能为空', trigger: 'change' }],
+      compOptions: {
+        elTagName: 'date-picker',
+        type: 'date',
+        placeholder: '请选择结束时间'
+      }
+    },
+    {
+      label: '耗时',
+      prop: 'costSecond',
+      rules: [{ required: true, message: '耗时不能为空', trigger: 'blur' }],
+      compOptions: {
+        placeholder: '请输入耗时'
+      }
+    },
+    {
+      label: '备注',
+      prop: 'remarks',
+      rules: [{ required: true, message: '备注不能为空', trigger: 'blur' }],
+      compOptions: {
+        placeholder: '请输入备注'
+      }
+    }
+  ]
+}
+</script>

+ 33 - 56
src/views/demo/videoStable/index.vue

@@ -46,24 +46,27 @@
     <FormDialog ref="formDialogRef" />
     <ImportExcel ref="dialogRef" />
     <el-dialog v-model="dialogVisible" :title="dialogTitle" width="80%">
-      <el-form>
+      <el-form :inline="true">
         <el-form-item label="帧率">
           <el-select v-model="imageFps" placeholder="选择帧率" style="width: 200px" @change="changeFps">
             <el-option label="0" value="0"></el-option>
             <el-option label="5" value="5"></el-option>
             <el-option label="15" value="15"></el-option>
             <el-option label="30" value="30"></el-option>
-            <el-option label="60" value="60"></el-option>
           </el-select>
         </el-form-item>
+        <el-form-item label="跳转至">
+          <el-input v-model="newImageIdx" type="number" style="width: 100px" />
+          <el-button type="primary" @click="confirmNewImageIdx" style="margin-left: 10px">确认</el-button>
+        </el-form-item>
       </el-form>
-      <div class="image-dialog" v-if="imageIdx > 0">
-        <el-image :src="'data:image/png;base64,' + cacheImages[imageIdx].origin" style="width: 45%"></el-image>
-        <el-image :src="'data:image/png;base64,' + cacheImages[imageIdx].stable" style="width: 45%"></el-image>
+      <div class="image-dialog">
+        <el-image :src="imageUrlList[imageIdx].inputUrl" style="width: 45%"></el-image>
+        <el-image :src="imageUrlList[imageIdx].outputUrl" style="width: 45%"></el-image>
       </div>
       <div class="image-dialog-btn" v-if="imageFps == 0">
-        <el-button type="primary" @click="pre_picture" :disabled="imageIdx <= 1">上一个</el-button>
-        <el-button type="primary" @click="next_picture" :disabled="imageIdx >= fileCount">下一个</el-button>
+        <el-button type="primary" @click="pre_picture" :disabled="imageIdx <= 0">上一个</el-button>
+        <el-button type="primary" @click="next_picture" :disabled="imageIdx >= imageUrlList.length - 1">下一个</el-button>
       </div>
     </el-dialog>
   </div>
@@ -89,23 +92,18 @@ import {
   getVideoStableApi,
   startVideoStableApi,
   stopVideoStableApi,
-  getCompareImageApi,
-  getCompareImageCountApi
+  // getCompareImageApi,
+  // getCompareImageCountApi,
+  getImagesApi
 } from '@/api/modules/demo/videoStable'
 
 const dialogVisible = ref(false)
-const taskId = ref('')
 const imageIdx = ref(0)
-const imageBase64List = ref({
-  origin: '',
-  stable: ''
-})
-const inFileCount = ref(0)
-const outFileCount = ref(0)
+const imageUrlList: any = ref([])
+const newImageIdx = ref('')
+
 // 直接缓存所有图片
-const cacheImages = ref({ 0: { origin: '', stable: '' } })
 const dialogTitle = ref('')
-const fileCount = ref(0)
 const imageFps = ref(0)
 const intervalChangeFps: any = ref()
 
@@ -144,57 +142,36 @@ const stopVideoStable = async (params: any) => {
   proTable.value?.getTableList()
 }
 
-const loadImageData = async (taskId: string, imageIdx: number) => {
-  const res: any = await getCompareImageApi(taskId, imageIdx)
-  imageBase64List.value.origin = res.origin
-  imageBase64List.value.stable = res.stable
+const confirmNewImageIdx = () => {
+  const val = parseInt(newImageIdx.value)
+  if (val > 0 && val <= imageUrlList.value.length) {
+    imageIdx.value = val - 1
+  } else {
+    ElMessageBox.alert('跳转索引有误,请检查!')
+  }
 }
+
 const compareVideoStable = async (params: any) => {
-  taskId.value = params.id
+  console.log('compareVideoStable')
+  const data: any = await getImagesApi(params.inputOssId)
+
+  imageUrlList.value = data.data
   imageIdx.value = 0
 
-  const resCount: any = await getCompareImageCountApi(params.id)
-  if (resCount.code === 200) {
-    inFileCount.value = resCount.data.inFileCount
-    outFileCount.value = resCount.data.outFileCount
-  } else {
-    ElMessage.error('获取图片对比数量失败')
-    return
-  }
+  dialogTitle.value = '预览: 第' + (imageIdx.value + 1) + '张图片 共' + imageUrlList.value.length + '张图片'
   dialogVisible.value = true
-
-  dialogTitle.value = '缓存图片中'
-  fileCount.value = Math.min(inFileCount.value, outFileCount.value)
-  for (let idx = 1; idx <= fileCount.value; idx++) {
-    dialogTitle.value = '缓存图片中: 第' + idx + '张图片 共' + fileCount.value + '张图片'
-    if (cacheImages.value[idx]) {
-      continue
-    }
-    const res: any = await getCompareImageApi(taskId.value, idx)
-    cacheImages.value[idx] = {
-      origin: res.origin,
-      stable: res.stable
-    }
-  }
-  next_picture()
 }
 const next_picture = async () => {
-  if (imageIdx.value < fileCount.value) {
-    if (!cacheImages.value[imageIdx.value + 1]) {
-      await loadImageData(taskId.value, imageIdx.value + 1)
-    }
+  if (imageIdx.value < imageUrlList.value.length - 1) {
     imageIdx.value = imageIdx.value + 1
   }
-  dialogTitle.value = '预览: 第' + imageIdx.value + '张图片 共' + fileCount.value + '张图片'
+  dialogTitle.value = '预览: 第' + (imageIdx.value + 1) + '张图片 共' + imageUrlList.value.length + '张图片'
 }
 const pre_picture = async () => {
-  if (imageIdx.value > 1) {
-    if (!cacheImages.value[imageIdx.value - 1]) {
-      await loadImageData(taskId.value, imageIdx.value - 1)
-    }
+  if (imageIdx.value > 0) {
     imageIdx.value = imageIdx.value - 1
   }
-  dialogTitle.value = '预览: 第' + imageIdx.value + '张图片 共' + fileCount.value + '张图片'
+  dialogTitle.value = '预览: 第' + (imageIdx.value + 1) + '张图片 共' + imageUrlList.value.length + '张图片'
 }
 
 // ProTable 实例

+ 193 - 0
src/views/import-export/index.vue

@@ -0,0 +1,193 @@
+<template>
+  <el-drawer v-model="drawerVisible" :destroy-on-close="true" size="950px" :title="drawerProps.title">
+    <el-tabs v-model="activeName">
+      <el-tab-pane label="导入日志" name="1">
+        <div class="drawer-table-box">
+          <ProTable
+            :columns="iColumns"
+            :height="400"
+            :tool-button="false"
+            row-key="id"
+            :init-param="{ type: '0' }"
+            :request-api="listImportExportApi"
+          >
+            <template #status="scope">
+              <div class="i-text">
+                <span v-show="scope.row.status == 1" style="margin-right: 8px">
+                  <i class="dot-class" style="background-color: #67c23a"></i>
+                </span>
+                <span v-show="scope.row.status == 0" style="margin-right: 8px">
+                  <i class="dot-class" style="background-color: #f56c6c"></i>
+                </span>
+                <span v-show="scope.row.status == 2" style="margin-right: 8px">
+                  <i class="dot-class" style="background-color: #e6a23c"></i>
+                </span>
+                <span> </span>
+              </div>
+            </template>
+            <!-- 表格操作 -->
+            <template #operation="scope">
+              <el-button type="primary" link @click="handleDownload(scope.row)"> 下载 </el-button>
+              <el-button type="primary" link @click="handleLog(scope.row)"> 日志 </el-button>
+            </template>
+          </ProTable>
+        </div>
+      </el-tab-pane>
+      <el-tab-pane label="导出日志" name="second">
+        <div class="drawer-table-box">
+          <ProTable
+            :columns="eColumns"
+            :height="400"
+            :tool-button="false"
+            row-key="id"
+            :init-param="{ type: '1' }"
+            :request-api="listImportExportApi"
+          >
+            <!-- 表格操作 -->
+            <template #operation="scope">
+              <el-button type="primary" link @click="handleDownload(scope.row)"> 下载 </el-button>
+              <el-button type="primary" link @click="handleLog(scope.row)"> 日志 </el-button>
+            </template>
+          </ProTable>
+        </div>
+      </el-tab-pane>
+    </el-tabs>
+  </el-drawer>
+</template>
+
+<script setup lang="ts" name="IEDrawer">
+import { ColumnProps } from '@/components/ProTable/interface'
+import { listImportExportApi } from '@/api/modules/system/importExport'
+import useDownload from '@/hooks/useDownload'
+import { ImportExportVO } from '@/api/interface/system/importExport'
+import { ElMessageBox } from 'element-plus'
+import { reactive, ref } from 'vue'
+import { getDictsApi } from '@/api/modules/system/dictData'
+
+const activeName = ref('1')
+interface DrawerProps {
+  title: string
+}
+
+const drawerVisible = ref(false)
+const drawerProps = ref<DrawerProps>({
+  title: '我的导入导出'
+})
+
+// const tableData = [
+//   {
+//     id: 11,
+//     name: 'Tom',
+//     status: '1',
+//     createBy: 'wanggaokun',
+//     updateTime: '2024-06-21 17:25:33'
+//   }
+// ]
+/** 下载按钮操作 */
+const handleDownload = (row: ImportExportVO) => {
+  useDownload.oss(row.ossId)
+}
+const handleLog = (row: ImportExportVO) => {
+  ElMessageBox.alert(row.logInfo, '日志信息', {
+    dangerouslyUseHTMLString: true
+  })
+}
+
+// 导入信息表格配置项
+const iColumns = reactive<ColumnProps<any>[]>([
+  {
+    type: 'index',
+    label: '序号',
+    width: 60
+  },
+  {
+    prop: 'name',
+    label: '文件名称',
+    search: {
+      el: 'input'
+    }
+  },
+  {
+    prop: 'status',
+    label: '状态',
+    enum: () => getDictsApi('sys_normal_disable'),
+    search: {
+      el: 'select'
+    },
+    width: 120
+  },
+  {
+    prop: 'createByName',
+    label: '操作人',
+    search: {
+      el: 'input'
+    },
+    width: 220
+  },
+  {
+    prop: 'createTime',
+    label: '操作时间',
+    width: 220
+  },
+  { prop: 'operation', label: '操作' }
+])
+// 导出信息表格配置项
+const eColumns = reactive<ColumnProps<any>[]>([
+  {
+    type: 'index',
+    label: '序号',
+    width: 60
+  },
+  {
+    prop: 'name',
+    label: '文件名称',
+    search: {
+      el: 'input'
+    }
+  },
+  {
+    prop: 'createByName',
+    label: '操作人',
+    width: 220
+  },
+  {
+    prop: 'createTime',
+    label: '操作时间',
+    width: 220
+  },
+  {
+    prop: 'status',
+    label: '状态',
+    tag: true,
+    enum: () => getDictsApi('sys_normal_disable'),
+    search: {
+      el: 'select'
+    },
+    width: 120
+  },
+  { prop: 'operation', label: '操作' }
+])
+
+// 接收父组件传过来的参数
+const acceptParams = () => {
+  drawerVisible.value = true
+}
+
+defineExpose({
+  acceptParams
+})
+</script>
+<style scoped lang="scss">
+.dot-class {
+  display: block;
+  width: 10px;
+  height: 10px;
+  margin-left: 10px; // 这个用于圆点居中
+  border-radius: 50%;
+}
+.i-text {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+</style>

+ 19 - 25
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>
@@ -149,7 +149,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>
@@ -222,12 +222,12 @@ const valid = data => {
       return ret
     }
   }
-  if (data.hasTrainAugmentation) {
-    if (!data.trainAugmentationParams || data.trainAugmentationParams.length === 0) {
-      ret.message = '请配置扩增参数'
-      return ret
-    }
-  }
+  // if (data.hasTrainAugmentation) {
+  //   if (!data.trainAugmentationParams || data.trainAugmentationParams.length === 0) {
+  //     ret.message = '请配置扩增参数'
+  //     return ret
+  //   }
+  // }
   ret.code = 200
   return ret
 }
@@ -242,7 +242,7 @@ const submit = () => {
     trainBatchNumList: formData.data,
     testBatchNumList: formData.testData,
     hasTrainAugmentation: formData.expandData,
-    trainAugmentationParams: formData.expandConfig
+    trainAugmentationParams: null
   }
   let result = valid(params)
   // console.log(result)
@@ -271,12 +271,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)
@@ -439,7 +434,7 @@ const formData = reactive({
   // 测试数据
   testData: [null],
   expandData: false,
-  expandConfig: ''
+  expandConfig: null
 })
 let selectDataIndex = null
 const dataDialogVisible = ref(false)
@@ -500,18 +495,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 = {
@@ -564,10 +558,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]
     }
   })
 }

+ 30 - 29
src/views/task/bizProcess/index.vue

@@ -3,48 +3,52 @@
     <ProTable ref="proTable" :columns="columns" row-key="id" :data="bizProcessList">
       <!-- 表格 header 按钮 -->
       <template #tableHeader="scope">
+        <!--        #tableHeader="scope"-->
         <!-- <el-button type="primary" v-auth="['identification:identificationSubtaskDetails:add']" icon="CirclePlus" @click="openDialog(1, '算法业务处理新增')"> 新增 </el-button>
         <el-button type="primary" v-auth="['identification:identificationSubtaskDetails:import']" icon="Upload" plain @click="batchAdd"> 导入 </el-button> -->
-        <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" 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(false && scope.row)"> 测试结果 </el-button>
         <el-button type="primary" icon="View" @click="showValResult(true)"> 验证结果 </el-button>
       </template>
       <!-- 表格操作 -->
       <template #operation="scope">
-        <el-button
-          type="primary"
-          link
-          icon="View"
-          v-auth="['identification:identificationSubtaskDetails:query']"
-          @click="openDialog(3, '算法业务处理查看', scope.row)"
-        >
-          查看详情
+        <!--        <el-button-->
+        <!--          type="primary"-->
+        <!--          link-->
+        <!--          icon="View"-->
+        <!--          v-auth="['identification:identificationSubtaskDetails:query']"-->
+        <!--          @click="openDialog(3, '算法业务处理查看', scope.row)"-->
+        <!--        >-->
+        <!--          查看详情-->
+        <!--        </el-button>-->
+        <el-button v-if="scope.row.name.indexOf('训练') === -1" type="primary" link icon="Refresh" @click="reRunTask(scope.row)">
+          执行训练
         </el-button>
+        <el-button v-else type="primary" link icon="Refresh" @click="startTask(scope.row)"> 开始训练 </el-button>
 
-        <el-button type="primary" link icon="finished" @click="showResult(scope.row)"> 执行结果 </el-button>
+        <el-button type="primary" link icon="finished" @click="showResult(scope.row)"> 结果 </el-button>
 
         <el-button v-show="scope.row.name.indexOf('训练') === -1" type="primary" link icon="search" @click="showExecutedTime(scope.row)">
           执行时间
         </el-button>
 
-        <el-button v-if="scope.row.name.indexOf('训练') === -1" type="primary" link icon="Refresh" @click="reRunTask(scope.row)">
-          执行训练
+        <el-button type="primary" link icon="document" v-auth="['identification:identificationSubtaskDetails:query']" @click="viewLog(scope.row)">
+          查看日志
         </el-button>
-        <el-button v-else type="primary" link icon="Refresh" @click="startTask(scope.row)"> 开始训练 </el-button>
 
         <el-button type="primary" link icon="Refresh" @click="exportData(scope.row)"> 导出结果 </el-button>
 
@@ -52,9 +56,6 @@
         <!--          编辑-->
         <!--        </el-button>-->
         <!--        <el-button type="primary" link icon="Delete" v-auth="['identification:identificationSubtaskDetails:remove']" @click="deleteBizProcess(scope.row)"> 删除 </el-button>-->
-        <el-button type="primary" link icon="document" v-auth="['identification:identificationSubtaskDetails:query']" @click="viewLog(scope.row)">
-          查看日志
-        </el-button>
       </template>
     </ProTable>
     <FormDialog ref="formDialogRef" />

+ 14 - 14
src/views/task/subtask/index.vue

@@ -2,21 +2,21 @@
   <div class="table-box">
     <ProTable ref="proTable" :is-show-search="false" :columns="columns" row-key="id" :data="subTaskList">
       <!-- 表格 header 按钮 -->
-      <template #tableHeader="scope">
-        <!-- <el-button type="primary" v-auth="['identification:identificationTask:add']" icon="CirclePlus" @click="openDialog(1, '算法子任务新增')"> 新增 </el-button>
+      <!--      <template #tableHeader="scope">-->
+      <!-- <el-button type="primary" v-auth="['identification:identificationTask:add']" icon="CirclePlus" @click="openDialog(1, '算法子任务新增')"> 新增 </el-button>
         <el-button type="primary" v-auth="['identification:identificationTask:import']" icon="Upload" plain @click="batchAdd"> 导入 </el-button> -->
-        <el-button type="primary" v-auth="['identification:identificationTask:export']" icon="Download" plain @click="downloadFile"> 导出 </el-button>
-        <el-button
-          type="danger"
-          v-auth="['identification:identificationTask:remove']"
-          icon="Delete"
-          plain
-          :disabled="!scope.isSelected"
-          @click="batchDelete(scope.selectedListIds)"
-        >
-          批量删除
-        </el-button>
-      </template>
+      <!--        <el-button type="primary" v-auth="['identification:identificationTask:export']" icon="Download" plain @click="downloadFile"> 导出 </el-button>-->
+      <!--        <el-button-->
+      <!--          type="danger"-->
+      <!--          v-auth="['identification:identificationTask:remove']"-->
+      <!--          icon="Delete"-->
+      <!--          plain-->
+      <!--          :disabled="!scope.isSelected"-->
+      <!--          @click="batchDelete(scope.selectedListIds)"-->
+      <!--        >-->
+      <!--          批量删除-->
+      <!--        </el-button>-->
+      <!--      </template>-->
       <!-- 表格操作 -->
       <template #operation="scope">
         <el-button type="primary" link icon="View" v-auth="['identification:identificationTask:query']" @click="viewDetails(scope.row)">