Procházet zdrojové kódy

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

WANGKANG před 8 měsíci
rodič
revize
35162cc05e
33 změnil soubory, kde provedl 3715 přidání a 688 odebrání
  1. 1 1
      package.json
  2. 144 146
      src/api/interface/demo/AlgorithmConfigTrack.ts
  3. 129 131
      src/api/interface/demo/AlgorithmModelTrack.ts
  4. 44 46
      src/api/interface/demo/TargetDetection.ts
  5. 186 0
      src/api/interface/demo/dataAugmentation.ts
  6. 161 0
      src/api/interface/demo/traceMerge.ts
  7. 96 0
      src/api/interface/system/importExport.ts
  8. 1 1
      src/api/modules/demo/AlgorithmModelTrack.ts
  9. 91 0
      src/api/modules/demo/dataAugmentation.ts
  10. 78 0
      src/api/modules/demo/traceMerge.ts
  11. 19 0
      src/api/modules/system/importExport.ts
  12. 218 0
      src/components/DataAugmentationFormDialog/index.vue
  13. 11 11
      src/components/FormDialog/index.vue
  14. 71 38
      src/components/ImportPicDataset/index.vue
  15. 1 0
      src/components/ProTable/index.vue
  16. 69 0
      src/components/TaskDialog/index.vue
  17. 7 1
      src/components/Upload/Img.vue
  18. 11 0
      src/layouts/components/Header/components/Avatar.vue
  19. 12 2
      src/views/ag/model/index.vue
  20. 1 1
      src/views/demo/AlgorithmConfigTrack/index.vue
  21. 31 35
      src/views/demo/DataSeq/index.vue
  22. 34 24
      src/views/demo/components/img-maker.vue
  23. 18 1
      src/views/demo/data/index.vue
  24. 528 0
      src/views/demo/dataAugmentation/index.vue
  25. 401 0
      src/views/demo/traceMerge/index.vue
  26. 193 0
      src/views/import-export/index.vue
  27. 1 1
      src/views/system/dict/data.vue
  28. 19 25
      src/views/taais/homePage/task/index.vue
  29. 139 88
      src/views/task/bizProcess/index.vue
  30. 14 14
      src/views/task/subtask/index.vue
  31. 426 0
      vite.config.ts.timestamp-1728903656862-499f9b40dc949.mjs
  32. 426 0
      vite.config.ts.timestamp-1729079247820-0269fb76961da.mjs
  33. 134 122
      yarn.lock

+ 1 - 1
package.json

@@ -99,7 +99,7 @@
     "stylelint-config-standard-scss": "^12.0.0",
     "typescript": "4.9.5",
     "unplugin-vue-setup-extend-plus": "^1.0.0",
-    "vite": "^5.0.8",
+    "vite": "^5.4.8",
     "vite-plugin-compression": "^0.5.1",
     "vite-plugin-eslint": "^1.8.1",
     "vite-plugin-prismjs": "^0.0.8",

+ 144 - 146
src/api/interface/demo/AlgorithmConfigTrack.ts

@@ -1,148 +1,146 @@
 import { PageQuery, BaseEntity } from '@/api/interface/index'
 export interface AlgorithmConfigTrackVO extends BaseEntity {
-    /**
-    * 主键ID
-    */
-        id: string | number;
-
-    /**
-    * 类型
-    */
-        type: string;
-
-    /**
-    * 父id
-    */
-        parentId: string | number;
-
-    /**
-    * 分系统
-    */
-        subsystem: string;
-
-    /**
-    * 算法名称
-    */
-        algorithmName: string;
-
-    /**
-    * 算法地址
-    */
-        algorithmAddress: string;
-
-    /**
-    * 参数配置
-    */
-        parameterConfig: string;
-
-    /**
-    * 备注
-    */
-        remarks: string;
-
-    /**
-    * 系统
-    */
-        system: string;
-
-    }
-
-    export interface AlgorithmConfigTrackForm {
-        /**
-        * 主键ID
-        */
-        id?: string | number;
-
-        /**
-        * 类型
-        */
-        type?: string;
-
-        /**
-        * 父id
-        */
-        parentId?: string | number;
-
-        /**
-        * 分系统
-        */
-        subsystem?: string;
-
-        /**
-        * 算法名称
-        */
-        algorithmName?: string;
-
-        /**
-        * 算法地址
-        */
-        algorithmAddress?: string;
-
-        /**
-        * 参数配置
-        */
-        parameterConfig?: string;
-
-        /**
-        * 备注
-        */
-        remarks?: string;
-
-        /**
-        * 乐观锁
-        */
-        version?: number;
-
-        /**
-        * 系统
-        */
-        system?: string;
-
-    }
-
-    export interface AlgorithmConfigTrackQuery extends PageQuery {
-        /**
-        * 类型
-        */
-        type?: string;
-
-        /**
-        * 父id
-        */
-        parentId?: string | number;
-
-        /**
-        * 分系统
-        */
-        subsystem?: string;
-
-        /**
-        * 算法名称
-        */
-        algorithmName?: string;
-
-        /**
-        * 算法地址
-        */
-        algorithmAddress?: string;
-
-        /**
-        * 参数配置
-        */
-        parameterConfig?: string;
-
-        /**
-        * 备注
-        */
-        remarks?: string;
-
-        /**
-        * 系统
-        */
-        system?: string;
-
-    /**
-    * 日期范围参数
-    */
-    params?: any;
-    }
+  /**
+   * 主键ID
+   */
+  id: string | number
+
+  /**
+   * 类型
+   */
+  type: string
+
+  /**
+   * 父id
+   */
+  parentId: string | number
+
+  /**
+   * 分系统
+   */
+  subsystem: string
+
+  /**
+   * 算法名称
+   */
+  algorithmName: string
+
+  /**
+   * 算法地址
+   */
+  algorithmAddress: string
+
+  /**
+   * 参数配置
+   */
+  parameterConfig: string
+
+  /**
+   * 备注
+   */
+  remarks: string
+
+  /**
+   * 系统
+   */
+  system: string
+}
+
+export interface AlgorithmConfigTrackForm {
+  /**
+   * 主键ID
+   */
+  id?: string | number
+
+  /**
+   * 类型
+   */
+  type?: string
+
+  /**
+   * 父id
+   */
+  parentId?: string | number
+
+  /**
+   * 分系统
+   */
+  subsystem?: string
+
+  /**
+   * 算法名称
+   */
+  algorithmName?: string
+
+  /**
+   * 算法地址
+   */
+  algorithmAddress?: string
+
+  /**
+   * 参数配置
+   */
+  parameterConfig?: string
+
+  /**
+   * 备注
+   */
+  remarks?: string
+
+  /**
+   * 乐观锁
+   */
+  version?: number
+
+  /**
+   * 系统
+   */
+  system?: string
+}
+
+export interface AlgorithmConfigTrackQuery extends PageQuery {
+  /**
+   * 类型
+   */
+  type?: string
+
+  /**
+   * 父id
+   */
+  parentId?: string | number
+
+  /**
+   * 分系统
+   */
+  subsystem?: string
+
+  /**
+   * 算法名称
+   */
+  algorithmName?: string
+
+  /**
+   * 算法地址
+   */
+  algorithmAddress?: string
+
+  /**
+   * 参数配置
+   */
+  parameterConfig?: string
+
+  /**
+   * 备注
+   */
+  remarks?: string
+
+  /**
+   * 系统
+   */
+  system?: string
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+}

+ 129 - 131
src/api/interface/demo/AlgorithmModelTrack.ts

@@ -1,133 +1,131 @@
 import { PageQuery, BaseEntity } from '@/api/interface/index'
 export interface AlgorithmModelTrackVO extends BaseEntity {
-    /**
-    * 主键ID
-    */
-        id: string | number;
-
-    /**
-    * 算法
-    */
-        algorithmId: string | number;
-
-    /**
-    * 模型名称
-    */
-        modelName: string;
-
-    /**
-    * 模型
-    */
-        modelAddress: string;
-
-    /**
-    * 训练样本数
-    */
-        sampleNumber: number;
-
-    /**
-    * 训练循环次数
-    */
-        cycleEpoch: number;
-
-    /**
-    * 备注
-    */
-        remarks: string;
-
-    /**
-    * 系统
-    */
-        system: string;
-
-    }
-
-    export interface AlgorithmModelTrackForm {
-        /**
-        * 主键ID
-        */
-        id?: string | number;
-
-        /**
-        * 算法
-        */
-        algorithmId?: string | number;
-
-        /**
-        * 模型名称
-        */
-        modelName?: string;
-
-        /**
-        * 模型
-        */
-        modelAddress?: string;
-
-        /**
-        * 训练样本数
-        */
-        sampleNumber?: number;
-
-        /**
-        * 训练循环次数
-        */
-        cycleEpoch?: number;
-
-        /**
-        * 备注
-        */
-        remarks?: string;
-
-        /**
-        * 乐观锁
-        */
-        version?: number;
-
-        /**
-        * 系统
-        */
-        system?: string;
-
-    }
-
-    export interface AlgorithmModelTrackQuery extends PageQuery {
-        /**
-        * 算法
-        */
-        algorithmId?: string | number;
-
-        /**
-        * 模型名称
-        */
-        modelName?: string;
-
-        /**
-        * 模型
-        */
-        modelAddress?: string;
-
-        /**
-        * 训练样本数
-        */
-        sampleNumber?: number;
-
-        /**
-        * 训练循环次数
-        */
-        cycleEpoch?: number;
-
-        /**
-        * 备注
-        */
-        remarks?: string;
-
-        /**
-        * 系统
-        */
-        system?: string;
-
-    /**
-    * 日期范围参数
-    */
-    params?: any;
-    }
+  /**
+   * 主键ID
+   */
+  id: string | number
+
+  /**
+   * 算法
+   */
+  algorithmId: string | number
+
+  /**
+   * 模型名称
+   */
+  modelName: string
+
+  /**
+   * 模型
+   */
+  modelAddress: string
+
+  /**
+   * 训练样本数
+   */
+  sampleNumber: number
+
+  /**
+   * 训练循环次数
+   */
+  cycleEpoch: number
+
+  /**
+   * 备注
+   */
+  remarks: string
+
+  /**
+   * 系统
+   */
+  system: string
+}
+
+export interface AlgorithmModelTrackForm {
+  /**
+   * 主键ID
+   */
+  id?: string | number
+
+  /**
+   * 算法
+   */
+  algorithmId?: string | number
+
+  /**
+   * 模型名称
+   */
+  modelName?: string
+
+  /**
+   * 模型
+   */
+  modelAddress?: string
+
+  /**
+   * 训练样本数
+   */
+  sampleNumber?: number
+
+  /**
+   * 训练循环次数
+   */
+  cycleEpoch?: number
+
+  /**
+   * 备注
+   */
+  remarks?: string
+
+  /**
+   * 乐观锁
+   */
+  version?: number
+
+  /**
+   * 系统
+   */
+  system?: string
+}
+
+export interface AlgorithmModelTrackQuery extends PageQuery {
+  /**
+   * 算法
+   */
+  algorithmId?: string | number
+
+  /**
+   * 模型名称
+   */
+  modelName?: string
+
+  /**
+   * 模型
+   */
+  modelAddress?: string
+
+  /**
+   * 训练样本数
+   */
+  sampleNumber?: number
+
+  /**
+   * 训练循环次数
+   */
+  cycleEpoch?: number
+
+  /**
+   * 备注
+   */
+  remarks?: string
+
+  /**
+   * 系统
+   */
+  system?: string
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+}

+ 44 - 46
src/api/interface/demo/TargetDetection.ts

@@ -1,15 +1,15 @@
-import {PageQuery, BaseEntity} from '@/api/interface/index'
+import { PageQuery, BaseEntity } from '@/api/interface/index'
 
 export interface TargetDetectionVO extends BaseEntity {
   /**
    * ID
    */
-  id: string | number;
+  id: string | number
 
   /**
    * 任务名称
    */
-  name: string;
+  name: string
 
   /**
    * 状态
@@ -19,75 +19,74 @@ export interface TargetDetectionVO extends BaseEntity {
    3:失败
    4:中断
    */
-  status: string;
+  status: string
 
   /**
    * 开始时间
    */
-  startTime: string;
+  startTime: string
 
   /**
    * 结束时间
    */
-  endTime: string;
+  endTime: string
 
   /**
    * 耗时
    */
-  costSecond: number;
+  costSecond: number
 
   /**
    * 日志
    */
-  log: string;
+  log: string
 
   /**
    * 备注
    */
-  remarks: string;
+  remarks: string
 
   /**
    * $column.columnComment
    */
-  url: string;
+  url: string
 
   /**
    * $column.columnComment
    */
-  inputOssId: string | number;
+  inputOssId: string | number
 
   /**
    * 输入路径
    */
-  inputPath: string;
+  inputPath: string
 
   /**
    * 输出路径
    */
-  outputPath: string;
+  outputPath: string
 
   /**
    * zip文件输出路径
    */
-  zipFilePath: string;
+  zipFilePath: string
 
   /**
    * 模型的id
    */
-  algorithmModelId: string | number;
-
+  algorithmModelId: string | number
 }
 
 export interface TargetDetectionForm {
   /**
    * ID
    */
-  id?: string | number;
+  id?: string | number
 
   /**
    * 任务名称
    */
-  name?: string;
+  name?: string
 
   /**
    * 状态
@@ -97,75 +96,74 @@ export interface TargetDetectionForm {
    3:失败
    4:中断
    */
-  status?: string;
+  status?: string
 
   /**
    * 开始时间
    */
-  startTime?: string;
+  startTime?: string
 
   /**
    * 结束时间
    */
-  endTime?: string;
+  endTime?: string
 
   /**
    * 耗时
    */
-  costSecond?: number;
+  costSecond?: number
 
   /**
    * 日志
    */
-  log?: string;
+  log?: string
 
   /**
    * 备注
    */
-  remarks?: string;
+  remarks?: string
 
   /**
    * $column.columnComment
    */
-  version?: number;
+  version?: number
 
   /**
    * $column.columnComment
    */
-  url?: string;
+  url?: string
 
   /**
    * $column.columnComment
    */
-  inputOssId?: string | number;
+  inputOssId?: string | number
 
   /**
    * 输入路径
    */
-  inputPath?: string;
+  inputPath?: string
 
   /**
    * 输出路径
    */
-  outputPath?: string;
+  outputPath?: string
 
   /**
    * zip文件输出路径
    */
-  zipFilePath?: string;
+  zipFilePath?: string
 
   /**
    * 模型的id
    */
-  algorithmModelId?: string | number;
-
+  algorithmModelId?: string | number
 }
 
 export interface TargetDetectionQuery extends PageQuery {
   /**
    * 任务名称
    */
-  name?: string;
+  name?: string
 
   /**
    * 状态
@@ -175,65 +173,65 @@ export interface TargetDetectionQuery extends PageQuery {
    3:失败
    4:中断
    */
-  status?: string;
+  status?: string
 
   /**
    * 开始时间
    */
-  startTime?: string;
+  startTime?: string
 
   /**
    * 结束时间
    */
-  endTime?: string;
+  endTime?: string
 
   /**
    * 耗时
    */
-  costSecond?: number;
+  costSecond?: number
 
   /**
    * 日志
    */
-  log?: string;
+  log?: string
 
   /**
    * 备注
    */
-  remarks?: string;
+  remarks?: string
 
   /**
    * $column.columnComment
    */
-  url?: string;
+  url?: string
 
   /**
    * $column.columnComment
    */
-  inputOssId?: string | number;
+  inputOssId?: string | number
 
   /**
    * 输入路径
    */
-  inputPath?: string;
+  inputPath?: string
 
   /**
    * 输出路径
    */
-  outputPath?: string;
+  outputPath?: string
 
   /**
    * zip文件输出路径
    */
-  zipFilePath?: string;
+  zipFilePath?: string
 
   /**
    * 模型的id
    */
-  algorithmModelId?: string | number;
+  algorithmModelId?: string | number
 
   /**
    * 日期范围参数
    */
-  params?: any;
+  params?: any
 }

+ 186 - 0
src/api/interface/demo/dataAugmentation.ts

@@ -0,0 +1,186 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface DataAugmentationVO extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id: string | number
+
+  /**
+   * 视频名称
+   */
+  name: string
+
+  /**
+   * 任务状态 0未开始 1进行中 2已结束
+   */
+  status: string
+
+  /**
+   * 输入图片集路径
+   */
+  inputPath: string
+
+  /**
+   * 去抖动的图片集路径
+   */
+  outPath: string
+
+  /**
+   * 开始时间
+   */
+  startTime: string
+
+  /**
+   * 结束时间
+   */
+  endTime: string
+
+  /**
+   * 耗时
+   */
+  costSecond: number
+
+  /**
+   * 日志
+   */
+  log: string
+
+  /**
+   * 备注
+   */
+  remarks: string
+  /**
+   * 算法路径
+   */
+  algorithmPath: string
+  /**
+   * 超参配置
+   */
+  hyperparameterConfiguration: string
+}
+
+export interface DataAugmentationForm {
+  /**
+   * 主键ID
+   */
+  id?: string | number
+
+  /**
+   * 视频名称
+   */
+  name?: string
+
+  /**
+   * 任务状态 0未开始 1进行中 2已结束
+   */
+  status?: string
+
+  /**
+   * 输入图片集路径
+   */
+  inputPath?: string
+
+  /**
+   * 去抖动的图片集路径
+   */
+  outPath?: string
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
+  /**
+   * 耗时
+   */
+  costSecond?: number
+
+  /**
+   * 日志
+   */
+  log?: string
+
+  /**
+   * 备注
+   */
+  remarks?: string
+
+  /**
+   * 乐观锁
+   */
+  version?: number
+  /**
+   * 算法路径
+   */
+  algorithmPath: string
+  /**
+   * 超参配置
+   */
+  hyperparameterConfiguration: string
+}
+
+export interface DataAugmentationQuery extends PageQuery {
+  /**
+   * 视频名称
+   */
+  name?: string
+
+  /**
+   * 任务状态 0未开始 1进行中 2已结束
+   */
+  taskType?: string
+  status?: string
+
+  /**
+   * 输入图片集路径
+   */
+  inputPath?: string
+
+  /**
+   * 去抖动的图片集路径
+   */
+  outPath?: string
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
+  /**
+   * 耗时
+   */
+  costSecond?: number
+
+  /**
+   * 日志
+   */
+  log?: string
+
+  /**
+   * 备注
+   */
+  remarks?: string
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+  /**
+   * 算法路径
+   */
+  algorithmPath: string
+  /**
+   * 超参配置
+   */
+  hyperparameterConfiguration: string
+}

+ 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
+}

+ 1 - 1
src/api/modules/demo/AlgorithmModelTrack.ts

@@ -69,6 +69,6 @@ export const exportAlgorithmModelTrackApi = (data: any) => {
   return http.downloadPost('/demo/AlgorithmModelTrack/export', data)
 }
 
-export const enumAlgorithmModelTrackApi = ():any => {
+export const enumAlgorithmModelTrackApi = (): any => {
   return http.get('/demo/AlgorithmModelTrack/enums')
 }

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

@@ -0,0 +1,91 @@
+import http from '@/api'
+import { DataAugmentationVO, DataAugmentationForm, DataAugmentationQuery } from '@/api/interface/demo/dataAugmentation'
+
+/**
+ * @name 查询视频去抖动列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listDataAugmentationApi = (query: DataAugmentationQuery) => {
+  return http.get<DataAugmentationVO[]>('/demo/dataAugmentation/list', query, { loading: true })
+}
+
+/**
+ * @name 查询视频去抖动详细
+ * @param id id
+ * @returns returns
+ */
+export const getDataAugmentationApi = (id: string | number) => {
+  return http.get<DataAugmentationVO>(`/demo/dataAugmentation/${id}`)
+}
+
+/**
+ * @name 新增视频去抖动
+ * @param data data
+ * @returns returns
+ */
+export const addDataAugmentationApi = (data: DataAugmentationForm) => {
+  return http.post<any>('/demo/dataAugmentation', data, { loading: false })
+}
+
+/**
+ * @name 修改视频去抖动
+ * @param data data
+ * @returns returns
+ */
+export const updateDataAugmentationApi = (data: DataAugmentationForm) => {
+  return http.put<any>('/demo/dataAugmentation', data, { loading: false })
+}
+
+/**
+ * @name 删除视频去抖动
+ * @param id id
+ * @returns returns
+ */
+export const delDataAugmentationApi = (id: string | number | Array<string | number>) => {
+  return http.delete<any>(`/demo/dataAugmentation/${id}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/demo/dataAugmentation/importTemplate', {})
+}
+
+/**
+ * @name 导入数据
+ * @returns returns
+ */
+export const importDataAugmentationDataApi = (data: any) => {
+  return http.post('/demo/dataAugmentation/importData', data)
+}
+
+/**
+ * @name 导出数据
+ * @returns returns
+ */
+export const exportDataAugmentationApi = (data: any) => {
+  return http.downloadPost('/demo/dataAugmentation/export', data)
+}
+
+export const startDataAugmentationApi = (id: String | Number) => {
+  return http.get('/demo/dataAugmentation/start/' + id)
+}
+
+export const stopDataAugmentationApi = (id: String | Number) => {
+  return http.get('/demo/dataAugmentation/stop/' + id)
+}
+
+export const getCompareImageApi = (taskId: String, idx: String | Number) => {
+  return http.get('/demo/dataAugmentation/compare/' + taskId + '/' + idx)
+}
+
+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)
+}

+ 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}`)
+}

+ 218 - 0
src/components/DataAugmentationFormDialog/index.vue

@@ -0,0 +1,218 @@
+<template>
+  <el-dialog
+    v-model="dialogVisible"
+    :close-on-click-modal="false"
+    :title="parameter.title"
+    :destroy-on-close="true"
+    :width="parameter.width"
+    :top="parameter.top"
+    :before-close="handleClose"
+    draggable
+  >
+    <ProFrom ref="proFormRef" :items-options="parameter.itemsOptions" :form-options="_options" :model="parameter.model">
+      <template #modelAddress="{}">
+        <FileUpload :file-size="4096" :file-type="['pt']" @update:model-value="setModelAddr" />
+      </template>
+    </ProFrom>
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button type="primary" v-if="parameter.isEdit" :loading="butLoading" @click="handleSubmit">确认</el-button>
+        <el-button @click="handleCancel">取消</el-button>
+      </span>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts" name="FormDialog">
+import { ref, ComputedRef, computed, reactive } from 'vue'
+import ProFrom from '@/components/ProForm/index.vue'
+import { ElMessage } from 'element-plus'
+import FileUpload from '@/components/Upload/File.vue'
+
+// import mittBus from '@/utils/mittBus'
+
+interface EmitEvent {
+  (e: 'update'): void
+}
+
+const emits = defineEmits<EmitEvent>()
+
+const videoUploadRef = ref<InstanceType<typeof FileUpload> | null>(null)
+
+export interface FormParameterProps {
+  title: string // 标题
+  width?: number // 弹框宽度
+  labelWidth?: number // label宽度
+  api?: (params: any) => Promise<any> // 表单提交api
+  isEdit?: boolean // 是否编辑
+  top?: string // 离顶部距离
+  formOptions?: ProForm.FormOptions // 表单配置
+  itemsOptions: ProForm.ItemsOptions[] // 动态表单字段配置
+  model?: Record<ProForm.FormItem['prop'], ProForm.FormItem['value']> // 表单数据对象
+  getTableList?: () => void // 获取表格数据的Api
+}
+
+// dialog状态
+const dialogVisible = ref(false)
+const butLoading = ref(false)
+// 父组件传过来的参数
+const parameter = ref<FormParameterProps>({
+  title: '',
+  width: 500,
+  top: '10vh',
+  itemsOptions: [],
+  formOptions: {},
+  isEdit: true
+})
+const _options: ComputedRef<ProForm.FormOptions> = computed(() => {
+  const form = {
+    labelWidth: 120,
+    hasFooter: false,
+    disabled: false
+  }
+  return Object.assign(form, parameter.value.formOptions)
+})
+
+const modelAddr = ref(null)
+const setModelAddr = res => {
+  //console.log("setModelAddr res:")
+  console.log(res)
+  modelAddr.value = res
+}
+
+const proFormRef = ref<InstanceType<typeof ProFrom> | null>(null)
+// 表单提交校验
+const handleSubmit = () => {
+  const formEl = proFormRef.value?.proFormRef
+  const formModel = proFormRef.value?.formModel
+  formModel.modelAddress = modelAddr.value
+  //console.log('formModel', formModel)
+
+  butLoading.value = true
+  if (!formEl) return
+  formEl.validate(valid => {
+    if (valid) {
+      let data = {}
+      if (algorithmModelId.value) {
+        data = { ...formModel, ...parameter.value.model, algorithmId: algorithmModelId.value }
+      } else {
+        data = { ...formModel, ...parameter.value.model }
+      }
+
+      let excludedKeys = ['name', 'taskType', 'inputOssId', 'remarks', 'modelAddress']
+      for (const key in data) {
+        if (data.hasOwnProperty(key) && !excludedKeys.includes(key)) {
+          let num = parseFloat(data[key])
+          if (isNaN(num) || !isFinite(num)) {
+            ElMessage.error('${key}参数设置不合理!')
+            return
+          } else {
+            if (key == 's_v' && Number.isInteger(num) && num % 2 == 0) {
+              ElMessage.error('${key}参数只能为奇数!')
+              return
+            }
+          }
+        }
+      }
+      // 使用 Object.fromEntries 从指定的键值对创建新的对象
+      let hyperparameters = Object.fromEntries(Object.entries(data).filter(([key, _]) => !excludedKeys.includes(key)))
+
+      // 将 hyperparameters 对象转换为 JSON 字符串
+      let hyperparameterConfigurationStr = JSON.stringify(hyperparameters)
+
+      // 向 data 对象中新增 hyperparameterConfiguration 属性
+      data.hyperparameterConfiguration = hyperparameterConfigurationStr
+      // 删除 modelAddress 属性,如果它存在
+      if (data.hasOwnProperty('modelAddress')) {
+        delete data.modelAddress
+      }
+      console.log(data)
+      parameter.value.api!(data).then(res => {
+        if (res.code == 200) {
+          proFormRef.value?.resetForm(formEl)
+          ElMessage.success('操作成功')
+          emits('update')
+          setItemsOptions()
+          parameter.value.model = {}
+          dialogVisible.value = false
+          parameter.value.getTableList && parameter.value.getTableList()
+        } else {
+          //console.log('message', res.message)
+        }
+      })
+      butLoading.value = false
+    }
+    butLoading.value = false
+  })
+}
+// mittBus.on('data:fileName', (fileName: string) => {
+//   if (fileName !== undefined && fileName !== null) {
+//     console.log(proFormRef.value?.formModel)
+//     if(proFormRef.value?.formModel){
+//       proFormRef.value.formModel.name = fileName.split('.')[0]
+//     }
+//   }
+// })
+// 取消按钮,重置表单,关闭弹框
+const setItemsOptions = () => {
+  if (parameter.value.itemsOptions.length > 4) {
+    parameter.value.itemsOptions.splice(4) //取消和确认后需要重新设置itemOptions
+  }
+}
+const handleClose = () => {
+  parameter.value.model = {}
+  dialogVisible.value = false
+  setItemsOptions()
+}
+const handleCancel = () => {
+  //console.log(parameter.value.model)
+  parameter.value.model = {}
+  setItemsOptions()
+  const formEl = proFormRef.value?.proFormRef
+  if (!formEl) return
+  if (parameter.value.model?.url) {
+    ElMessage.info('请先删除已经上传的图片')
+    return
+  }
+  proFormRef.value?.resetForm(formEl)
+  butLoading.value = false
+  dialogVisible.value = false
+}
+
+let algorithmModelId = ref(0)
+
+// 接收父组件参数
+const openDialog = (params: FormParameterProps, algoModelId = null) => {
+  algorithmModelId.value = algoModelId
+  parameter.value = { ...parameter.value, ...params }
+  _options.value.disabled = !parameter.value.isEdit
+  butLoading.value = false
+  dialogVisible.value = true
+}
+
+defineExpose({
+  openDialog
+})
+</script>
+
+<style scoped>
+.upload-video-box {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  height: 200px;
+  margin-top: 20px;
+  border: 1px dashed #cccccc;
+  :deep(.upload-file-uploader) {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 100%;
+    height: 100%;
+    font-size: 18px;
+    text-align: center;
+    cursor: pointer;
+  }
+}
+</style>

+ 11 - 11
src/components/FormDialog/index.vue

@@ -10,7 +10,7 @@
   >
     <ProFrom ref="proFormRef" :items-options="parameter.itemsOptions" :form-options="_options" :model="parameter.model">
       <template #modelAddress="{}">
-        <FileUpload :file-size="4096" :file-type="['pt']" @update:model-value="setModelAddr"/>
+        <FileUpload :file-size="4096" :file-type="['pt']" @update:model-value="setModelAddr" />
       </template>
     </ProFrom>
     <template #footer>
@@ -23,9 +23,9 @@
 </template>
 
 <script setup lang="ts" name="FormDialog">
-import {ref, ComputedRef, computed, reactive} from 'vue'
+import { ref, ComputedRef, computed, reactive } from 'vue'
 import ProFrom from '@/components/ProForm/index.vue'
-import {ElMessage} from 'element-plus'
+import { ElMessage } from 'element-plus'
 import FileUpload from '@/components/Upload/File.vue'
 
 // import mittBus from '@/utils/mittBus'
@@ -74,7 +74,8 @@ const _options: ComputedRef<ProForm.FormOptions> = computed(() => {
 
 const modelAddr = ref(null)
 const setModelAddr = res => {
-  console.log('modelAddr', res)
+  //console.log("setModelAddr res:")
+  console.log(res)
   modelAddr.value = res
 }
 
@@ -84,7 +85,7 @@ const handleSubmit = () => {
   const formEl = proFormRef.value?.proFormRef
   const formModel = proFormRef.value?.formModel
   formModel.modelAddress = modelAddr.value
-  console.log('formModel', formModel)
+  //console.log('formModel', formModel)
 
   butLoading.value = true
   if (!formEl) return
@@ -92,9 +93,9 @@ const handleSubmit = () => {
     if (valid) {
       let data = {}
       if (algorithmModelId.value) {
-        data = {...formModel, ...parameter.value.model, algorithmId: algorithmModelId.value}
+        data = { ...formModel, ...parameter.value.model, algorithmId: algorithmModelId.value }
       } else {
-        data = {...formModel, ...parameter.value.model}
+        data = { ...formModel, ...parameter.value.model }
       }
       parameter.value.api!(data).then(res => {
         if (res.code == 200) {
@@ -104,7 +105,7 @@ const handleSubmit = () => {
           dialogVisible.value = false
           parameter.value.getTableList && parameter.value.getTableList()
         } else {
-          console.log('message', res.message)
+          //console.log('message', res.message)
         }
       })
       butLoading.value = false
@@ -122,7 +123,7 @@ const handleSubmit = () => {
 // })
 // 取消按钮,重置表单,关闭弹框
 const handleCancel = () => {
-  console.log(parameter.value.model)
+  //console.log(parameter.value.model)
   const formEl = proFormRef.value?.proFormRef
   if (!formEl) return
   if (parameter.value.model?.url) {
@@ -139,7 +140,7 @@ let algorithmModelId = ref(0)
 // 接收父组件参数
 const openDialog = (params: FormParameterProps, algoModelId = null) => {
   algorithmModelId.value = algoModelId
-  parameter.value = {...parameter.value, ...params}
+  parameter.value = { ...parameter.value, ...params }
   _options.value.disabled = !parameter.value.isEdit
   butLoading.value = false
   dialogVisible.value = true
@@ -159,7 +160,6 @@ defineExpose({
   height: 200px;
   margin-top: 20px;
   border: 1px dashed #cccccc;
-
   :deep(.upload-file-uploader) {
     display: flex;
     align-items: center;

+ 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
 }
 

+ 1 - 0
src/components/ProTable/index.vue

@@ -213,6 +213,7 @@ const flatColumnsFunc = (columns: ColumnProps[], flatArr: ColumnProps[] = []) =>
 
 // 过滤需要搜索的配置项 && 排序
 const searchColumns = computed(() => {
+  //console.log(flatColumns.value)
   return flatColumns.value?.filter(item => item.search?.el || item.search?.render).sort((a, b) => a.search!.order! - b.search!.order!)
 })
 

+ 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>

+ 7 - 1
src/components/Upload/Img.vue

@@ -56,7 +56,13 @@
     <!--    </el-dialog>-->
     <!--    <el-image-viewer v-else-if="imgViewVisible" :url-list="['/api' + imageUrl]" @close="imgViewVisible = false" />-->
 
-    <el-image-viewer v-if="imgViewVisible" :url-list="['/api' + imageUrl]" @close="imgViewVisible = false" />
+    <el-image-viewer
+      v-if="imgViewVisible"
+      style="position: absolute; z-index: 9999"
+      :z-index="9999"
+      :url-list="['/api' + imageUrl]"
+      @close="imgViewVisible = false"
+    />
   </div>
 </template>
 

+ 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">

+ 12 - 2
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>
@@ -53,6 +54,15 @@ import {
   getModelApi
 } 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>()
@@ -216,8 +226,8 @@ const setItemsOptions = () => {
   ]
 }
 onMounted(() => {
-  getAlgorithmOptionApi().then(res => {
-    allAgloData.value = res.data
+  listTaskConfigurationApi().then(res => {
+    allAgloData.value = res.data.list
   })
 })
 </script>

+ 1 - 1
src/views/demo/AlgorithmConfigTrack/index.vue

@@ -62,7 +62,7 @@ import {
   exportAlgorithmConfigTrackApi,
   getAlgorithmConfigTrackApi
 } from '@/api/modules/demo/AlgorithmConfigTrack'
-import {enumsAlgorithmType, enumsSubSystem} from "@/views/demo/utils";
+import { enumsAlgorithmType, enumsSubSystem } from '@/views/demo/utils'
 
 // ProTable 实例
 const proTable = ref<ProTableInstance>()

+ 31 - 35
src/views/demo/DataSeq/index.vue

@@ -3,8 +3,7 @@
     <ProTable ref="proTable" :columns="columns" row-key="id" :request-api="listDataSeqApi">
       <!-- 表格 header 按钮 -->
       <template #tableHeader="scope">
-        <el-button type="primary" v-auth="['demo:DataSeq:add']" icon="CirclePlus" @click="openDialog(1, '数据集新增')"> 新增
-        </el-button>
+        <el-button type="primary" v-auth="['demo:DataSeq:add']" icon="CirclePlus" @click="openDialog(1, '数据集新增')"> 新增 </el-button>
         <!-- <el-button type="primary" v-auth="['demo:DataSeq:import']" icon="Upload" plain @click="batchAdd"> 导入 </el-button>
         <el-button type="primary" v-auth="['demo:DataSeq:export']" icon="Download" plain @click="downloadFile"> 导出 </el-button> -->
         <el-button
@@ -20,33 +19,31 @@
       </template>
       <!-- 表格操作 -->
       <template #operation="scope">
-        <el-button type="primary" link icon="View" v-auth="['demo:DataSeq:query']"
-                   @click="openDialog(3, '数据管理查看', scope.row)">
+        <el-button type="primary" link icon="View" v-auth="['demo:DataSeq:query']" @click="openDialog(3, '数据管理查看', scope.row)">
           查看
         </el-button>
         <el-button type="primary" link icon="View" v-auth="['demo:DataSeq:query']" @click="preview(scope.row)"> 预览</el-button>
         <!-- <el-button type="primary" link icon="EditPen" v-auth="['demo:DataSeq:edit']" @click="openDialog(2, '数据管理编辑', scope.row)">
           编辑
         </el-button> -->
-        <el-button type="primary" link icon="Delete" v-auth="['demo:DataSeq:remove']" @click="deleteDataSeq(scope.row)"> 删除
-        </el-button>
+        <el-button type="primary" link icon="Delete" v-auth="['demo:DataSeq:remove']" @click="deleteDataSeq(scope.row)"> 删除 </el-button>
       </template>
     </ProTable>
-    <FormDialog ref="formDialogRef"/>
+    <FormDialog ref="formDialogRef" />
     <!-- <ImportExcel ref="dialogRef" /> -->
-    <PreviewImages :visible="dialogVisible" :urls="imageUrls" @close="dialogVisible = false"/>
+    <PreviewImages :visible="dialogVisible" :urls="imageUrls" @close="dialogVisible = false" />
   </div>
 </template>
 
 <script setup lang="tsx" name="DataSeq">
-import {ref, reactive} from 'vue'
-import {useHandleData} from '@/hooks/useHandleData'
-import {useDownload} from '@/hooks/useDownload'
-import {ElMessageBox} from 'element-plus'
+import { ref, reactive } from 'vue'
+import { useHandleData } from '@/hooks/useHandleData'
+import { useDownload } from '@/hooks/useDownload'
+import { 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 {ProTableInstance, ColumnProps} from '@/components/ProTable/interface'
+import { ProTableInstance, ColumnProps } from '@/components/ProTable/interface'
 import {
   listDataSeqApi,
   delDataSeqApi,
@@ -58,12 +55,12 @@ import {
   getDataSeqApi,
   getAllImagesApi
 } from '@/api/modules/demo/DataSeq'
-import {enumsSubSystem} from '../utils'
-import PreviewImages from "@/views/demo/components/PreviewImages.vue";
+import { enumsSubSystem } from '../utils'
+import PreviewImages from '@/views/demo/components/PreviewImages.vue'
 const dialogVisible = ref(false)
 const imageUrls = ref([])
-const preview = async(row) => {
-  console.log("showImages")
+const preview = async row => {
+  console.log('showImages')
   const data: any = await getAllImagesApi(row.inputOssId)
   imageUrls.value = data.data
   dialogVisible.value = true
@@ -87,7 +84,7 @@ const batchDelete = async (ids: string[]) => {
 
 // 导出数据管理列表
 const downloadFile = async () => {
-  ElMessageBox.confirm('确认导出数据管理数据?', '温馨提示', {type: 'warning'}).then(() =>
+  ElMessageBox.confirm('确认导出数据管理数据?', '温馨提示', { type: 'warning' }).then(() =>
     useDownload(exportDataSeqApi, '数据管理列表', proTable.value?.searchParam)
   )
 }
@@ -107,7 +104,7 @@ const batchAdd = () => {
 const formDialogRef = ref<InstanceType<typeof FormDialog> | null>(null)
 // 打开弹框的功能
 const openDialog = async (type: number, title: string, row?: any) => {
-  let res = {data: {}}
+  let res = { data: {} }
   if (row?.id) {
     res = await getDataSeqApi(row?.id || null)
   }
@@ -127,8 +124,8 @@ const openDialog = async (type: number, title: string, row?: any) => {
 
 // 表格配置项
 const columns = reactive<ColumnProps<any>[]>([
-  {type: 'selection', fixed: 'left', width: 70},
-  {prop: 'id', label: 'id'},
+  { type: 'selection', fixed: 'left', width: 70 },
+  { prop: 'id', label: 'id' },
   {
     prop: 'name',
     label: '名称',
@@ -211,7 +208,7 @@ const columns = reactive<ColumnProps<any>[]>([
       el: 'input'
     }
   },
-  {prop: 'operation', label: '操作', width: 230, fixed: 'right'}
+  { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
 ])
 // 表单配置项
 let itemsOptions: ProForm.ItemsOptions[] = []
@@ -220,7 +217,7 @@ const setItemsOptions = () => {
     {
       label: '名称',
       prop: 'name',
-      rules: [{required: true, message: '名称不能为空', trigger: 'blur'}],
+      rules: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
       compOptions: {
         placeholder: '请输入名称'
       }
@@ -228,7 +225,7 @@ const setItemsOptions = () => {
     {
       label: '分系统',
       prop: 'subsystem',
-      rules: [{required: true, message: '分系统不能为空', trigger: 'blur'}],
+      rules: [{ required: true, message: '分系统不能为空', trigger: 'blur' }],
       compOptions: {
         elTagName: 'select',
         enum: enumsSubSystem,
@@ -238,7 +235,7 @@ const setItemsOptions = () => {
     {
       label: '批次号',
       prop: 'batchNum',
-      rules: [{required: true, message: '批次号不能为空', trigger: 'blur'}],
+      rules: [{ required: true, message: '批次号不能为空', trigger: 'blur' }],
       compOptions: {
         placeholder: '请输入批次号'
       }
@@ -246,7 +243,7 @@ const setItemsOptions = () => {
     {
       label: '上传文件',
       prop: 'inputOssId',
-      rules: [{required: true, message: '数据集文件不能为空', trigger: 'blur'}],
+      rules: [{ required: true, message: '数据集文件不能为空', trigger: 'blur' }],
       compOptions: {
         elTagName: 'file-upload',
         fileSize: 4096,
@@ -265,7 +262,7 @@ const setItemsOptions = () => {
     {
       label: '目标类型',
       prop: 'objectType',
-      rules: [{required: false, message: '目标类型不能为空', trigger: 'blur'}],
+      rules: [{ required: false, message: '目标类型不能为空', trigger: 'blur' }],
       compOptions: {
         placeholder: '请输入目标类型'
       }
@@ -273,7 +270,7 @@ const setItemsOptions = () => {
     {
       label: '目标子类型',
       prop: 'objectSubtype',
-      rules: [{required: false, message: '目标子类型不能为空', trigger: 'blur'}],
+      rules: [{ required: false, message: '目标子类型不能为空', trigger: 'blur' }],
       compOptions: {
         placeholder: '请输入目标子类型'
       }
@@ -281,7 +278,7 @@ const setItemsOptions = () => {
     {
       label: '场景',
       prop: 'scene',
-      rules: [{required: false, message: '场景不能为空', trigger: 'blur'}],
+      rules: [{ required: false, message: '场景不能为空', trigger: 'blur' }],
       compOptions: {
         placeholder: '请输入场景'
       }
@@ -289,7 +286,7 @@ const setItemsOptions = () => {
     {
       label: '数据源',
       prop: 'dataSource',
-      rules: [{required: false, message: '数据源不能为空', trigger: 'blur'}],
+      rules: [{ required: false, message: '数据源不能为空', trigger: 'blur' }],
       compOptions: {
         placeholder: '请输入数据源'
       }
@@ -297,7 +294,7 @@ const setItemsOptions = () => {
     {
       label: '采集时间',
       prop: 'gatherTime',
-      rules: [{required: false, message: '采集时间不能为空', trigger: 'change'}],
+      rules: [{ required: false, message: '采集时间不能为空', trigger: 'change' }],
       compOptions: {
         elTagName: 'date-picker',
         type: 'date',
@@ -307,7 +304,7 @@ const setItemsOptions = () => {
     {
       label: '采集地点',
       prop: 'gatherSpot',
-      rules: [{required: false, message: '采集地点不能为空', trigger: 'blur'}],
+      rules: [{ required: false, message: '采集地点不能为空', trigger: 'blur' }],
       compOptions: {
         placeholder: '请输入采集地点'
       }
@@ -333,7 +330,7 @@ const setItemsOptions = () => {
     {
       label: '备注',
       prop: 'remarks',
-      rules: [{required: false, message: '备注不能为空', trigger: 'blur'}],
+      rules: [{ required: false, message: '备注不能为空', trigger: 'blur' }],
       compOptions: {
         placeholder: '请输入备注'
       }
@@ -342,5 +339,4 @@ const setItemsOptions = () => {
 }
 </script>
 
-<style lang="scss" scoped>
-</style>
+<style lang="scss" scoped></style>

+ 34 - 24
src/views/demo/components/img-maker.vue

@@ -13,7 +13,7 @@
       <el-button plain type="primary" class="shape-border" @click="changeZoom(0.9)">缩小图片</el-button>
       <!-- <el-button plain type="primary" class="shape-border" @click="drawPolygon('polygon')">多边形</el-button> -->
     </div>
-    <canvas id="canvas" :width="cWidth" :height="cHeight"></canvas>
+    <canvas :id="props.canvasId" :width="cWidth" :height="cHeight"></canvas>
   </div>
 </template>
 <script lang="ts" setup>
@@ -56,6 +56,10 @@ const props = defineProps({
   isPicOnly: {
     type: Boolean,
     default: false
+  },
+  canvasId: {
+    type: String,
+    default: 'canvas'
   }
 })
 const state = reactive({
@@ -132,28 +136,31 @@ const changeZoom = multi => {
 const loadInit = () => {
   drawTypeChange('rectangle')
   state.color = props.classDef && props.classDef.color ? props.classDef.color : '#E34F51'
-  document.addEventListener('keydown', function (e) {
-    if (e.key === 'w' || e.key === 'W') {
-      selectLastObject()
-      return
-    }
-    if (state.activeTarget) {
-      if (e.key === 'r' || e.key === 'R') {
-        // 旋转矩形对象
-        state.activeTarget.rotate(state.activeTarget.angle + 5)
-        state.canvas.renderAll()
-      } else if (e.key === 'e' || e.key === 'E') {
-        // 旋转矩形对象
-        state.activeTarget.rotate(state.activeTarget.angle - 5)
-        state.canvas.renderAll()
+  if (!props.isPicOnly) {
+    document.addEventListener('keydown', function (e) {
+      if (e.key === 'w' || e.key === 'W') {
+        selectLastObject()
+        return
       }
-    }
-  })
+      if (state.activeTarget) {
+        if (e.key === 'r' || e.key === 'R') {
+          // 旋转矩形对象
+          state.activeTarget.rotate(state.activeTarget.angle + 5)
+          state.canvas.renderAll()
+        } else if (e.key === 'e' || e.key === 'E') {
+          // 旋转矩形对象
+          state.activeTarget.rotate(state.activeTarget.angle - 5)
+          state.canvas.renderAll()
+        }
+      }
+    })
+  }
+
   if (props.src == '') {
     return
   }
   state.loading = true
-  state.canvas = new fabric.Canvas('canvas', {})
+  state.canvas = new fabric.Canvas(props.canvasId, {})
   state.canvas.selectionColor = 'rgba(0,0,0,0.05)'
   state.canvas.on('mouse:down', mousedown)
   state.canvas.on('mouse:move', mousemove)
@@ -162,11 +169,11 @@ const loadInit = () => {
   let imgElement = new Image()
   imgElement.src = props.src
   imgElement.onload = () => {
-    console.log(imgElement.height, imgElement.width)
+    // console.log(imgElement.height, imgElement.width)
     // 区域大小/图片原始大小 缩放比例
     state.radio =
       props.cWidth / imgElement.width > props.cHeight / imgElement.height ? props.cHeight / imgElement.height : props.cWidth / imgElement.width
-    console.log('state.radio', state.radio)
+    // console.log('state.radio', state.radio)
 
     // 屏幕分辨率/图片原始大小
     state.realRadioX = props.width / imgElement.width
@@ -186,8 +193,8 @@ const loadInit = () => {
       scaleY: state.radio
     })
     state.canvas.add(imgInstance)
-    console.log('props', props)
-    console.log('state', state)
+    // console.log('props', props)
+    // console.log('state', state)
     if (props.jsonData && props.jsonData.length > 0) {
       for (let i = 0; i < props.jsonData.length; i++) {
         let config = props.jsonData[i]
@@ -220,8 +227,8 @@ const loadInit = () => {
     }
     state.radio = state.canvas.getZoom()
     state.loading = false
-    console.log(state.canvas.getObjects())
-    console.log(props.isPicOnly)
+    // console.log('objects', state.canvas.getObjects())
+    // console.log(props.isPicOnly)
     // console.log(state.realRadioX)
     // console.log(state.realRadioY)
   }
@@ -322,6 +329,9 @@ const drawTypeChange = e => {
 }
 // 鼠标按下时触发
 const mousedown = e => {
+  if (props.isPicOnly) {
+    return
+  }
   if (state.dragMode) {
     state.isDragging = true
     state.lastPosX = e.e.clientX - state.canvas.getElement().offsetLeft

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

@@ -1,8 +1,10 @@
 <template>
   <div class="table-box">
+    <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">
-        <uploadImg :is-show-data="true" :disabled="true" :image-url="scope.row.url" />
+        <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>
       <!-- 表格 header 按钮 -->
@@ -10,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']"
@@ -75,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'
@@ -85,6 +90,13 @@ onMounted(() => {
   // })
 })
 
+const imageUrl = ref('')
+const imgViewVisible = ref(false)
+const loadImg = url => {
+  imageUrl.value = url
+  imgViewVisible.value = true
+}
+
 const imgDetect = ref()
 const state = reactive({
   area: '' as string,
@@ -349,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) => {

+ 528 - 0
src/views/demo/dataAugmentation/index.vue

@@ -0,0 +1,528 @@
+<template>
+  <div class="table-box">
+    <ProTable ref="proTable" :columns="columns" row-key="id" :request-api="listDataAugmentationApi">
+      <!-- 表格 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="danger"
+          v-auth="['demo:DataAugmentation:remove']"
+          icon="Delete"
+          plain
+          :disabled="!scope.isSelected"
+          @click="batchDelete(scope.selectedListIds)"
+        >
+          批量删除
+        </el-button>
+      </template>
+      <!-- 表格操作 -->
+      <template #operation="scope">
+        <el-button
+          type="primary"
+          link
+          icon="View"
+          @click="startDataAugmentation(scope.row)"
+          v-if="scope.row.status == '0' || scope.row.status == '3' || scope.row.status == '4'"
+        >
+          开始
+        </el-button>
+        <el-popconfirm title="确定终止此任务吗?" @confirm="stopDataAugmentation(scope.row)" v-if="scope.row.status == '1'">
+          <template #reference>
+            <el-button type="primary" link icon="View"> 终止 </el-button>
+          </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>
+        <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>
+      </template>
+    </ProTable>
+    <DataAugmentationFormDialog ref="formDialogRef" />
+    <ImportExcel ref="dialogRef" />
+    <el-dialog v-model="dialogVisible" :title="dialogTitle" width="80%">
+      <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>
+
+<script setup lang="tsx" name="DataAugmentation">
+import { ref, reactive, onMounted } 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 DataAugmentationFormDialog from '@/components/DataAugmentationFormDialog/index.vue'
+import { ProTableInstance, ColumnProps, EnumProps } from '@/components/ProTable/interface'
+import {
+  listDataAugmentationApi,
+  delDataAugmentationApi,
+  addDataAugmentationApi,
+  updateDataAugmentationApi,
+  importTemplateApi,
+  importDataAugmentationDataApi,
+  exportDataAugmentationApi,
+  getDataAugmentationApi,
+  startDataAugmentationApi,
+  stopDataAugmentationApi,
+  getCompareImageApi,
+  getCompareImageCountApi,
+  getDialogApi
+} from '@/api/modules/demo/dataAugmentation'
+import { listDataApi } from '@/api/modules/system/dictData'
+import { S } from 'vite/dist/node/types.d-aGj9QkWt'
+import { servicesVersion } from 'typescript'
+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 cacheImages = ref({})
+const dialogTitle = ref('')
+const fileCount = ref(0)
+const imageFps = ref(0)
+const intervalChangeFps: any = ref()
+const taskType = ref([])
+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: '',
+    dictType: 'biz_data_augmentation',
+    dictLabel: '任务类型',
+    pageNum: 0,
+    pageSize: 1000
+  })
+  if (res.data.list.length != 0) {
+    taskType.value = res.data.list.map(item => ({
+      label: item.dictValue,
+      value: item.dictValue
+    }))
+    res.data.list.forEach(item => {
+      taskTypeEnums.push({
+        label: item.dictValue,
+        value: item.dictValue,
+        disabled: false,
+        tagType: 'default'
+      })
+    })
+    for (let i = 0; i < taskType.value.length; i++) {
+      let dictValue = taskType.value[i].value
+      const res: any = await listDataApi({
+        dictName: '',
+        dictType: 'biz_data_augmentation',
+        dictLabel: dictValue + '超参配置',
+        pageNum: 0,
+        pageSize: 1000
+      })
+      if (res.data.list.length != 0) {
+        //console.log(res.data.list[0].dictValue)
+        let obj = {}
+        obj[dictValue] = res.data.list[0].dictValue
+        hyperparameterConfiguration.push(obj)
+      } else {
+        ElMessage.error('${dictValue}未在数据字典中设置超参!')
+      }
+    }
+  } else {
+    ElMessage.error('task_type为空,请在数据字典中设置具体的任务类型!')
+  }
+
+  // console.log(taskType.value)
+}
+onMounted(() => {
+  getTaskType()
+})
+
+const startDataAugmentation = async (params: any) => {
+  const res = await startDataAugmentationApi(params.id)
+  if (res.code === 200) {
+    ElMessage.success('任务已经开始,请等待')
+  } else {
+    ElMessage.error('任务开始失败,请检查!')
+  }
+  proTable.value?.getTableList()
+}
+
+const stopDataAugmentation = async (params: any) => {
+  const res = await stopDataAugmentationApi(params.id)
+  if (res.code === 200) {
+    ElMessage.success('任务终止成功')
+  } else {
+    ElMessage.error('任务终止失败!')
+  }
+  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
+  cacheImages.value[imageIdx].origin = res.origin
+  cacheImages.value[imageIdx].stable = res.stable
+}
+
+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
+    outFileCount.value = resCount.data.outFileCount
+  } else {
+    ElMessage.error('获取图片对比数量失败')
+    return
+  }
+  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 - 1]) {
+      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])
+  dialogTitle.value = '预览: 第1个样本 共' + fileCount.value + '个样本'
+  // next_picture()
+}
+const next_picture = async () => {
+  if (imageIdx.value < fileCount.value - 1) {
+    if (!cacheImages.value[imageIdx.value + 1]) {
+      await loadImageData(taskId.value, imageIdx.value + 1)
+    }
+    imageIdx.value = imageIdx.value + 1
+  }
+  dialogTitle.value = '预览: 第' + (imageIdx.value + 1) + '个样本 共' + fileCount.value + '个样本'
+}
+const pre_picture = async () => {
+  if (imageIdx.value > 0) {
+    if (!cacheImages.value[imageIdx.value - 1]) {
+      await loadImageData(taskId.value, imageIdx.value - 1)
+    }
+    imageIdx.value = imageIdx.value - 1
+  }
+  dialogTitle.value = '预览: 第' + (imageIdx.value + 1) + '个样本 共' + fileCount.value + '个样本'
+}
+
+// ProTable 实例
+const proTable = ref<ProTableInstance>()
+
+// 删除视频去抖动信息
+const deleteDataAugmentation = async (params: any) => {
+  await useHandleData(delDataAugmentationApi, params.id, '删除任务【' + params.name + '】?')
+  proTable.value?.getTableList()
+}
+
+// 批量删除视频去抖动信息
+const batchDelete = async (ids: string[]) => {
+  await useHandleData(delDataAugmentationApi, ids, '删除所选任务?')
+  proTable.value?.clearSelection()
+  proTable.value?.getTableList()
+}
+
+// 导出视频去抖动列表
+const downloadFile = async () => {
+  ElMessageBox.confirm('确认导出任务数据?', '温馨提示', { type: 'warning' }).then(() =>
+    useDownload(exportDataAugmentationApi, '任务列表', proTable.value?.searchParam)
+  )
+}
+
+// 批量添加视频去抖动
+const dialogRef = ref<InstanceType<typeof ImportExcel> | null>(null)
+const batchAdd = () => {
+  const params = {
+    title: '视频去抖动',
+    tempApi: importTemplateApi,
+    importApi: importDataAugmentationDataApi,
+    getTableList: proTable.value?.getTableList
+  }
+  dialogRef.value?.acceptParams(params)
+}
+
+const formDialogRef = ref<InstanceType<typeof DataAugmentationFormDialog> | null>(null)
+// 打开弹框的功能
+const openDialog = async (type: number, title: string, row?: any) => {
+  // hyperparameter.value = ''
+  let res = { data: {} }
+  if (row?.id) {
+    res = await getDataAugmentationApi(row?.id || null)
+    // hyperparameter.value = res.data?.hyperparameterConfiguration
+  }
+  // console.log(itemsOptions[1].compOptions?.value)
+  // 重置表单
+  // setItemsOptions()
+  const params = {
+    title,
+    width: 580,
+    isEdit: type !== 3,
+    itemsOptions: itemsOptions,
+    model: type == 1 ? model : res.data,
+    api: type == 1 ? addDataAugmentationApi : updateDataAugmentationApi,
+    getTableList: proTable.value?.getTableList
+  }
+  formDialogRef.value?.openDialog(params)
+}
+
+const statusEnums: EnumProps[] = [
+  {
+    label: '未开始',
+    value: '0',
+    disabled: false,
+    tagType: 'default'
+  },
+  {
+    label: '进行中',
+    value: '1',
+    disabled: false,
+    tagType: 'primary'
+  },
+  {
+    label: '完成',
+    value: '2',
+    disabled: false,
+    tagType: 'success'
+  },
+  {
+    label: '失败',
+    value: '3',
+    disabled: false,
+    tagType: 'danger'
+  },
+  {
+    label: '已中断',
+    value: '4',
+    disabled: false,
+    tagType: 'default'
+  }
+]
+
+// 表格配置项
+const columns = reactive<ColumnProps<any>[]>([
+  { type: 'selection', fixed: 'left', width: 70 },
+  { prop: 'id', label: '主键ID', width: 180 },
+  {
+    prop: 'name',
+    label: '任务名称',
+    search: {
+      el: 'input'
+    },
+    width: 150
+  },
+  {
+    prop: 'taskType',
+    label: '任务类型',
+    search: {
+      el: 'select'
+    },
+    width: 100,
+    tag: true,
+    enum: taskTypeEnums
+  },
+  {
+    prop: 'status',
+    label: '任务状态',
+    search: {
+      el: 'select'
+    },
+    width: 100,
+    tag: true,
+    enum: statusEnums
+  },
+  {
+    prop: 'startTime',
+    label: '开始时间',
+    width: 180
+  },
+  {
+    prop: 'endTime',
+    label: '结束时间',
+    width: 180
+  },
+  {
+    prop: 'costSecond',
+    label: '耗时',
+    search: {
+      el: 'input'
+    },
+    width: 80
+  },
+  {
+    prop: 'log',
+    label: '日志',
+    width: 120
+  },
+
+  {
+    prop: 'algorithmPath',
+    label: '日志路径',
+    width: 120
+  },
+  {
+    prop: 'hyperparameterConfiguration',
+    label: '超参配置',
+    width: 120
+  },
+  {
+    prop: 'remarks',
+    label: '备注',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'operation',
+    label: '操作',
+    width: 230,
+    fixed: 'right'
+  }
+])
+// 表单配置项
+let itemsOptions: ProForm.ItemsOptions[] = [
+  {
+    label: '任务名称',
+    prop: 'name',
+    rules: [{ required: true, message: '任务名称不能为空', trigger: 'blur' }],
+    compOptions: {
+      placeholder: '请输入任务名称'
+    }
+  },
+  {
+    label: '任务类型',
+    prop: 'taskType',
+    rules: [{ required: true, message: '任务类型不能为空', trigger: 'change' }],
+    compOptions: {
+      elTagName: 'select', // 指定使用 el-select 组件
+      placeholder: '请选择任务类型',
+      enum: taskType,
+      onChange: (value: string) => {
+        model.value['taskType'] = value
+        hyperparameterConfiguration.forEach(obj => {
+          if (value in obj) {
+            // console.log(obj[value])
+            addParams(obj[value])
+            openDialog(1, '任务新增')
+          }
+        })
+      }
+    }
+  },
+  {
+    label: '图片集压缩包',
+    prop: 'inputOssId',
+    rules: [{ required: true, message: '数据压缩包不能为空', trigger: 'change' }],
+    compOptions: {
+      elTagName: 'file-upload',
+      fileSize: 4096,
+      fileType: ['zip'],
+      placeholder: '请上传图片集压缩包'
+    }
+  },
+  {
+    label: '备注',
+    prop: 'remarks',
+    rules: [
+      {
+        required: false,
+        trigger: 'blur'
+      }
+    ],
+    compOptions: {
+      placeholder: '请输入备注'
+    }
+  }
+]
+const model = ref({})
+const setItemsOptions = () => {
+  if (itemsOptions.length > 4) {
+    itemsOptions.splice(4) // 如果里面有新增参数,删除,重新添加
+  }
+}
+const addParams = params => {
+  setItemsOptions()
+  if (params == 'null') {
+    return
+  }
+  let validJsonString = params.replace(/'/g, '"')
+  try {
+    const obj: { [key: string]: number } = JSON.parse(validJsonString)
+    Object.keys(obj).forEach(key => {
+      // model.value[key] = obj[key]
+      itemsOptions.push({
+        label: key,
+        prop: key,
+        rules: [{ required: true, trigger: 'blur' }],
+        compOptions: {
+          type: 'input',
+          clearable: true,
+          placeholder: obj[key]
+        }
+      })
+    })
+  } catch (error) {
+    console.error('解析 JSON 字符串时出错:', error)
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.image-dialog {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  .el-image {
+    margin-right: 20px;
+    margin-bottom: 20px;
+  }
+}
+.image-dialog-btn {
+  display: flex;
+  justify-content: center;
+  margin-top: 20px;
+}
+</style>

+ 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>

+ 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>

+ 1 - 1
src/views/system/dict/data.vue

@@ -101,7 +101,7 @@ const openDialog = async (type: number, title: string, row?: any) => {
     width: 500,
     isEdit: type !== 3,
     itemsOptions: itemsOptions,
-    model: type == 1 ? { dictType: defaultDictType.value, version: 0 } : { ...res.data, version: 0 },
+    model: type == 1 ? { dictType: defaultDictType.value, version: 0 } : res.data,
     api: type == 1 ? addDataApi : updateDataApi,
     getTableList: proTable.value?.getTableList
   }

+ 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]
     }
   })
 }

+ 139 - 88
src/views/task/bizProcess/index.vue

@@ -3,43 +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" icon="View" @click="showCompareResult"> 对比结果 </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-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>
-        <el-button v-else type="primary" link icon="Refresh" @click="startTask(scope.row)"> 开始训练 </el-button>
+        <el-button type="primary" link icon="document" v-auth="['identification:identificationSubtaskDetails:query']" @click="viewLog(scope.row)">
+          查看日志
+        </el-button>
 
         <el-button type="primary" link icon="Refresh" @click="exportData(scope.row)"> 导出结果 </el-button>
 
@@ -47,27 +56,32 @@
         <!--          编辑-->
         <!--        </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" />
     <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>
+      <el-container v-for="(item, index) in executedTimeData.data" :key="index">
+        <el-container style="display: flex; flex-direction: column">
+          <h4 v-if="index === 0" style="color: greenyellow">单幅图像最短运行时间</h4>
+          <h4 v-else-if="index === 1" style="color: greenyellow">单幅图像最长运行时间</h4>
+          <h4 v-else-if="index === 2" style="color: greenyellow">单幅图像平均运行时间</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>
+            <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-container>
+        <div v-if="executedTimeData.isVal">
+          <h4 style="color: greenyellow">虚警率</h4>
+          <h5>{{ executedTimeData.falseAlarmRate }} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</h5>
+          <h4 style="color: greenyellow">漏检率</h4>
+          <h5>{{ executedTimeData.omitDetectRate }}</h5>
+        </div>
+      </el-container>
     </el-dialog>
 
     <el-dialog v-model="dialogVisible" title="日志" width="70%">
@@ -168,10 +182,10 @@
       </el-card>
     </el-dialog>
 
-    <el-dialog v-model="compareDialogVisible" title="执行结果对比">
+    <el-dialog v-model="compareDialogVisible" title="验证指标对比">
       <!--      style="width: 70vw"-->
       <el-container style="display: flex; flex-direction: row">
-        <el-container v-for="(item, index) in listData" :key="index" style="display: flex; flex-direction: column">
+        <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">
@@ -212,16 +226,25 @@
           <!--          <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="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.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
-              style=" width: 200px;height: 200px"
+              :canvas-id="_item.name + '_' + _index"
+              style="width: 200px; height: 200px"
               ref="imgMaker"
               v-if="_item.imgUrl"
               :is-pic-only="true"
               :src="_item.imgUrl"
-              :area="area"
               :width="200"
               :height="200"
               :c-width="200"
@@ -229,7 +252,7 @@
               :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-image v-if="_item.resUrl" :src="_item.resUrl" style="width: 200px; height: 200px"></el-image>
           </el-container>
         </el-container>
       </el-container>
@@ -270,24 +293,22 @@ const PATH_PREFIX = 'api/profile/task'
 let resultDialogVisible = ref(false)
 let refSelectData = ref(reactive({}))
 const reRunTask = row => {
-  http.post<any>('/identification/identificationSubtaskDetails/execute', { taskId: row.id }, { loading: false })
-    .then(res => {
-      if (res.code !== 200) {
-        ElMessage.error(res.msg)
-      } else {
-        ElMessage.success('启动成功')
-      }
-    })
+  http.post<any>('/identification/identificationSubtaskDetails/execute', { taskId: row.id }, { loading: false }).then(res => {
+    if (res.code !== 200) {
+      ElMessage.error(res.msg)
+    } else {
+      ElMessage.success('启动成功')
+    }
+  })
 }
 const startTask = row => {
-  http.post<any>('/identification/identificationSubtaskDetails/startTask', { taskId: row.id }, { loading: false })
-    .then(res => {
-      if (res.code !== 200) {
-        ElMessage.error(res.msg)
-      } else {
-        ElMessage.success('启动成功')
-      }
-    })
+  http.post<any>('/identification/identificationSubtaskDetails/startTask', { taskId: row.id }, { loading: false }).then(res => {
+    if (res.code !== 200) {
+      ElMessage.error(res.msg)
+    } else {
+      ElMessage.success('启动成功')
+    }
+  })
 }
 const typeDefs = ref(reactive([]))
 
@@ -301,29 +322,27 @@ const exportData = row => {
 }
 
 let executedTimeVisible = ref(false)
-let executedTimeData = ref([])
+let executedTimeData = ref({})
 const showExecutedTime = row => {
-  // row.remarks = '[\n' +
-  //   '{\n' +
-  //   '"preprocess": 1,\n' +
-  //   '"inference": 2,\n' +
-  //   '"postprocess": 3\n' +
-  //   '},\n' +
-  //   '{\n' +
-  //   '"preprocess": 11,\n' +
-  //   '"inference": 22,\n' +
-  //   '"postprocess": 33\n' +
-  //   '},\n' +
-  //   '{\n' +
-  //   '"preprocess": 111,\n' +
-  //   '"inference": 233,\n' +
-  //   '"postprocess": 333\n' +
-  //   '}\n' +
-  //   ']'
   try {
-    executedTimeData.value = JSON.parse(row.remarks)
+    console.log('row', row)
+    executedTimeData.value.isVal = row.name.includes('验证')
+    http.get('/profile/task' + row.resultPath + '/time.json').then(res => {
+      executedTimeData.value.data = []
+      executedTimeData.value.data.push(res[0].min)
+      executedTimeData.value.data.push(res[0].max)
+      executedTimeData.value.data.push(res[0].average)
+      if (executedTimeData.value.isVal) {
+        setTimeout(() => {
+          http.get('/profile/task' + row.resultPath + '/matrics.json').then(res => {
+            executedTimeData.value.omitDetectRate = res[1].omit_detect_rate
+            executedTimeData.value.falseAlarmRate = res[0].false_alarm_rate
+          })
+        }, 550)
+      }
+    })
   } catch (e) {
-    ElMessage.error("解析JSON错误,请检查任务是否已完成")
+    ElMessage.error('解析JSON错误,请检查任务是否已完成')
     return
   }
   executedTimeVisible.value = true
@@ -352,7 +371,7 @@ const showValResult = async isVal => {
           jList[jList.length - 1] = 'txt'
           let obj = {
             name: res.data[j],
-            srcUrl: 'api/profile/task' + listData.value[i].preprocessPath + '/' + res.data[j]
+            srcUrl: 'api/profile/task' + listData.value[i].preprocessPath + (isVal ? '/images/' : '/') + res.data[j]
             // imgUrl: 'api/profile/task' + listData.value[i].preprocessPath + '/images/' + res.data[j],
             // labelUrl: 'api/profile/task' + listData.value[i].preprocessPath + '/labels/' + jList.join('.')
           }
@@ -371,27 +390,53 @@ const showValResult = async isVal => {
         subPath: 'images'
       })
       console.log(res.data)
+      if (isVal) {
+        await loadVerifyResult(listData.value[i].name, '/profile/task' + listData.value[i].preprocessPath + '/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].resultPath + '/' + res.data[j],
-          name: listData.value[i].name
+          name: listData.value[i].name,
+          picName: res.data[j],
+          color: verifyResult.value[res.data[j]] ? '#00ff00' : '#ff0000'
         })
       }
     }
   }
-  console.log(imgDataList)
+  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.split('\r\n')
-    console.log(arr)
+    // 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)
@@ -407,6 +452,7 @@ const setDetail = obj => {
       const ww = 200
       const hh = 200
       obj.jsonData.push({
+        subArr: subArr,
         pathString:
           'M ' +
           subArr[1] * ww +
@@ -437,10 +483,15 @@ const setDetail = obj => {
 }
 
 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)
@@ -743,7 +794,7 @@ const columns = reactive<ColumnProps<any>[]>([
     label: '耗时(ms)'
   },
   {
-    prop: 'log',
+    prop: 'remarks',
     label: '日志'
   },
   { prop: 'operation', label: '操作', width: 230, fixed: 'right' }

+ 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)">

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 426 - 0
vite.config.ts.timestamp-1728903656862-499f9b40dc949.mjs


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 426 - 0
vite.config.ts.timestamp-1729079247820-0269fb76961da.mjs


+ 134 - 122
yarn.lock

@@ -1599,85 +1599,85 @@
     estree-walker "^2.0.2"
     picomatch "^2.3.1"
 
-"@rollup/rollup-android-arm-eabi@4.18.0":
-  version "4.18.0"
-  resolved "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz#bbd0e616b2078cd2d68afc9824d1fadb2f2ffd27"
-  integrity sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==
-
-"@rollup/rollup-android-arm64@4.18.0":
-  version "4.18.0"
-  resolved "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz#97255ef6384c5f73f4800c0de91f5f6518e21203"
-  integrity sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==
-
-"@rollup/rollup-darwin-arm64@4.18.0":
-  version "4.18.0"
-  resolved "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz#b6dd74e117510dfe94541646067b0545b42ff096"
-  integrity sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==
-
-"@rollup/rollup-darwin-x64@4.18.0":
-  version "4.18.0"
-  resolved "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz#e07d76de1cec987673e7f3d48ccb8e106d42c05c"
-  integrity sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==
-
-"@rollup/rollup-linux-arm-gnueabihf@4.18.0":
-  version "4.18.0"
-  resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz#9f1a6d218b560c9d75185af4b8bb42f9f24736b8"
-  integrity sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==
-
-"@rollup/rollup-linux-arm-musleabihf@4.18.0":
-  version "4.18.0"
-  resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz#53618b92e6ffb642c7b620e6e528446511330549"
-  integrity sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==
-
-"@rollup/rollup-linux-arm64-gnu@4.18.0":
-  version "4.18.0"
-  resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz#99a7ba5e719d4f053761a698f7b52291cefba577"
-  integrity sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==
-
-"@rollup/rollup-linux-arm64-musl@4.18.0":
-  version "4.18.0"
-  resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz#f53db99a45d9bc00ce94db8a35efa7c3c144a58c"
-  integrity sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==
-
-"@rollup/rollup-linux-powerpc64le-gnu@4.18.0":
-  version "4.18.0"
-  resolved "https://registry.npmmirror.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz#cbb0837408fe081ce3435cf3730e090febafc9bf"
-  integrity sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==
-
-"@rollup/rollup-linux-riscv64-gnu@4.18.0":
-  version "4.18.0"
-  resolved "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz#8ed09c1d1262ada4c38d791a28ae0fea28b80cc9"
-  integrity sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==
-
-"@rollup/rollup-linux-s390x-gnu@4.18.0":
-  version "4.18.0"
-  resolved "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz#938138d3c8e0c96f022252a28441dcfb17afd7ec"
-  integrity sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==
-
-"@rollup/rollup-linux-x64-gnu@4.18.0":
-  version "4.18.0"
-  resolved "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz#1a7481137a54740bee1ded4ae5752450f155d942"
-  integrity sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==
-
-"@rollup/rollup-linux-x64-musl@4.18.0":
-  version "4.18.0"
-  resolved "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz#f1186afc601ac4f4fc25fac4ca15ecbee3a1874d"
-  integrity sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==
-
-"@rollup/rollup-win32-arm64-msvc@4.18.0":
-  version "4.18.0"
-  resolved "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz#ed6603e93636a96203c6915be4117245c1bd2daf"
-  integrity sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==
-
-"@rollup/rollup-win32-ia32-msvc@4.18.0":
-  version "4.18.0"
-  resolved "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz#14e0b404b1c25ebe6157a15edb9c46959ba74c54"
-  integrity sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==
-
-"@rollup/rollup-win32-x64-msvc@4.18.0":
-  version "4.18.0"
-  resolved "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz#5d694d345ce36b6ecf657349e03eb87297e68da4"
-  integrity sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==
+"@rollup/rollup-android-arm-eabi@4.24.0":
+  version "4.24.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz#1661ff5ea9beb362795304cb916049aba7ac9c54"
+  integrity sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==
+
+"@rollup/rollup-android-arm64@4.24.0":
+  version "4.24.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz#2ffaa91f1b55a0082b8a722525741aadcbd3971e"
+  integrity sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==
+
+"@rollup/rollup-darwin-arm64@4.24.0":
+  version "4.24.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz#627007221b24b8cc3063703eee0b9177edf49c1f"
+  integrity sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==
+
+"@rollup/rollup-darwin-x64@4.24.0":
+  version "4.24.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz#0605506142b9e796c370d59c5984ae95b9758724"
+  integrity sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==
+
+"@rollup/rollup-linux-arm-gnueabihf@4.24.0":
+  version "4.24.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz#62dfd196d4b10c0c2db833897164d2d319ee0cbb"
+  integrity sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==
+
+"@rollup/rollup-linux-arm-musleabihf@4.24.0":
+  version "4.24.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz#53ce72aeb982f1f34b58b380baafaf6a240fddb3"
+  integrity sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==
+
+"@rollup/rollup-linux-arm64-gnu@4.24.0":
+  version "4.24.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz#1632990f62a75c74f43e4b14ab3597d7ed416496"
+  integrity sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==
+
+"@rollup/rollup-linux-arm64-musl@4.24.0":
+  version "4.24.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz#8c03a996efb41e257b414b2e0560b7a21f2d9065"
+  integrity sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==
+
+"@rollup/rollup-linux-powerpc64le-gnu@4.24.0":
+  version "4.24.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz#5b98729628d5bcc8f7f37b58b04d6845f85c7b5d"
+  integrity sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==
+
+"@rollup/rollup-linux-riscv64-gnu@4.24.0":
+  version "4.24.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz#48e42e41f4cabf3573cfefcb448599c512e22983"
+  integrity sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==
+
+"@rollup/rollup-linux-s390x-gnu@4.24.0":
+  version "4.24.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz#e0b4f9a966872cb7d3e21b9e412a4b7efd7f0b58"
+  integrity sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==
+
+"@rollup/rollup-linux-x64-gnu@4.24.0":
+  version "4.24.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz#78144741993100f47bd3da72fce215e077ae036b"
+  integrity sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==
+
+"@rollup/rollup-linux-x64-musl@4.24.0":
+  version "4.24.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz#d9fe32971883cd1bd858336bd33a1c3ca6146127"
+  integrity sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==
+
+"@rollup/rollup-win32-arm64-msvc@4.24.0":
+  version "4.24.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz#71fa3ea369316db703a909c790743972e98afae5"
+  integrity sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==
+
+"@rollup/rollup-win32-ia32-msvc@4.24.0":
+  version "4.24.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz#653f5989a60658e17d7576a3996deb3902e342e2"
+  integrity sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==
+
+"@rollup/rollup-win32-x64-msvc@4.24.0":
+  version "4.24.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz#0574d7e87b44ee8511d08cc7f914bcb802b70818"
+  integrity sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==
 
 "@surma/rollup-plugin-off-main-thread@^2.2.3":
   version "2.2.3"
@@ -1712,7 +1712,7 @@
     "@types/estree" "*"
     "@types/json-schema" "*"
 
-"@types/estree@*", "@types/estree@1.0.5", "@types/estree@^1.0.0":
+"@types/estree@*", "@types/estree@^1.0.0":
   version "1.0.5"
   resolved "https://registry.npmmirror.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
   integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
@@ -1722,6 +1722,11 @@
   resolved "https://registry.npmmirror.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
   integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
 
+"@types/estree@1.0.6":
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50"
+  integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==
+
 "@types/event-emitter@^0.3.3":
   version "0.3.5"
   resolved "https://registry.npmmirror.com/@types/event-emitter/-/event-emitter-0.3.5.tgz#ce9b513f72c50dcf0443a12165a93a79ba7a7092"
@@ -2039,7 +2044,7 @@
     "@babel/parser" "^7.23.5"
     "@vue/shared" "3.3.13"
     estree-walker "^2.0.2"
-    source-map-js "^1.2.0"
+    source-map-js "^1.0.2"
 
 "@vue/compiler-core@3.4.29":
   version "3.4.29"
@@ -2080,9 +2085,9 @@
     "@vue/reactivity-transform" "3.3.13"
     "@vue/shared" "3.3.13"
     estree-walker "^2.0.2"
-    magic-string "^0.30.10"
-    postcss "^8.4.38"
-    source-map-js "^1.2.0"
+    magic-string "^0.30.5"
+    postcss "^8.4.32"
+    source-map-js "^1.0.2"
 
 "@vue/compiler-sfc@^3.2.37", "@vue/compiler-sfc@^3.4.15":
   version "3.4.29"
@@ -4300,13 +4305,6 @@ fill-range@^7.1.1:
   dependencies:
     to-regex-range "^5.0.1"
 
-fill-range@^7.1.1:
-  version "7.1.1"
-  resolved "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
-  integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
-  dependencies:
-    to-regex-range "^5.0.1"
-
 find-up@^2.0.0:
   version "2.1.0"
   resolved "https://registry.npmmirror.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
@@ -6447,10 +6445,10 @@ picocolors@^1.0.0, picocolors@^1.0.1:
   resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1"
   integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==
 
-picocolors@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1"
-  integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==
+picocolors@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59"
+  integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==
 
 picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.1:
   version "2.3.1"
@@ -6572,6 +6570,15 @@ postcss@^8.4.0, postcss@^8.4.32, postcss@^8.4.38:
     picocolors "^1.0.0"
     source-map-js "^1.2.0"
 
+postcss@^8.4.43:
+  version "8.4.47"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365"
+  integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==
+  dependencies:
+    nanoid "^3.3.7"
+    picocolors "^1.1.0"
+    source-map-js "^1.2.1"
+
 posthtml-parser@^0.2.0, posthtml-parser@^0.2.1:
   version "0.2.1"
   resolved "https://registry.npmmirror.com/posthtml-parser/-/posthtml-parser-0.2.1.tgz#35d530de386740c2ba24ff2eb2faf39ccdf271dd"
@@ -6951,29 +6958,29 @@ rollup@^2.43.1, rollup@^2.77.2:
   optionalDependencies:
     fsevents "~2.3.2"
 
-rollup@^4.13.0:
-  version "4.18.0"
-  resolved "https://registry.npmmirror.com/rollup/-/rollup-4.18.0.tgz#497f60f0c5308e4602cf41136339fbf87d5f5dda"
-  integrity sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==
+rollup@^4.20.0:
+  version "4.24.0"
+  resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.24.0.tgz#c14a3576f20622ea6a5c9cad7caca5e6e9555d05"
+  integrity sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==
   dependencies:
-    "@types/estree" "1.0.5"
+    "@types/estree" "1.0.6"
   optionalDependencies:
-    "@rollup/rollup-android-arm-eabi" "4.18.0"
-    "@rollup/rollup-android-arm64" "4.18.0"
-    "@rollup/rollup-darwin-arm64" "4.18.0"
-    "@rollup/rollup-darwin-x64" "4.18.0"
-    "@rollup/rollup-linux-arm-gnueabihf" "4.18.0"
-    "@rollup/rollup-linux-arm-musleabihf" "4.18.0"
-    "@rollup/rollup-linux-arm64-gnu" "4.18.0"
-    "@rollup/rollup-linux-arm64-musl" "4.18.0"
-    "@rollup/rollup-linux-powerpc64le-gnu" "4.18.0"
-    "@rollup/rollup-linux-riscv64-gnu" "4.18.0"
-    "@rollup/rollup-linux-s390x-gnu" "4.18.0"
-    "@rollup/rollup-linux-x64-gnu" "4.18.0"
-    "@rollup/rollup-linux-x64-musl" "4.18.0"
-    "@rollup/rollup-win32-arm64-msvc" "4.18.0"
-    "@rollup/rollup-win32-ia32-msvc" "4.18.0"
-    "@rollup/rollup-win32-x64-msvc" "4.18.0"
+    "@rollup/rollup-android-arm-eabi" "4.24.0"
+    "@rollup/rollup-android-arm64" "4.24.0"
+    "@rollup/rollup-darwin-arm64" "4.24.0"
+    "@rollup/rollup-darwin-x64" "4.24.0"
+    "@rollup/rollup-linux-arm-gnueabihf" "4.24.0"
+    "@rollup/rollup-linux-arm-musleabihf" "4.24.0"
+    "@rollup/rollup-linux-arm64-gnu" "4.24.0"
+    "@rollup/rollup-linux-arm64-musl" "4.24.0"
+    "@rollup/rollup-linux-powerpc64le-gnu" "4.24.0"
+    "@rollup/rollup-linux-riscv64-gnu" "4.24.0"
+    "@rollup/rollup-linux-s390x-gnu" "4.24.0"
+    "@rollup/rollup-linux-x64-gnu" "4.24.0"
+    "@rollup/rollup-linux-x64-musl" "4.24.0"
+    "@rollup/rollup-win32-arm64-msvc" "4.24.0"
+    "@rollup/rollup-win32-ia32-msvc" "4.24.0"
+    "@rollup/rollup-win32-x64-msvc" "4.24.0"
     fsevents "~2.3.2"
 
 run-parallel@^1.1.9:
@@ -7265,6 +7272,11 @@ sortablejs@^1.15.1:
   resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
   integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==
 
+source-map-js@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
+  integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
+
 source-map-resolve@^0.5.0:
   version "0.5.3"
   resolved "https://registry.npmmirror.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
@@ -8261,14 +8273,14 @@ vite-plugin-svg-icons@^2.0.1:
     svg-baker "1.7.0"
     svgo "^2.8.0"
 
-vite@^5.0.8:
-  version "5.3.1"
-  resolved "https://registry.npmmirror.com/vite/-/vite-5.3.1.tgz#bb2ca6b5fd7483249d3e86b25026e27ba8a663e6"
-  integrity sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ==
+vite@^5.4.8:
+  version "5.4.8"
+  resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.8.tgz#af548ce1c211b2785478d3ba3e8da51e39a287e8"
+  integrity sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==
   dependencies:
     esbuild "^0.21.3"
-    postcss "^8.4.38"
-    rollup "^4.13.0"
+    postcss "^8.4.43"
+    rollup "^4.20.0"
   optionalDependencies:
     fsevents "~2.3.3"
 

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů