1
0

84 Revīzijas 77ffd506b9 ... 4a3c8de624

Autors SHA1 Ziņojums Datums
  allen 4a3c8de624 fix: add 'txt','xlsx', 'xls' for 评估标签 2 mēneši atpakaļ
  Eagle d23a19934c fix: fix log.log 4 mēneši atpakaļ
  Eagle c89fe94bdf Merge branch 'develop' of http://101.126.133.7:9001/www/taais-web into develop 4 mēneši atpakaļ
  Eagle 89239f4395 feat: 数据扩增入库、电子稳相指标 4 mēneši atpakaļ
  allen ad77a93086 fix: some bug 4 mēneši atpakaļ
  28968 b28515ed5e fix: bug fix 4 mēneši atpakaļ
  Eagle 196f476d73 fix: 多源信息融合显示修改,多目标检测按键修改 4 mēneši atpakaļ
  allen c4b9c32c44 Merge branch 'dev-style' into develop 4 mēneši atpakaļ
  28968 7b345e659d Merge branch 'tl' into develop 4 mēneši atpakaļ
  28968 14f5ac3536 Merge branch 'develop' of http://101.126.133.7:9001/www/taais-web into develop 4 mēneši atpakaļ
  28968 84537f19cd fix: bug fix 4 mēneši atpakaļ
  wanggaokun a3aff89e14 style: 表格列宽度足够用删除fixed: 'right'\fixed: 'left' 4 mēneši atpakaļ
  wanggaokun 15471aa508 style: 删除冗余代码 4 mēneši atpakaļ
  wanggaokun e28e848c4b style: 修改个人中心 4 mēneši atpakaļ
  wanggaokun f26f49304d style: 修改列表左右滑动问题登陆增加: 界面显示软件名称、版本号、研制单位: 西安交通大学弹出框优化 4 mēneši atpakaļ
  Eagle 476062d73d fix: fix label txt file cache 4 mēneši atpakaļ
  28968 98b5c056aa Merge branch 'develop' of http://101.126.133.7:9001/www/taais-web into tl 4 mēneši atpakaļ
  Gaokun Wang a7db019a1b style: 标题logo 4 mēneši atpakaļ
  Gaokun Wang 59406eab08 style: logo+系统名称 4 mēneši atpakaļ
  wanggaokun 0d3f27703a style: 头像 4 mēneši atpakaļ
  wanggaokun 3cf24ba5e6 style: 字体,按钮样式 4 mēneši atpakaļ
  Suuuuuukang eabb4d82f6 fix: 图片标注显示修复 4 mēneši atpakaļ
  wanggaokun fd5df63181 style: 样式修改 4 mēneši atpakaļ
  Gaokun Wang 77d015da20 style: 样式修改 4 mēneši atpakaļ
  Suuuuuukang b4e104a0d8 feat: 目标检测启动停止,下载改打开文件夹 4 mēneši atpakaļ
  28968 f2d8555bb6 fix: bug fix 4 mēneši atpakaļ
  allen a586bc6e42 Merge branch 'dev_wk2' into develop 5 mēneši atpakaļ
  Sk18834839360 7b08c79fb0 Merge branch 'dev_lsk_zip' of www/taais-web into develop 5 mēneši atpakaļ
  Suuuuuukang ca0abb7bb1 feat: 添加多目标检测导入模型、多源信息融合、异源图像匹配的文件说明 5 mēneši atpakaļ
  Sk18834839360 c435e9e8ae Merge branch 'dev_lsk_sjkz' of www/taais-web into develop 5 mēneši atpakaļ
  28968 631b76c696 fix: bug fix 5 mēneši atpakaļ
  WANGKANG 25ae37b53c feat: 压缩包添加标签提示 5 mēneši atpakaļ
  Suuuuuukang 1bddbd0eb4 feat: 添加打开文件夹功能 5 mēneši atpakaļ
  Suuuuuukang 05953bbe67 fix: 修改数据扩增显示细节 5 mēneši atpakaļ
  WANGKANG 3487b63472 Merge branch 'dev_wk2' into develop 6 mēneši atpakaļ
  WANGKANG a0dcc1bc51 feat: 1.修改数据加载逻辑 2. 添加自动刷新 6 mēneši atpakaļ
  WANGKANG a727c75e9a feat: 总任务测试 6 mēneši atpakaļ
  WANGKANG 35856c591a feat: cat测试 6 mēneši atpakaļ
  WANGKANG c07210e7a0 feat: masc测试 6 mēneši atpakaļ
  WANGKANG 2659eeb6ca feat: 修改模型必要性 6 mēneši atpakaļ
  WANGKANG a69bce53e2 feat: 目标检测模型名称可以修改 6 mēneši atpakaļ
  WANGKANG fa4e655807 feat: 评估结果展示 7 mēneši atpakaļ
  WANGKANG 6a272dc0c9 fix: 修改ShowStatisticResult的封装,添加title 7 mēneši atpakaļ
  WANGKANG dd86175169 feat: 预测任务结果预览 7 mēneši atpakaļ
  WANGKANG 10df04f5c3 feat: 修改ShowStatisticResult组件的封装 7 mēneši atpakaļ
  WANGKANG da9d5019d6 fix: 发现一个命名错误 7 mēneši atpakaļ
  WANGKANG f0939d04d5 feat: 预览功能 7 mēneši atpakaļ
  WANGKANG be7ae9809e feat: 查看日志功能 7 mēneši atpakaļ
  WANGKANG de1b8ca6a6 feat: 修改的ViewLog组件 7 mēneši atpakaļ
  WANGKANG 3e4dc257a0 feat: 停止功能 7 mēneši atpakaļ
  WANGKANG bbd9b2df98 feat: 开始功能 7 mēneši atpakaļ
  WANGKANG da43da10d2 feat: 删除功能 7 mēneši atpakaļ
  WANGKANG 0051787d8f fix: 修正 弹窗关不掉的问题 7 mēneši atpakaļ
  WANGKANG e5ca552392 feat: 总任务-注释轨迹序列-查看-编辑 初步完成 目标检测模型目前还获取不到 7 mēneši atpakaļ
  WANGKANG 5b5b03d9af feat: 总任务-可见光-查看-编辑 完成 7 mēneši atpakaļ
  WANGKANG 273f4c601b feat: 查看功能-列表展示完善 7 mēneši atpakaļ
  Eagle e84e772cff feat: 多源信息融合、异源图像匹配、电子稳相的暂停、继续、停止功能 7 mēneši atpakaļ
  WANGKANG 30de862353 feat: 初步实现子任务查看功能 7 mēneši atpakaļ
  WANGKANG a610081dc8 feat: 添加一个子任务查看接口 7 mēneši atpakaļ
  WANGKANG c506380af1 feat: 添加一个enum 7 mēneši atpakaļ
  WANGKANG eb7ead22ca fix: 修正表单关闭后再打开内容未重置 7 mēneši atpakaļ
  WANGKANG 1dbf83a9eb feat: 总任务新增初步完成 7 mēneši atpakaļ
  WANGKANG 40bd03cdfd fix: 算法参数设置 7 mēneši atpakaļ
  WANGKANG 9f14d2b0e6 feat: 总任务新增窗口初步完成 7 mēneši atpakaļ
  WANGKANG 31fd6e5c13 feat: 总任务添加功能编写(未完成) 7 mēneši atpakaļ
  WANGKANG dd5f6af347 feat: 可辨识性分析总任务前端任务初步添加 7 mēneši atpakaļ
  WANGKANG a72d64a4d8 feat: 可辨识性分析优化 7 mēneši atpakaļ
  Eagle 5bf88e391c feat: revert 4nodes labeled file to xywh format 7 mēneši atpakaļ
  WANGKANG 9829203a45 feat: 目标检测优化 7 mēneši atpakaļ
  WANGKANG fdb92e4d25 feat: 优化可见光转红外两个细节 7 mēneši atpakaļ
  WANGKANG cf96a0a712 fix: 1. 可见光转红外新增、更新完成 2. 修正若干逻辑 3. 删掉无用方法 7 mēneši atpakaļ
  WANGKANG 4646566348 fix: 1. 移除多余的console 2. 可见光转红外新增界面修正 7 mēneši atpakaļ
  WANGKANG 96217b761a fix: 1. FromDialog组件添加updateItemOptions方法,用于动态更新表单 2. File组件修正一个警告 7 mēneši atpakaļ
  WANGKANG 7e13fc2a75 fix: protable添加一个change方法,可以用于在值发生变化时的回调 7 mēneši atpakaļ
  WANGKANG 3e93f505ba fix: 算法名称 7 mēneši atpakaļ
  WANGKANG 3540c449ea feat: 模型配置添加新的参数algorithmParameters 7 mēneši atpakaļ
  WANGKANG 9d4cd04b08 feat: 可辨识性分析添加新的参数,前端适配 7 mēneši atpakaļ
  allen f65c4dfe61 Merge branch 'dev_lsk_b12' into develop 7 mēneši atpakaļ
  28968 b6847bb29d fix: bug fix 7 mēneši atpakaļ
  Eagle 3fcbd18f3a feat: 数据扩增任务、电子稳相标准化 7 mēneši atpakaļ
  28968 69045b929f fix: bug fix 7 mēneši atpakaļ
  www 47bc38f8c7 Merge branch 'tl' of www/taais-web into develop 7 mēneši atpakaļ
  28968 e553a99c56 fix: bug fix 7 mēneši atpakaļ
  Eagle a6468390d3 feat: 多源信息融合、异源图像匹配定位的配置读取、超参传递 7 mēneši atpakaļ
74 mainītis faili ar 4978 papildinājumiem un 1452 dzēšanām
  1. 1 1
      .env
  2. 1 1
      .eslintrc.cjs
  3. 1 1
      .stylelintrc.cjs
  4. 1 1
      .vscode/settings.json
  5. 1 1
      index.html
  6. 766 95
      package-lock.json
  7. 0 1
      package.json
  8. BIN
      public/logo.png
  9. 146 0
      src/api/interface/demo/algorithmConfig.ts
  10. 146 0
      src/api/interface/demo/algorithmTaskTrack.ts
  11. 85 0
      src/api/modules/demo/algorithmConfig.ts
  12. 75 0
      src/api/modules/demo/algorithmTaskTrack.ts
  13. 5 2
      src/api/modules/demo/dataAugmentation.ts
  14. 8 0
      src/api/modules/demo/match.ts
  15. 8 0
      src/api/modules/demo/traceMerge.ts
  16. 1 1
      src/api/modules/demo/trackSequence.ts
  17. 4 0
      src/api/modules/demo/videoStable.ts
  18. BIN
      src/assets/images/bg0.png
  19. BIN
      src/assets/images/bg1.png
  20. BIN
      src/assets/images/logo.png
  21. BIN
      src/assets/images/touxiang.png
  22. 18 18
      src/components/DataAugmentationFormDialog/index.vue
  23. 14 6
      src/components/FormDialog/index.vue
  24. 10 0
      src/components/ProForm/components/Item.vue
  25. 15 0
      src/components/ProForm/index.scss
  26. 5 5
      src/components/ProForm/index.vue
  27. 2 2
      src/components/Upload/File.vue
  28. 1 1
      src/config/index.ts
  29. 26 12
      src/layouts/LayoutTransverse/index.scss
  30. 1 1
      src/layouts/LayoutTransverse/index.vue
  31. 2 1
      src/layouts/components/Footer/index.scss
  32. 1 1
      src/layouts/components/Footer/index.vue
  33. 3 0
      src/layouts/components/Header/ToolBarRight.vue
  34. 1 1
      src/layouts/components/Header/components/Avatar.vue
  35. 5 0
      src/layouts/components/Header/components/Fullscreen.vue
  36. 3 1
      src/layouts/components/Main/index.scss
  37. 12 17
      src/layouts/components/Menu/SubMenu.vue
  38. 9 4
      src/layouts/components/Tabs/index.scss
  39. 1 2
      src/main.ts
  40. 1 1
      src/stores/modules/global.ts
  41. 1 1
      src/stores/modules/user.ts
  42. 30 12
      src/styles/element-dark.scss
  43. 64 18
      src/styles/element.scss
  44. 1 0
      src/typings/ProForm.d.ts
  45. 72 10
      src/views/demo/AlgorithmConfigTrack/index.vue
  46. 59 35
      src/views/demo/AlgorithmModelTrack/index.vue
  47. 135 27
      src/views/demo/TargetDetection/index.vue
  48. 1231 0
      src/views/demo/algorithmTaskTrack/index.vue
  49. 20 0
      src/views/demo/components/PreviewImages.vue
  50. 16 4
      src/views/demo/components/ShowStatisticResult.vue
  51. 10 5
      src/views/demo/components/ViewLog.vue
  52. 21 5
      src/views/demo/components/img-maker.vue
  53. 15 12
      src/views/demo/data/AmplifyForm.vue
  54. 16 7
      src/views/demo/data/index.vue
  55. 41 0
      src/views/demo/data/reformat.js
  56. 210 166
      src/views/demo/dataAugmentation/index.vue
  57. 56 12
      src/views/demo/imageMosaic/index.vue
  58. 51 5
      src/views/demo/match/index.vue
  59. 67 30
      src/views/demo/targetDamageAcess/index.vue
  60. 146 106
      src/views/demo/targetTrack/index.vue
  61. 134 98
      src/views/demo/toInfrared/index.vue
  62. 71 10
      src/views/demo/traceMerge/index.vue
  63. 201 27
      src/views/demo/trackSequence/index.vue
  64. 8 0
      src/views/demo/utils.ts
  65. 122 74
      src/views/demo/videoStable/index.vue
  66. 15 8
      src/views/login/index.scss
  67. 5 8
      src/views/login/index.vue
  68. 258 0
      src/views/system/config/index.vue
  69. 13 13
      src/views/taais/homePage/index.scss
  70. 2 2
      src/views/taais/homePage/index.vue
  71. 29 5
      src/views/taais/homePage/task/index.vue
  72. 13 9
      src/views/task/amplify/index.vue
  73. 60 5
      src/views/task/bizProcess/index.vue
  74. 406 561
      yarn.lock

+ 1 - 1
.env

@@ -1,5 +1,5 @@
 # title
-VITE_GLOB_APP_TITLE = 算法任务系统
+VITE_GLOB_APP_TITLE = 目标捕获技术设计支撑环境
 
 # 本地运行端口号
 VITE_PORT = 8848

+ 1 - 1
.eslintrc.cjs

@@ -29,7 +29,7 @@ module.exports = {
   rules: {
     // eslint (http://eslint.cn/docs/rules)
     'no-var': 'warn', // 要求使用 let 或 const 而不是 var
-    // 'no-multiple-empty-lines': ['warn', { max: 1 }], // 不允许多个空行
+    'no-multiple-empty-lines': 'off', // 不允许多个空行
     'prefer-const': 'off', // 使用 let 关键字声明但在初始分配后从未重新分配的变量,要求使用 const
     'no-use-before-define': 'off', // 禁止在 函数/类/变量 定义之前使用它们
     'prettier/prettier': [

+ 1 - 1
.stylelintrc.cjs

@@ -20,7 +20,7 @@ module.exports = {
   rules: {
     'function-url-quotes': 'always', // URL 的引号 "always(必须加上引号)"|"never(没有引号)"
     'color-hex-length': 'long', // 指定 16 进制颜色的简写或扩写 "short(16进制简写)"|"long(16进制扩写)"
-    'rule-empty-line-before': 'never', // 要求或禁止在规则之前的空行 "always(规则之前必须始终有一个空行)"|"never(规则前绝不能有空行)"|"always-multi-line(多行规则之前必须始终有一个空行)"|"never-multi-line(多行规则之前绝不能有空行)"
+    'rule-empty-line-before': null, // 要求或禁止在规则之前的空行 "always(规则之前必须始终有一个空行)"|"never(规则前绝不能有空行)"|"always-multi-line(多行规则之前必须始终有一个空行)"|"never-multi-line(多行规则之前绝不能有空行)"
     'font-family-no-missing-generic-family-keyword': null, // 禁止在字体族名称列表中缺少通用字体族关键字
     'scss/at-import-partial-extension': null, // 解决不能使用 @import 引入 scss 文件
     'property-no-unknown': null, // 禁止未知的属性

+ 1 - 1
.vscode/settings.json

@@ -8,7 +8,7 @@
   "files.eol": "\n",
   "typescript.tsdk": "node_modules/typescript/lib",
   "[vue]": {
-    "editor.defaultFormatter": "Vue.volar"
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
   },
   "[typescript]": {
     "editor.defaultFormatter": "esbenp.prettier-vscode"

+ 1 - 1
index.html

@@ -2,7 +2,7 @@
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
-    <link rel="icon" type="image/svg+xml" href="/logo.svg" />
+    <link rel="icon" type="image/svg+xml" href="/logo.png" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title><%= title %></title>
   </head>

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 766 - 95
package-lock.json


+ 0 - 1
package.json

@@ -27,7 +27,6 @@
   },
   "dependencies": {
     "@element-plus/icons-vue": "^2.3.1",
-    "@kjgl77/datav-vue3": "^1.7.2",
     "@types/file-saver": "^2.0.7",
     "@types/js-cookie": "^3.0.6",
     "@vueuse/core": "^10.6.1",

BIN
public/logo.png


+ 146 - 0
src/api/interface/demo/algorithmConfig.ts

@@ -0,0 +1,146 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface AlgorithmConfigVO extends BaseEntity {
+  /**
+   * $column.columnComment
+   */
+  id: string | number
+
+  /**
+   * $column.columnComment
+   */
+  tool: string
+
+  /**
+   * $column.columnComment
+   */
+  module: string
+
+  /**
+   * $column.columnComment
+   */
+  algorithmName: string
+
+  /**
+   * $column.columnComment
+   */
+  startApi: string
+
+  /**
+   * $column.columnComment
+   */
+  pauseApi: string
+
+  /**
+   * $column.columnComment
+   */
+  terminateApi: string
+
+  /**
+   * $column.columnComment
+   */
+  parameters: string
+
+  /**
+   * $column.columnComment
+   */
+  remarks: string
+}
+
+export interface AlgorithmConfigForm {
+  /**
+   * $column.columnComment
+   */
+  id?: string | number
+
+  /**
+   * $column.columnComment
+   */
+  tool?: string
+
+  /**
+   * $column.columnComment
+   */
+  module?: string
+
+  /**
+   * $column.columnComment
+   */
+  algorithmName?: string
+
+  /**
+   * $column.columnComment
+   */
+  startApi?: string
+
+  /**
+   * $column.columnComment
+   */
+  pauseApi?: string
+
+  /**
+   * $column.columnComment
+   */
+  terminateApi?: string
+
+  /**
+   * $column.columnComment
+   */
+  parameters?: string
+
+  /**
+   * $column.columnComment
+   */
+  remarks?: string
+
+  /**
+   * $column.columnComment
+   */
+  version?: number
+}
+
+export interface AlgorithmConfigQuery extends PageQuery {
+  /**
+   * $column.columnComment
+   */
+  tool?: string
+
+  /**
+   * $column.columnComment
+   */
+  module?: string
+
+  /**
+   * $column.columnComment
+   */
+  algorithmName?: string
+
+  /**
+   * $column.columnComment
+   */
+  startApi?: string
+
+  /**
+   * $column.columnComment
+   */
+  pauseApi?: string
+
+  /**
+   * $column.columnComment
+   */
+  terminateApi?: string
+
+  /**
+   * $column.columnComment
+   */
+  parameters?: string
+
+  /**
+   * $column.columnComment
+   */
+  remarks?: string
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+}

+ 146 - 0
src/api/interface/demo/algorithmTaskTrack.ts

@@ -0,0 +1,146 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface AlgorithmTaskTrackVO extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id: string | number
+
+  /**
+   * 任务名称
+   */
+  name: string
+
+  /**
+   * 任务状态
+   */
+  status: string
+
+  /**
+   * 开始时间
+   */
+  startTime: string
+
+  /**
+   * 结束时间
+   */
+  endTime: string
+
+  /**
+   * 耗时
+   */
+  costSecond: number
+
+  /**
+   * 日志
+   */
+  log: string
+
+  /**
+   * 备注
+   */
+  remarks: string
+
+  /**
+   * 系统
+   */
+  system: string
+}
+
+export interface AlgorithmTaskTrackForm {
+  /**
+   * 主键ID
+   */
+  id?: string | number
+
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
+  /**
+   * 耗时
+   */
+  costSecond?: number
+
+  /**
+   * 日志
+   */
+  log?: string
+
+  /**
+   * 备注
+   */
+  remarks?: string
+
+  /**
+   * 乐观锁
+   */
+  version?: number
+
+  /**
+   * 系统
+   */
+  system?: string
+}
+
+export interface AlgorithmTaskTrackQuery extends PageQuery {
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
+  /**
+   * 耗时
+   */
+  costSecond?: number
+
+  /**
+   * 日志
+   */
+  log?: string
+
+  /**
+   * 备注
+   */
+  remarks?: string
+
+  /**
+   * 系统
+   */
+  system?: string
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+}

+ 85 - 0
src/api/modules/demo/algorithmConfig.ts

@@ -0,0 +1,85 @@
+import http from '@/api'
+import { AlgorithmConfigVO, AlgorithmConfigForm, AlgorithmConfigQuery } from '@/api/interface/demo/algorithmConfig'
+/**
+ * @name 查询【请填写功能名称】列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listAlgorithmConfigApi = (query: AlgorithmConfigQuery) => {
+  return http.get<AlgorithmConfigVO[]>('/demo/algorithmConfig/list', query, { loading: true })
+}
+
+export const getJsonParams = data => {
+  let ret = {}
+  data.forEach(item => {
+    if (item.value === 0 || item.value.length === 0 || !item.value) {
+      ret[item.agName] = item.defaultValue
+    } else {
+      ret[item.agName] = item.value
+    }
+  })
+  return ret
+}
+
+export const getOneAlgorithmConfigApi = (query: AlgorithmConfigQuery) => {
+  return http.get<AlgorithmConfigVO[]>('/demo/algorithmConfig/getOne', query, { loading: true })
+}
+/**
+ * @name 查询【请填写功能名称】详细
+ * @param id id
+ * @returns returns
+ */
+export const getAlgorithmConfigApi = (id: string | number) => {
+  return http.get<AlgorithmConfigVO>(`/demo/algorithmConfig/${id}`)
+}
+
+/**
+ * @name 新增【请填写功能名称】
+ * @param data data
+ * @returns returns
+ */
+export const addAlgorithmConfigApi = (data: AlgorithmConfigForm) => {
+  return http.post<any>('/demo/algorithmConfig', data, { loading: false })
+}
+
+/**
+ * @name 修改【请填写功能名称】
+ * @param data data
+ * @returns returns
+ */
+export const updateAlgorithmConfigApi = (data: AlgorithmConfigForm) => {
+  return http.put<any>('/demo/algorithmConfig', data, { loading: false })
+}
+
+/**
+ * @name 删除【请填写功能名称】
+ * @param id id
+ * @returns returns
+ */
+export const delAlgorithmConfigApi = (id: string | number | Array<string | number>) => {
+  return http.delete<any>(`/demo/algorithmConfig/${id}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/demo/algorithmConfig/importTemplate', {})
+}
+
+/**
+ * @name 导入数据
+ * @returns returns
+ */
+export const importAlgorithmConfigDataApi = (data: any) => {
+  return http.post('/demo/algorithmConfig/importData', data)
+}
+
+/**
+ * @name 导出数据
+ * @returns returns
+ */
+export const exportAlgorithmConfigApi = (data: any) => {
+  return http.downloadPost('/demo/algorithmConfig/export', data)
+}

+ 75 - 0
src/api/modules/demo/algorithmTaskTrack.ts

@@ -0,0 +1,75 @@
+import http from '@/api'
+import { AlgorithmTaskTrackVO, AlgorithmTaskTrackForm, AlgorithmTaskTrackQuery } from '@/api/interface/demo/algorithmTaskTrack'
+
+/**
+ * @name 查询可辨识性分析总任务列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listAlgorithmTaskTrackApi = (query: AlgorithmTaskTrackQuery) => {
+  return http.get<AlgorithmTaskTrackVO[]>('/demo/algorithmTaskTrack/list', query, { loading: true })
+}
+
+/**
+ * @name 查询可辨识性分析总任务详细
+ * @param id id
+ * @returns returns
+ */
+export const getAlgorithmTaskTrackApi = (id: string | number) => {
+  return http.get<AlgorithmTaskTrackVO>(`/demo/algorithmTaskTrack/${id}`)
+}
+
+/**
+ * @name 新增可辨识性分析总任务
+ * @param data data
+ * @returns returns
+ */
+export const addAlgorithmTaskTrackApi = (data: AlgorithmTaskTrackForm) => {
+  return http.post<any>('/demo/algorithmTaskTrack', data, { loading: false })
+}
+
+/**
+ * @name 修改可辨识性分析总任务
+ * @param data data
+ * @returns returns
+ */
+export const updateAlgorithmTaskTrackApi = (data: AlgorithmTaskTrackForm) => {
+  return http.put<any>('/demo/algorithmTaskTrack', data, { loading: false })
+}
+
+/**
+ * @name 删除可辨识性分析总任务
+ * @param id id
+ * @returns returns
+ */
+export const delAlgorithmTaskTrackApi = (id: string | number | Array<string | number>) => {
+  return http.delete<any>(`/demo/algorithmTaskTrack/${id}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/demo/algorithmTaskTrack/importTemplate', {})
+}
+
+/**
+ * @name 导入数据
+ * @returns returns
+ */
+export const importAlgorithmTaskTrackDataApi = (data: any) => {
+  return http.post('/demo/algorithmTaskTrack/importData', data)
+}
+
+/**
+ * @name 导出数据
+ * @returns returns
+ */
+export const exportAlgorithmTaskTrackApi = (data: any) => {
+  return http.downloadPost('/demo/algorithmTaskTrack/export', data)
+}
+
+export const listSubTaskAlgorithmTaskTrackApi = (id: string | number) => {
+  return http.get(`/demo/algorithmTaskTrack/listSubTask/${id}`)
+}

+ 5 - 2
src/api/modules/demo/dataAugmentation.ts

@@ -5,8 +5,8 @@ import { DataAugmentationVO, DataAugmentationForm, DataAugmentationQuery } from
  * @name 查询任务字典数据
  * @returns 返回列表
  */
-export const getTaskDictData = () => {
-  return http.get<any>('/demo/dataAugmentation/getTaskDictData', { loading: true })
+export const getTaskDictData = module => {
+  return http.post<any>('/demo/dataAugmentation/getTaskDictData', module, { loading: true })
 }
 /**
  * @name 查询视频去抖动列表
@@ -108,6 +108,9 @@ export const startDataAugmentationApi = (id: String | Number) => {
 export const stopDataAugmentationApi = (id: String | Number) => {
   return http.get('/demo/dataAugmentation/stop/' + id)
 }
+export const pauseDataAugmentationApi = (id: String | Number) => {
+  return http.get('/demo/dataAugmentation/pause/' + id)
+}
 
 export const getCompareImageApi = (taskId: String) => {
   return http.get('/demo/dataAugmentation/compare/' + taskId)

+ 8 - 0
src/api/modules/demo/match.ts

@@ -35,6 +35,14 @@ export const execute = data => {
   return http.get<any>('/demo/match/execute', data, { loading: false })
 }
 
+export const stopApi = data => {
+  return http.get<any>('/demo/match/stop', data, { loading: false })
+}
+
+export const hangupApi = data => {
+  return http.get<any>('/demo/match/hangup', data, { loading: false })
+}
+
 export const getResult = data => {
   return http.get<any>('/demo/match/result', data, { loading: false })
 }

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

@@ -31,6 +31,14 @@ export const executeApi = data => {
   return http.post<any>('/demo/traceMerge/execute', data, { loading: false })
 }
 
+export const stopApi = data => {
+  return http.post<any>('/demo/traceMerge/stop', data, { loading: false })
+}
+
+export const hangupApi = data => {
+  return http.post<any>('/demo/traceMerge/hangup', data, { loading: false })
+}
+
 export const getResApi = data => {
   return http.get<any>('/demo/traceMerge/result', data, { loading: false })
 }

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

@@ -115,6 +115,6 @@ export const previewEvaluateTrackSequenceApi = (id: string | number) => {
   return http.get('/demo/trackSequence/previewEvaluateResult/' + id, {}, { loading: false })
 }
 
-export const getStatisticsResultToInfraredApi = (id: string | number) => {
+export const getStatisticsResultTrackSequenceApi = (id: string | number) => {
   return http.get('/demo/trackSequence/statistics_result/' + id, {}, { loading: false })
 }

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

@@ -83,6 +83,10 @@ export const stopVideoStableApi = (id: String | Number) => {
   return http.get('/demo/videoStable/stop/' + id)
 }
 
+export const hangupVideoStableApi = (id: String | Number) => {
+  return http.get('/demo/videoStable/hangup/' + id)
+}
+
 export const getCompareImageApi = (taskId: String, idx: String | Number) => {
   return http.get('/demo/videoStable/compare/' + taskId + '/' + idx)
 }

BIN
src/assets/images/bg0.png


BIN
src/assets/images/bg1.png


BIN
src/assets/images/logo.png


BIN
src/assets/images/touxiang.png


+ 18 - 18
src/components/DataAugmentationFormDialog/index.vue

@@ -132,24 +132,24 @@ const handleSubmit = () => {
         // data = { ...formModel, ...parameter.value.model }
         data = mergeWithCondition(formModel, parameter.value.model)
       }
-      let excludedKeys = ['name', 'taskType', 'inputOssId', 'remarks', 'modelAddress', 'yolo_model', 'tracking_method']
-      for (let key in data) {
-        if (data.hasOwnProperty(key) && !excludedKeys.includes(key)) {
-          if (!isFloat(data[key])) {
-            ElMessage.error(key + '参数设置不合理!')
-            butLoading.value = false
-            return
-          } else {
-            let num = parseFloat(data[key])
-            if (key == 's_v' && Number.isInteger(num) && num % 2 == 0) {
-              ElMessage.error(key + '参数只能为奇数!')
-              butLoading.value = false
-              return
-            }
-          }
-        }
-      }
-      excludedKeys = ['name', 'taskType', 'inputOssId', 'remarks', 'modelAddress']
+      // let excludedKeys = ['name', 'taskType', 'inputOssId', 'remarks', 'modelAddress', 'yolo_model', 'tracking_method']
+      // for (let key in data) {
+      //   if (data.hasOwnProperty(key) && !excludedKeys.includes(key)) {
+      //     if (!isFloat(data[key])) {
+      //       ElMessage.error(key + '参数设置不合理!')
+      //       butLoading.value = false
+      //       return
+      //     } else {
+      //       let num = parseFloat(data[key])
+      //       if (key == 's_v' && Number.isInteger(num) && num % 2 == 0) {
+      //         ElMessage.error(key + '参数只能为奇数!')
+      //         butLoading.value = false
+      //         return
+      //       }
+      //     }
+      //   }
+      // }
+      let excludedKeys = ['name', 'taskType', 'inputOssId', 'remarks', 'modelAddress']
       // 使用 Object.fromEntries 从指定的键值对创建新的对象
       let hyperparameters = Object.fromEntries(Object.entries(data).filter(([key, _]) => !excludedKeys.includes(key)))
       // 将 hyperparameters 对象转换为 JSON 字符串

+ 14 - 6
src/components/FormDialog/index.vue

@@ -25,7 +25,7 @@
 </template>
 
 <script setup lang="ts" name="FormDialog">
-import { ref, ComputedRef, computed, reactive } from 'vue'
+import { ref, ComputedRef, computed, reactive, nextTick } from 'vue'
 import ProFrom from '@/components/ProForm/index.vue'
 import { ElMessage } from 'element-plus'
 import FileUpload from '@/components/Upload/File.vue'
@@ -130,10 +130,10 @@ const handleCancel = () => {
   //console.log(parameter.value.model)
   const formEl = proFormRef.value?.proFormRef
   if (!formEl) return
-  if (parameter.value.model?.url) {
-    ElMessage.info('请先删除已经上传的图片')
-    return
-  }
+  // if (parameter.value.model?.url) {
+  //   ElMessage.info('请先删除已经上传的图片')
+  //   return
+  // }
   proFormRef.value?.resetForm(formEl)
   butLoading.value = false
   dialogVisible.value = false
@@ -150,8 +150,16 @@ const openDialog = (params: FormParameterProps, algoModelId = null) => {
   dialogVisible.value = true
 }
 
+const updateItemOptions = (itemsOptions: ProForm.ItemsOptions[]) => {
+  // console.log('updateItemOptions', itemsOptions)
+  nextTick(() => {
+    parameter.value.itemsOptions = Object.assign([], itemsOptions)
+  })
+}
+
 defineExpose({
-  openDialog
+  openDialog,
+  updateItemOptions
 })
 </script>
 

+ 10 - 0
src/components/ProForm/components/Item.vue

@@ -5,6 +5,7 @@
     v-model.trim="_formModel[handleProp(item.prop)]"
     :data="['tree-select'].includes(item.compOptions.elTagName!) ? itemEnum : []"
     :options="['cascader', 'select-v2'].includes(item.compOptions.elTagName!) ? itemEnum : []"
+    @change="handleInputChange(item, formModel)"
   >
     <template v-if="item.compOptions.elTagName === 'cascader'" #default="{ data }">
       <span>{{ data[item.compOptions.labelKey || 'label'] }}</span>
@@ -44,10 +45,13 @@
 <script setup lang="ts" name="Item">
 import { computed, inject, ref } from 'vue'
 import { handleProp } from '@/utils'
+
 interface FormItem {
   item: ProForm.ItemsOptions
   formModel: Record<string, any>
+  change?: (val: any) => void
 }
+
 const props = defineProps<FormItem>()
 const _formModel = computed(() => props.formModel)
 const elTagNameValue = computed(() => {
@@ -73,4 +77,10 @@ const itemEnum = computed(() => {
   }
   return enumData
 })
+
+const handleInputChange = (item: ProForm.ItemsOptions, formModel: Record<string, any>) => {
+  if (item.change) {
+    props.change(item, formModel)
+  }
+}
 </script>

+ 15 - 0
src/components/ProForm/index.scss

@@ -0,0 +1,15 @@
+.label-span {
+  display: inline-block;
+  max-width: 150px;
+
+  /* 防止文本换行 */
+  overflow: hidden;
+
+  /* 超出部分隐藏 */
+  text-overflow: ellipsis;
+
+  /* 你可以根据需求调整这个宽度 */
+  white-space: nowrap;
+
+  /* 超出部分用省略号表示 */
+}

+ 5 - 5
src/components/ProForm/index.vue

@@ -2,7 +2,7 @@
   <component :is="'el-form'" v-bind="_formOptions" ref="proFormRef" :model="formModel">
     <el-row :gutter="5">
       <template v-for="item in itemsOptions" :key="item.prop">
-        <el-col :span="item.span || 24" g v-if="show(item.show)">
+        <el-col :span="item.span || 24" v-if="show(item.show)">
           <component :is="'el-form-item'" v-bind="item">
             <template #label>
               <el-space :size="4">
@@ -46,7 +46,7 @@
             <template v-else-if="item.compOptions.elTagName === 'imgs-upload-s3'">
               <ImgsS3 v-model="formModel[item.prop]" v-bind="$attrs" />
             </template>
-            <Item v-else :item="item" :form-model="formModel" />
+            <Item v-else :item="item" :form-model="formModel" :change="item.change" />
           </component>
         </el-col>
       </template>
@@ -96,8 +96,8 @@ const props = withDefaults(defineProps<ProFormProps>(), {
 const show = (showFunction: any) => {
   if (!showFunction) return true
   if (typeof showFunction == 'function') {
-    // 直接调用 showFunction 函数,并传入 formModel.value
-    return showFunction(formModel.value)
+    // 直接调用 showFunction 函数,并传入 formModel,方便修改参数
+    return showFunction(formModel)
   }
   // 如果 showFunction 不是函数,直接返回 true 显示该表单项
   return true
@@ -213,5 +213,5 @@ defineExpose({
 })
 </script>
 <style scoped lang="scss">
-@import './index.scss';
+@import './index';
 </style>

+ 2 - 2
src/components/Upload/File.vue

@@ -66,7 +66,7 @@ interface UploadFileProps {
   icon?: string
   fileType?: Array<string>
   uploadApiPath?: string // 上传文件服务器地址
-  canRemove: boolean // 是否显示删除按钮
+  canRemove?: boolean // 是否显示删除按钮
 }
 
 // 默认值
@@ -81,7 +81,7 @@ const props = withDefaults(defineProps<UploadFileProps>(), {
   isShowTip: true,
   uploadApiPath: '/common/upload',
   icon: 'upload-filled',
-  canRemove: false
+  canRemove: true
 })
 
 const baseUrl = import.meta.env.VITE_API_URL

+ 1 - 1
src/config/index.ts

@@ -7,7 +7,7 @@ export const HOME_URL: string = '/index'
 export const LOGIN_URL: string = '/login'
 
 // 默认主题颜色
-export const DEFAULT_PRIMARY: string = '#009688'
+export const DEFAULT_PRIMARY: string = '#7FFFFF'
 
 // 路由白名单地址(本地存在的路由 staticRouter.ts 中)
 export const ROUTER_WHITE_LIST: string[] = ['/500', '/login', '/register']

+ 26 - 12
src/layouts/LayoutTransverse/index.scss

@@ -1,6 +1,9 @@
 .el-container {
   width: 100%;
   height: 100%;
+  background-image: url('@/assets/images/bg0.png');
+  background-repeat: repeat;
+  background-size: contain;
   :deep(.el-header) {
     box-sizing: border-box;
     display: flex;
@@ -8,20 +11,23 @@
     justify-content: space-between;
     height: 55px;
     padding: 0 15px 0 0;
-    background-color: var(--el-header-bg-color);
-    border-bottom: 1px solid var(--el-header-border-color);
+    background-image: url('@/assets/images/bg1.png');
+    background-repeat: repeat;
+
+    // background-size: contain;
+    border-bottom: 1px solid #4ca6ff;
     .logo {
-      width: 210px;
+      min-width: 210px;
       margin-right: 30px;
       .logo-img {
-        width: 28px;
-        object-fit: contain;
+        width: 45px;
         margin-right: 6px;
+        object-fit: contain;
       }
       .logo-text {
-        font-size: 21.5px;
+        font-size: 19px;
         font-weight: bold;
-        color: var(--el-header-logo-text-color);
+        color: #7fffff;
         white-space: nowrap;
       }
     }
@@ -29,24 +35,32 @@
       flex: 1;
       height: 100%;
       overflow: hidden;
+      background-color: transparent;
       border-bottom: none;
+      .el-menu-item {
+        font-size: 18px !important;
+        color: #7fffff !important;
+      }
       .el-sub-menu__hide-arrow {
         width: 65px;
         height: 55px;
       }
       .el-menu-item.is-active {
-        color: #ffffff !important;
+        color: #7fffff !important;
+      }
+      .el-sub-menu__title {
+        font-size: 18px !important;
       }
       .is-active {
-        background-color: var(--el-color-primary) !important;
-        border-bottom-color: var(--el-color-primary) !important;
+        background: linear-gradient(0deg, #4ca6ff 0%, #7fffff 100%) !important;
+        border-bottom: none;
         &::before {
           width: 0;
         }
         .el-sub-menu__title {
           color: #ffffff !important;
-          background-color: var(--el-color-primary) !important;
-          border-bottom-color: var(--el-color-primary) !important;
+          background: linear-gradient(0deg, #4ca6ff 0%, #7fffff 100%) !important;
+          border-bottom: none;
         }
       }
     }

+ 1 - 1
src/layouts/LayoutTransverse/index.vue

@@ -3,7 +3,7 @@
   <el-container class="layout">
     <el-header>
       <div class="logo flx-center">
-        <img class="logo-img" src="@/assets/images/logo.svg" alt="logo" />
+        <img class="logo-img" src="@/assets/images/logo.png" alt="logo" />
         <span class="logo-text">{{ title }}</span>
       </div>
       <el-menu mode="horizontal" :router="false" :default-active="activeMenu">

+ 2 - 1
src/layouts/components/Footer/index.scss

@@ -1,6 +1,7 @@
 .footer {
   height: 30px;
-  background-color: var(--el-bg-color);
+
+  // background-color: var(--el-bg-color);
   border-top: 1px solid var(--el-border-color-light);
   a {
     font-size: 14px;

+ 1 - 1
src/layouts/components/Footer/index.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="footer flx-center">
-    <a href="https://gitee.com/gaokunw/kimi-web" target="_blank"> 2023 © taais-Admin By gaokunw Technology. </a>
+    <a href="https://gitee.com/gaokunw/kimi-web" target="_blank"> 版本号:V1.2.0 研制单位:西安交通大学</a>
   </div>
 </template>
 

+ 3 - 0
src/layouts/components/Header/ToolBarRight.vue

@@ -36,9 +36,11 @@ import Avatar from './components/Avatar.vue'
   align-items: center;
   justify-content: center;
   padding-right: 25px;
+
   .header-icon {
     display: flex;
     align-items: center;
+
     & > * {
       margin-left: 21px;
       color: var(--el-header-text-color);
@@ -46,6 +48,7 @@ import Avatar from './components/Avatar.vue'
 
     margin-right: 12px;
   }
+
   .username {
     margin: 0 20px;
     font-size: 15px;

+ 1 - 1
src/layouts/components/Header/components/Avatar.vue

@@ -4,7 +4,7 @@
       <img :src="userStore.avatar" />
     </div>
     <div class="avatar-dft" v-else>
-      <img src="@/assets/icons/avatar-user.svg" alt="avatar" />
+      <img src="@/assets/images/touxiang.png" alt="avatar" />
     </div>
     <template #dropdown>
       <el-dropdown-menu>

+ 5 - 0
src/layouts/components/Header/components/Fullscreen.vue

@@ -23,3 +23,8 @@ const handleFullScreen = () => {
   screenfull.toggle()
 }
 </script>
+<style scoped lang="scss">
+.toolBar-icon {
+  color: #7fffff;
+}
+</style>

+ 3 - 1
src/layouts/components/Main/index.scss

@@ -2,7 +2,9 @@
   box-sizing: border-box;
   padding: 6px;
   overflow-x: hidden;
-  background-color: var(--el-bg-color-page);
+
+  // background-color: var(--el-bg-color-page);
+  background-color: transparent;
 }
 .el-footer {
   height: auto;

+ 12 - 17
src/layouts/components/Menu/SubMenu.vue

@@ -34,39 +34,34 @@ const handleClickMenu = (subItem: Menu.MenuOptions) => {
 
 <style lang="scss">
 .el-sub-menu .el-sub-menu__title:hover {
-  color: var(--el-menu-hover-text-color) !important;
+  color: var(--el-menu-active-color) !important;
   background-color: var(--el-menu-active-bg-color) !important;
 }
+.el-menu--horizontal > .el-sub-menu .el-sub-menu__title {
+  color: #7fffff !important;
+}
 .el-sub-menu.is-active > .el-sub-menu__title {
   color: var(--el-menu-active-color) !important;
-  background-color: var(--el-menu-bg-color) !important;
+  background-color: var(--el-menu-active-bg-color) !important;
 }
 .el-menu--collapse {
   .is-active {
     .el-sub-menu__title {
-      color: #ffffff !important;
-      background-color: var(--el-color-primary) !important;
+      color: var(--el-menu-active-color) !important;
+      background-color: var(--el-menu-active-bg-color) !important;
     }
   }
 }
 .el-menu-item {
   &:hover {
-    color: var(--el-menu-hover-text-color) !important;
-    background-color: var(--el-menu-active-bg-color) !important;
-  }
-  &.is-active {
     color: var(--el-menu-active-color) !important;
     background-color: var(--el-menu-active-bg-color) !important;
-    &::before {
-      position: absolute;
-      top: 0;
-      bottom: 0;
-      width: 6px;
-      content: '';
-      background-color: var(--el-color-primary);
-      border-radius: 6px;
-    }
   }
+
+  // &.is-active {
+  //   color: var(--el-menu-active-color) !important;
+  //   background-color: var(--el-menu-active-bg-color) !important;
+  // }
 }
 .vertical,
 .classic,

+ 9 - 4
src/layouts/components/Tabs/index.scss

@@ -1,5 +1,7 @@
 .tabs-box {
-  background-color: var(--el-bg-color);
+  background-color: #0088cc;
+
+  // background-color: transparent;
   .tabs-menu {
     position: relative;
     width: 100%;
@@ -8,19 +10,21 @@
       top: 0;
       right: 0;
       bottom: 0;
+      background: rgb(127 255 255 / 20%);
       .more-button {
         display: flex;
         align-items: center;
         justify-content: center;
         width: 43px;
         cursor: pointer;
-        border-left: 1px solid var(--el-border-color-light);
+        border-left: 1px solid #4ca6ff;
         transition: all 0.3s;
         &:hover {
-          background-color: var(--el-color-info-light-9);
+          background-color: rgb(127 255 255 / 20%);
         }
         .iconfont {
           font-size: 12.5px;
+          color: #7fffff;
         }
       }
     }
@@ -30,6 +34,7 @@
         height: 40px;
         padding: 0 10px;
         margin: 0;
+        border-bottom: #4ca6ff;
         .el-tabs__nav-wrap {
           position: absolute;
           width: calc(100% - 70px);
@@ -40,7 +45,7 @@
               display: flex;
               align-items: center;
               justify-content: center;
-              color: #afafaf;
+              color: #7fffff;
               border: none;
               .tabs-icon {
                 margin: 1.5px 4px 0 0;

+ 1 - 2
src/main.ts

@@ -39,7 +39,6 @@ import SvgIcon from '@/components/SvgIcon/index.vue'
 import DictTag from '@/components/DictTag/index.vue'
 
 import { useDict } from '@/utils/dict'
-import DataVVue3 from '@kjgl77/datav-vue3'
 const app = createApp(App)
 
 // 全局方法挂载
@@ -56,4 +55,4 @@ Object.keys(Icons).forEach(key => {
 // eslint-disable-next-line vue/component-definition-name-casing
 app.component('svg-icon', SvgIcon)
 
-app.use(ElementPlus).use(directives).use(router).use(I18n).use(pinia).use(DataVVue3).mount('#app')
+app.use(ElementPlus).use(directives).use(router).use(I18n).use(pinia).mount('#app')

+ 1 - 1
src/stores/modules/global.ts

@@ -39,7 +39,7 @@ export const useGlobalStore = defineStore('admin-global', {
     // 标签页图标
     tabsIcon: true,
     // 页脚
-    footer: false
+    footer: true
   }),
   getters: {},
   actions: {

+ 1 - 1
src/stores/modules/user.ts

@@ -3,7 +3,7 @@ import { UserState } from '@/stores/interface'
 import piniaPersistConfig from '@/stores/helper/persist'
 import { getToken, setToken, removeToken } from '@/utils/token'
 import { loginApi, getInfoApi, logoutApi } from '@/api/modules/login'
-import defAva from '@/assets/images/defAva.png'
+import defAva from '@/assets/images/touxiang.png'
 import { Login } from '@/api/interface/index'
 export const useUserStore = defineStore('admin-user', {
   state: (): UserState => ({

+ 30 - 12
src/styles/element-dark.scss

@@ -1,28 +1,46 @@
 /* 自定义 element 暗黑模式 */
+html {
+  --table-border-color: #7fffff;
+}
 html.dark {
+  --el-fill-color-light: transparent;
+  --el-border-color: #90fdfd;
+  --el-border-color-hover: #7fffff;
+  --el-text-color-placeholder: #abf2f2;
+
+  // --el-bg-color-overlay: transparent;
+
+  // --el-bg-color: transparent;
+
   /* wangEditor */
   --w-e-toolbar-color: #eeeeee;
   --w-e-toolbar-bg-color: #141414;
   --w-e-textarea-bg-color: #141414;
   --w-e-textarea-color: #eeeeee;
   --w-e-toolbar-active-bg-color: #464646;
+  --el-header-text-color: #7fffff;
+  --table-border-color: #7fffff;
   --w-e-toolbar-border-color: var(--el-border-color-darker);
+  --el-table-border-color: #4ca6ff;
   .w-e-bar-item button:hover,
   .w-e-menu-tooltip-v5::before {
     color: #eeeeee;
   }
+  .el-card {
+    --el-card-bg-color: transparent;
+  }
 
   /* login */
-  .login-container {
-    background-color: #191919 !important;
-    .login-box {
-      background-color: rgb(0 0 0 / 80%) !important;
-      .login-form {
-        box-shadow: rgb(255 255 255 / 12%) 0 2px 10px 2px !important;
-        .logo-text {
-          color: var(--el-text-color-primary) !important;
-        }
-      }
-    }
-  }
+  // .login-container {
+  //   background-color: #191919 !important;
+  //   .login-box {
+  //     background-color: rgb(0 0 0 / 80%) !important;
+  //     .login-form {
+  //       box-shadow: rgb(255 255 255 / 12%) 0 2px 10px 2px !important;
+  //       .logo-text {
+  //         color: var(--el-text-color-primary) !important;
+  //       }
+  //     }
+  //   }
+  // }
 }

+ 64 - 18
src/styles/element.scss

@@ -1,27 +1,33 @@
 /* 设置 notification、message 层级在 loading 之上 */
 .el-message,
 .el-notification {
-  z-index: 2070 !important;
+  z-index: 2070 !important ;
 }
+.el-pagination {
+  --el-pagination-button-bg-color: transparent;
+}
+
 label {
   font-weight: 700;
 }
+.el-button--primary,
+.el-button--primary.is-plain {
+  --el-button-text-color: #0a1f33;
 
-// .label-span {
-//   display: inline-block;
-//   overflow: hidden;
-//   text-overflow: ellipsis;
-//   white-space: nowrap;
-//   cursor: pointer;
-// }
+  background: linear-gradient(0deg, #4ca6ff 0%, #7fffff 100%);
+}
 .el-form-item__label {
-  // display: list-item;
-  // overflow: hidden;
   font-weight: 700;
-
-  // text-overflow: ellipsis;
-  // white-space: nowrap;
+  color: #7fffff;
 }
+.el-form-item__content {
+  border-color: #7fffff !important;
+}
+.el-form-item--default {
+  --font-size: 14px;
+  --el-form-label-font-size: var(--font-size);
+}
+
 .dialog-slot-c {
   .el-tabs__content {
     max-height: 52vh;
@@ -78,8 +84,8 @@ label {
   box-sizing: border-box;
   padding: 12px;
   overflow-x: hidden;
-  background-color: var(--el-bg-color);
-  border: 1px solid var(--el-border-color-light);
+  background-color: transparent;
+  border: 1px solid rgb(76 166 255 / 40%) !important;
   border-radius: 6px;
   box-shadow: 0 0 12px rgb(0 0 0 / 5%);
 }
@@ -223,9 +229,28 @@ label {
     }
   }
 
+  // .is-scrolling-middle {
+  .el-table-fixed-column--right {
+    --el-table-tr-bg-color: rgb(0 136 204 / 40%) !important;
+
+    background-image: url('@/assets/images/bg0.png') !important;
+  }
+
+  .el-table-fixed-column--left {
+    --el-table-tr-bg-color: rgb(0 136 204 / 40%) !important;
+
+    background-image: url('@/assets/images/bg0.png') !important;
+  }
+
   // el-table 表格样式
   .el-table {
     flex: 1;
+    color: #7fffff;
+
+    // background-color: transparent;
+
+    --el-table-border-color: rgb(76 166 255 / 40%);
+    --el-table-tr-bg-color: rgb(0 136 204 / 40%);
 
     // 修复 safari
     table {
@@ -233,14 +258,21 @@ label {
     }
     .el-table__header th {
       height: 45px;
-      font-size: 15px;
+      font-size: 17px;
       font-weight: bold;
-      color: var(--el-text-color-primary);
+
+      // color: var(--el-text-color-primary);
+      color: #7fffff;
       background: var(--el-fill-color-light);
+
+      // background-color: #7fffff;
+
+      // background-color: transparent;
     }
     .el-table__row {
       height: 45px;
       font-size: 14px;
+      background-color: transparent;
       .move {
         cursor: move;
         .el-icon {
@@ -253,6 +285,7 @@ label {
     .el-table__header .el-table__cell > .cell {
       // white-space: nowrap;
       white-space: wrap;
+      background-color: transparent;
     }
 
     // 解决表格数据为空时样式不居中问题(仅在element-plus中)
@@ -284,28 +317,37 @@ label {
 
 /* el-table 组件大小 */
 .el-table--small {
+  background-color: transparent;
   .el-table__header th {
     height: 40px !important;
     font-size: 14px !important;
+    background-color: transparent;
   }
   .el-table__row {
     height: 40px !important;
     font-size: 13px !important;
+    background-color: transparent;
   }
 }
 .el-table--large {
   .el-table__header th {
     height: 50px !important;
     font-size: 16px !important;
+    background-color: transparent;
   }
   .el-table__row {
     height: 50px !important;
     font-size: 15px !important;
+    background-color: transparent;
   }
 }
 
 /* el-drawer */
 .el-drawer {
+  background-image: url('@/assets/images/bg0.png');
+  background-repeat: repeat;
+
+  // background-color: transparent;
   .el-drawer__header {
     padding: 16px 20px;
     margin-bottom: 0;
@@ -341,6 +383,10 @@ label {
 
 /* el-dialog */
 .el-dialog {
+  background-image: url('@/assets/images/bg0.png');
+  background-repeat: repeat;
+
+  // background-size: contain;
   border-radius: 6px;
   .el-dialog__header {
     padding: 15px 20px;
@@ -352,7 +398,7 @@ label {
     // border-top-left-radius: 6px;
     // border-top-right-radius: 6px;
     .el-dialog__title {
-      font-size: 18px;
+      font-size: 20px;
 
       // color: var(--el-dialog-bg-color);
     }

+ 1 - 0
src/typings/ProForm.d.ts

@@ -66,6 +66,7 @@ declare namespace ProForm {
     rules?: FormItemRule[]
     span?: number // 表单col宽度
     show?: (params?: any) => Promise<any> | boolean | string // 是否显示 默认显示
+    change?: (item: any, params?: any) => void // 值改变时触发
     /** 表单组件配置项 */
     compOptions: CompAttributes // 表单组件配置项
   }

+ 72 - 10
src/views/demo/AlgorithmConfigTrack/index.vue

@@ -166,19 +166,47 @@ const columns = reactive<ColumnProps<any>[]>([
     }
   },
   {
-    prop: 'algorithmAddress',
-    label: '算法地址',
+    prop: 'startApi',
+    label: '开始api',
     search: {
       el: 'input'
     }
   },
   {
-    prop: 'parameterConfig',
+    prop: 'pauseApi',
+    label: '暂停api',
+    search: {
+      el: 'input'
+    }
+  },
+  {
+    prop: 'terminateApi',
+    label: '终止api',
+    search: {
+      el: 'input'
+    }
+  },
+  {
+    prop: 'parameters',
     label: '参数配置',
     search: {
       el: 'input'
     }
   },
+  // {
+  //   prop: 'algorithmAddress',
+  //   label: '算法地址',
+  //   search: {
+  //     el: 'input'
+  //   }
+  // },
+  // {
+  //   prop: 'parameterConfig',
+  //   label: '参数配置',
+  //   search: {
+  //     el: 'input'
+  //   }
+  // },
   {
     prop: 'remarks',
     label: '备注',
@@ -237,23 +265,57 @@ const setItemsOptions = () => {
       }
     },
     {
-      label: '算法地址',
-      prop: 'algorithmAddress',
-      rules: [{ required: true, message: '算法地址不能为空', trigger: 'blur' }],
+      label: '开始api',
+      prop: 'startApi',
+      rules: [{ required: true, message: '开始api不能为空', trigger: 'blur' }],
+      compOptions: {
+        placeholder: '请输入开始api'
+      }
+    },
+    {
+      label: '暂停api',
+      prop: 'pauseApi',
+      rules: [{ required: false, message: '暂停api不能为空', trigger: 'blur' }],
       compOptions: {
-        placeholder: '请输入算法地址'
+        placeholder: '请输入暂停api'
+      }
+    },
+    {
+      label: '终止api',
+      prop: 'terminateApi',
+      rules: [{ required: true, message: '终止api不能为空', trigger: 'blur' }],
+      compOptions: {
+        placeholder: '请输入终止api'
       }
     },
     {
       label: '参数配置',
-      prop: 'parameterConfig',
-      rules: [{ required: true, message: '参数配置不能为空', trigger: 'blur' }],
+      prop: 'parameters',
+      rules: [{ required: false, message: '参数配置不能为空', trigger: 'blur' }],
       compOptions: {
         type: 'textarea',
         clearable: true,
-        placeholder: '请输入内容'
+        placeholder: '请输入参数配置'
       }
     },
+    // {
+    //   label: '算法地址',
+    //   prop: 'algorithmAddress',
+    //   rules: [{ required: true, message: '算法地址不能为空', trigger: 'blur' }],
+    //   compOptions: {
+    //     placeholder: '请输入算法地址'
+    //   }
+    // },
+    // {
+    //   label: '参数配置',
+    //   prop: 'parameterConfig',
+    //   rules: [{ required: true, message: '参数配置不能为空', trigger: 'blur' }],
+    //   compOptions: {
+    //     type: 'textarea',
+    //     clearable: true,
+    //     placeholder: '请输入内容'
+    //   }
+    // },
     {
       label: '备注',
       prop: 'remarks',

+ 59 - 35
src/views/demo/AlgorithmModelTrack/index.vue

@@ -70,7 +70,7 @@ import {
 } from '@/api/modules/demo/AlgorithmModelTrack'
 
 import { enumAlgorithmConfigTrackApi } from '@/api/modules/demo/AlgorithmConfigTrack'
-import { AlgorithmType, SubSystem, enumsModelStatus, enumsAlgorithmType, enumsSubSystem } from '@/views/demo/utils'
+import { AlgorithmType, SubSystem, enumsModelStatus, enumsAlgorithmType, enumsSubSystem, AlgorithmType2 } from '@/views/demo/utils'
 
 // ProTable 实例
 const proTable = ref<ProTableInstance>()
@@ -148,16 +148,16 @@ const columns = reactive<ColumnProps<any>[]>([
     },
     minWidth: 200
   },
-  {
-    prop: 'type',
-    label: '类型',
-    tag: true,
-    enum: enumsAlgorithmType,
-    search: {
-      el: 'select'
-    },
-    width: 120
-  },
+  // {
+  //   prop: 'type',
+  //   label: '类型',
+  //   tag: true,
+  //   enum: enumsAlgorithmType,
+  //   search: {
+  //     el: 'select'
+  //   },
+  //   width: 120
+  // },
   //   {
   //     prop: 'parentId',
   //     label: '父id',
@@ -176,16 +176,16 @@ const columns = reactive<ColumnProps<any>[]>([
     },
     width: 120
   },
-  {
-    prop: 'modelStatus',
-    label: '模型状态',
-    tag: true,
-    enum: enumsModelStatus,
-    search: {
-      el: 'select'
-    },
-    width: 120
-  },
+  // {
+  //   prop: 'modelStatus',
+  //   label: '模型状态',
+  //   tag: true,
+  //   enum: enumsModelStatus,
+  //   search: {
+  //     el: 'select'
+  //   },
+  //   width: 120
+  // },
   //   {
   //     prop: 'sampleNumber',
   //     label: '训练样本数',
@@ -204,11 +204,19 @@ const columns = reactive<ColumnProps<any>[]>([
   //   },
   {
     prop: 'modelAddress',
-    label: '模型',
+    label: '模型地址',
     search: {
       el: 'input'
     },
-    width: 120
+    width: 240
+  },
+  {
+    prop: 'algorithmParameters',
+    label: '算法参数',
+    search: {
+      el: 'input'
+    },
+    width: 200
   },
   {
     prop: 'remarks',
@@ -228,6 +236,7 @@ const columns = reactive<ColumnProps<any>[]>([
   //   },
   { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
 ])
+
 // 表单配置项
 let itemsOptions: ProForm.ItemsOptions[] = []
 
@@ -235,21 +244,16 @@ const enumsAlgorithmConfigTrack = ref<any>([])
 
 onMounted(async () => {
   const result: any = await enumAlgorithmConfigTrackApi()
-  // console.log(result)
-  // console.log(result['data'])
+  const tmp = []
   for (let item of result['data']) {
-    // console.log(item)
-    // console.log(item['type'])
-    // console.log(item['subsystem'])
-    // console.log(AlgorithmType[item['type']])
-    // console.log(SubSystem[item['subsystem']])
-    // console.log(AlgorithmType)
-    // console.log(SubSystem)
-    // console.log('-------------------')
-    item['label'] = item['label'] + '-' + SubSystem[item['subsystem']] + '-' + AlgorithmType[item['type']]
+    if (item['type'] == AlgorithmType2['预测/推理']) {
+      const tmpItem = { ...item }
+      tmpItem['label'] = item['label'] + '-' + SubSystem[item['subsystem']] + '-' + AlgorithmType[item['type']]
+      tmp.push(tmpItem)
+    }
   }
 
-  enumsAlgorithmConfigTrack.value = result['data']
+  enumsAlgorithmConfigTrack.value = tmp
   return result['data']
 })
 
@@ -273,6 +277,16 @@ const setItemsOptions = () => {
         placeholder: '请输入模型名称'
       }
     },
+    // {
+    //   label: '分系统',
+    //   prop: 'subSystem',
+    //   rules: [{required: true, message: '分系统不能为空', trigger: 'blur'}],
+    //   compOptions: {
+    //     elTagName: 'select',
+    //     placeholder: '请选择分系统',
+    //     enum: enumsSubSystem,
+    //   }
+    // },
     {
       label: '模型',
       prop: 'modelInputOssId',
@@ -300,6 +314,16 @@ const setItemsOptions = () => {
     //     placeholder: '请输入训练循环次数'
     //   }
     // },
+    {
+      label: '算法参数',
+      prop: 'algorithmParameters',
+      rules: [{ required: false, message: '算法参数不能为空', trigger: 'blur' }],
+      compOptions: {
+        type: 'textarea',
+        clearable: true,
+        placeholder: '请输入算法参数'
+      }
+    },
     {
       label: '备注',
       prop: 'remarks',

+ 135 - 27
src/views/demo/TargetDetection/index.vue

@@ -28,10 +28,16 @@
       </template>
       <!-- 表格操作 -->
       <template #operation="scope">
-        <el-button type="primary" link icon="View" v-if="scope.row.algorithmModelId != null" @click="openModelDialog(scope.row)">
-          <!--@click="openStartDialog(scope.row)"  -->
+        <!--        <el-button type="primary" link icon="View" @click="openModelDialog(scope.row)">-->
+        <!--          &lt;!&ndash;@click="openStartDialog(scope.row)"  &ndash;&gt;-->
+        <!--          详情-->
+        <!--        </el-button>-->
+        <el-button type="primary" link icon="View" v-auth="['demo:TargetDetection:query']" @click="openDialog(3, '详情', scope.row)">
           详情
         </el-button>
+        <el-button type="primary" link icon="EditPen" v-auth="['demo:TargetDetection:edit']" @click="openDialog(2, '编辑', scope.row)">
+          编辑
+        </el-button>
         <el-button
           type="primary"
           link
@@ -77,24 +83,6 @@
         >
           模型
         </el-button>
-        <!--        <el-button-->
-        <!--          type="primary"-->
-        <!--          link-->
-        <!--          icon="View"-->
-        <!--          v-auth="['demo:TargetDetection:query']"-->
-        <!--          @click="openDialog(3, '目标检测查看', scope.row)"-->
-        <!--        >-->
-        <!--          查看-->
-        <!--        </el-button>-->
-        <!--        <el-button-->
-        <!--          type="primary"-->
-        <!--          link-->
-        <!--          icon="EditPen"-->
-        <!--          v-auth="['demo:TargetDetection:edit']"-->
-        <!--          @click="openDialog(2, '目标检测编辑', scope.row)"-->
-        <!--        >-->
-        <!--          编辑-->
-        <!--        </el-button>-->
         <el-button type="primary" link icon="Delete" v-auth="['demo:TargetDetection:remove']" @click="deleteTargetDetection(scope.row)">
           删除
         </el-button>
@@ -162,17 +150,25 @@ import {
 } from '@/api/modules/demo/TargetDetection'
 
 import { listDataSeqApi } from '@/api/modules/demo/DataSeq'
-
 import { enumAlgorithmModelTrackApi, getAlgorithmModelTrackApi } from '@/api/modules/demo/AlgorithmModelTrack'
-import { enumAlgorithmConfigTrackApi } from '@/api/modules/demo/AlgorithmConfigTrack'
+import { enumAlgorithmConfigTrackApi, getAlgorithmConfigTrackApi } from '@/api/modules/demo/AlgorithmConfigTrack'
 import { updateTrackSequenceApi } from '@/api/modules/demo/trackSequence'
 import ViewLog from '@/views/demo/components/ViewLog.vue'
 import { AlgorithmType2 } from '@/views/demo/utils'
 import { addAlgorithmModelTrackApi } from '@/api/modules/demo/AlgorithmModelTrack'
-
 import useWebSocketStore from '@/stores/modules/websocket'
 import { resetHeart } from '@/utils/websocket'
 
+import { getDictsApi } from '@/api/modules/system/dictData'
+const zipFileDescDict = ref<any>({})
+onMounted(async () => {
+  const res = await getDictsApi('zip_file_format_description')
+  for (let i = 0; i < res.data.length; i++) {
+    const item = res.data[i]
+    zipFileDescDict.value[item.dictValue] = item.remark
+  }
+})
+
 onMounted(() => {
   const websocketStore = useWebSocketStore()
   websocketStore.websocket.onmessage = (e: any) => {
@@ -192,7 +188,7 @@ onMounted(async () => {
   enumsAlgorithmConfigTrack.value = []
   const tmp_data: any = result['data']
   for (const item of tmp_data) {
-    if (item.subsystem === SubSystem__['目标检测'] && item.type === AlgorithmType2['预测/推理']) {
+    if (item.subsystem === SubSystem__['目标检测']) {
       item['label'] = item['label'] + '-' + SubSystem[item['subsystem']] + '-' + AlgorithmType[item['type']]
       enumsAlgorithmConfigTrack.value.push(item)
     }
@@ -227,7 +223,7 @@ const setItemsOptions222 = () => {
       prop: 'modelName',
       rules: [{ required: true, message: '模型名称不能为空', trigger: 'blur' }],
       compOptions: {
-        disabled: true,
+        disabled: false,
         placeholder: '请输入模型名称'
       }
     },
@@ -294,6 +290,7 @@ const stopTargetDetect = async (params: any) => {
 
 import statusEnums from '@/utils/status'
 import { AlgorithmType, SubSystem, SubSystem__, enumsAlgorithmType, enumsSubSystem } from '@/views/demo/utils'
+import { getDictsApi } from '@/api/modules/system/dictData'
 
 const dowloadTargetDetection = async (params: any) => {
   await useDownload(dowloadTargetDetectionApi, params.name, params.id, true, '.zip')
@@ -368,10 +365,17 @@ 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 getTargetDetectionApi(row?.id || null)
+    res = await getTargetDetectionApi(row.id || null)
+    const params = JSON.parse(res.data['algorithmParameters'])
+    if (params.otherParams) {
+      res.data = { ...res.data, ...params.otherParams }
+    }
   }
   // 重置表单
   setItemsOptions()
+  if (row?.id) {
+    itemsOptions = await updateItemsOptions(row.algorithmId)
+  }
   const params = {
     title,
     width: 580,
@@ -430,6 +434,14 @@ const columns = reactive<ColumnProps<any>[]>([
     label: '模型名称',
     width: 200
   },
+  {
+    prop: 'algorithmParameters',
+    label: '算法参数',
+    search: {
+      el: 'input'
+    },
+    width: 150
+  },
   // {
   //   prop: 'algorithmModelId',
   //   label: '模型',
@@ -516,6 +528,52 @@ onMounted(async () => {
   updateWnumsAlgorithmModelTrack()
 })
 
+const remove_unnecessary_parameters = (itemsOptions: ProForm.ItemsOptions[]): ProForm.ItemsOptions[] => {
+  try {
+    const endIndex = itemsOptions.findIndex(option => option['label'] === '备注')
+    if (endIndex !== -1) {
+      itemsOptions = itemsOptions.slice(0, endIndex + 1)
+    }
+    return itemsOptions
+  } catch (error) {
+    console.error('移除不必要的参数时出错:', error)
+    // ElMessage.error('移除不必要的参数时出错,请检查!');
+    return itemsOptions // 返回原始选项,避免进一步的问题
+  }
+}
+
+const updateItemsOptions = async (algorithmId: any) => {
+  try {
+    const result = await getAlgorithmConfigTrackApi(algorithmId)
+    if (result.code === 200) {
+      // 处理结果
+      const parameters = JSON.parse(result.data['parameters'])
+      // console.log('parameters: ', parameters)
+
+      const itemsOptions_new = remove_unnecessary_parameters(itemsOptions)
+      for (const item of parameters) {
+        // 添加新的表单项选项
+        itemsOptions_new.push({
+          label: item['name'],
+          prop: item['agName'],
+          rules: [{ required: item['required'], message: item['agName'] + '不能为空', trigger: 'blur' }],
+          tooltip: item['prompt'],
+          compOptions: {
+            elTagName: 'input',
+            placeholder: item['defaultValue']
+            // value: item['defaultValue']
+          }
+        })
+      }
+      formDialogRef.value?.updateItemOptions(itemsOptions_new)
+      return itemsOptions_new
+    }
+  } catch (err) {
+    console.log(err)
+    ElMessage.error('获取算法配置失败,请检查!')
+  }
+}
+
 // 表单配置项
 let itemsOptions: ProForm.ItemsOptions[] = []
 const setItemsOptions = () => {
@@ -543,6 +601,7 @@ const setItemsOptions = () => {
       label: '上传数据集',
       prop: 'inputOssId',
       rules: [{ required: true, message: '数据集不能为空', trigger: 'blur' }],
+      tooltip: zipFileDescDict.value['target_detection'],
       compOptions: {
         elTagName: 'file-upload',
         fileSize: 4096,
@@ -550,14 +609,62 @@ const setItemsOptions = () => {
         placeholder: '请上传数据集'
       }
     },
+    {
+      label: '选择算法',
+      prop: 'algorithmId',
+      rules: [{ required: true, message: '算法不能为空', trigger: 'blur' }],
+      compOptions: {
+        elTagName: 'select',
+        placeholder: '请选择算法',
+        enum: enumsAlgorithmConfigTrack,
+        clearable: true,
+        onChange: async (value: any) => {
+          if (value != undefined && value != null && value != '') {
+            await updateItemsOptions(value)
+          }
+        }
+      }
+    },
+    {
+      label: '任务类型',
+      prop: 'type',
+      rules: [{ required: true, message: '任务类型不能为空', trigger: 'blur' }],
+      compOptions: {
+        disabled: true,
+        elTagName: 'select',
+        placeholder: '请选择模任务类型',
+        enum: enumsAlgorithmType,
+        clearable: true,
+        value: ''
+      },
+      show: params => {
+        if (params.value.algorithmId != undefined) {
+          for (let i = 0; i < enumsAlgorithmConfigTrack.value.length; i++) {
+            if (enumsAlgorithmConfigTrack.value[i]['value'] === params.value.algorithmId) {
+              params.value.type = enumsAlgorithmConfigTrack.value[i]['type']
+              return true
+            }
+          }
+        }
+        return false
+      }
+    },
     {
       label: '选择模型',
       prop: 'algorithmModelId',
       rules: [{ required: true, message: '模型不能为空', trigger: 'blur' }],
+      show: params => {
+        if (params.value.type == AlgorithmType2['预测/推理']) {
+          return true
+        }
+        params.value.algorithmModelId = ''
+        return false
+      },
       compOptions: {
         elTagName: 'select',
         placeholder: '请选择模型',
-        enum: enumsAlgorithmModelTrack
+        enum: enumsAlgorithmModelTrack,
+        clearable: true
       }
     },
     {
@@ -565,6 +672,7 @@ const setItemsOptions = () => {
       prop: 'remarks',
       rules: [],
       compOptions: {
+        elTagName: 'input',
         placeholder: '请输入备注'
       }
     }

+ 1231 - 0
src/views/demo/algorithmTaskTrack/index.vue

@@ -0,0 +1,1231 @@
+<template>
+  <div class="table-box">
+    <ProTable ref="proTable" :columns="columns" row-key="id" :request-api="listAlgorithmTaskTrackApi">
+      <!-- 表格 header 按钮 -->
+      <template #tableHeader="scope">
+        <el-button type="primary" v-auth="['demo:algorithmTaskTrack:add']" icon="CirclePlus" @click="dialogVisibleAddTask = true"> 新增 </el-button>
+        <!--        <el-button type="primary" v-auth="['demo:algorithmTaskTrack:import']" icon="Upload" plain @click="batchAdd"> 导入-->
+        <!--        </el-button>-->
+        <!--        <el-button type="primary" v-auth="['demo:algorithmTaskTrack:export']" icon="Download" plain @click="downloadFile"> 导出-->
+        <!--        </el-button>-->
+        <el-button
+          type="danger"
+          v-auth="['demo:algorithmTaskTrack: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:algorithmTaskTrack:query']" @click="openViewDialog(scope.row)"> 查看 </el-button>
+        <!--        <el-button-->
+        <!--          type="primary"-->
+        <!--          link-->
+        <!--          icon="EditPen"-->
+        <!--          v-auth="['demo:algorithmTaskTrack:edit']"-->
+        <!--          @click="openDialog(2, '可辨识性分析总任务编辑', scope.row)"-->
+        <!--        >-->
+        <!--          编辑-->
+        <!--        </el-button>-->
+        <el-button type="primary" link icon="Delete" v-auth="['demo:algorithmTaskTrack:remove']" @click="deleteAlgorithmTaskTrack(scope.row)">
+          删除
+        </el-button>
+      </template>
+    </ProTable>
+    <FormDialog ref="formDialogRef" />
+    <ImportExcel ref="dialogRef" />
+    <el-dialog v-model="dialogVisibleAddTask" title="可辨识性分析总任务新增" width="700" @open="handleOpenAddTask()" :before-close="handleClose">
+      <el-form ref="formAddTaskRef" :model="formAddTask" :rules="rulesAddTask" label-width="auto" style="max-width: 600px">
+        <el-form-item label="任务名称" prop="name">
+          <el-input v-model="formAddTask.name" placeholder="请输入任务名称" />
+        </el-form-item>
+        <el-form-item label="是否转红外" prop="ifToInfrared">
+          <el-checkbox v-model="formAddTask.ifToInfrared" @click="setIfToInfrared()" />
+        </el-form-item>
+        <el-form-item label="选择转红外算法" v-show="formAddTask.ifToInfrared" prop="toInfraredAlgorithmId">
+          <div class="form-item1">
+            <el-select v-model="formAddTask.toInfraredAlgorithmId" placeholder="请选择转红外算法" clearable>
+              <el-option v-for="item in enumsAlgorithmConfigTrack_toInfrared" :key="item.value" :label="item.label" :value="item.value" />
+            </el-select>
+            <el-button
+              @click="setAlgorithmParams(formAddTask.toInfraredAlgorithmId, 'toInfraredAlgorithmParams')"
+              style="margin-left: 10px"
+              :disabled="formAddTask.toInfraredAlgorithmId == undefined || formAddTask.toInfraredAlgorithmId == ''"
+            >
+              <SvgIcon :name="'Setting'" style="margin-right: 5px" />
+              设置算法参数
+            </el-button>
+          </div>
+        </el-form-item>
+        <el-form-item label="选择可见光转红外模型" v-show="formAddTask.ifToInfrared" prop="toInfraredModelId">
+          <el-select v-model="formAddTask.toInfraredModelId" placeholder="请选择可见光转红外模型" clearable>
+            <el-option v-for="item in toInfraredModelList" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="选择数据集" prop="inputDatasetOssId">
+          <el-select v-model="formAddTask.inputDatasetOssId" placeholder="请选择数据集" clearable>
+            <el-option v-for="item in datasetList" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item prop="inputDatasetOssId">
+          <template #label>
+            <el-space :size="4">
+              <span class="label-span">上传数据集</span>
+              <el-tooltip effect="dark" :content="zipFileDescDict.total_task_dataset" placement="top">
+                <i :class="'iconfont icon-yiwen'"></i>
+              </el-tooltip>
+            </el-space>
+          </template>
+          <File ref="fileUploadRef" :file-type="['zip']" :file-size="4096" @update:model-value="fileUploadDatasetChange" />
+        </el-form-item>
+        <el-form-item label="选择视觉算法" prop="trackSequenceAlgorithmId">
+          <div class="form-item1">
+            <el-select v-model="formAddTask.trackSequenceAlgorithmId" placeholder="请选择视觉算法" clearable>
+              <el-option v-for="item in visionAlgorithmList" :key="item.value" :label="item.label" :value="item.value" />
+            </el-select>
+            <el-button
+              @click="setAlgorithmParams(formAddTask.trackSequenceAlgorithmId, 'trackSequenceAlgorithmParams')"
+              style="margin-left: 10px"
+              :disabled="formAddTask.trackSequenceAlgorithmId == undefined || formAddTask.trackSequenceAlgorithmId == ''"
+            >
+              <SvgIcon :name="'Setting'" style="margin-right: 5px" />
+              设置算法参数
+            </el-button>
+          </div>
+        </el-form-item>
+        <el-form-item label="选择目标检测模型" prop="TD_modelId">
+          <el-select v-model="formAddTask.TD_modelId" placeholder="请选择目标检测模型" clearable>
+            <el-option v-for="item in targetDetectionModelList" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="选择视觉算法模型" prop="trackSequenceModelId">
+          <el-select v-model="formAddTask.trackSequenceModelId" placeholder="请选择视觉算法模型" clearable>
+            <el-option v-for="item in visionAlgorithmModelList" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="是否评估" prop="ifEvaluate">
+          <el-checkbox v-model="formAddTask.ifEvaluate" />
+        </el-form-item>
+        <el-form-item prop="inputEvaluateLabelOssId" v-show="formAddTask.ifEvaluate">
+          <template #label>
+            <el-space :size="4">
+              <span class="label-span">上传真实标签</span>
+              <el-tooltip effect="dark" :content="zipFileDescDict.total_task_label" placement="top">
+                <i :class="'iconfont icon-yiwen'"></i>
+              </el-tooltip>
+            </el-space>
+          </template>
+          <File
+            ref="fileUploadEvaluateLabelRef"
+            :model-value="formAddTask.inputEvaluateLabelOssId"
+            :file-type="['txt', 'xlsx', 'xls']"
+            :file-size="4096"
+            @update:model-value="fileUploadChangeEvaluateLabel"
+          />
+        </el-form-item>
+        <el-form-item label="选择视觉评估算法" prop="trackSequenceEvaluateAlgorithmId" v-show="formAddTask.ifEvaluate">
+          <div class="form-item1">
+            <el-select v-model="formAddTask.trackSequenceEvaluateAlgorithmId" placeholder="请选择视觉评估算法" clearable>
+              <el-option v-for="item in visionEvaluateAlgorithmList" :key="item.value" :label="item.label" :value="item.value" />
+            </el-select>
+            <el-button
+              @click="setAlgorithmParams(formAddTask.trackSequenceEvaluateAlgorithmId, 'trackSequenceEvaluateAlgorithmParams')"
+              style="margin-left: 10px"
+              :disabled="formAddTask.trackSequenceEvaluateAlgorithmId == undefined || formAddTask.trackSequenceEvaluateAlgorithmId == ''"
+            >
+              <SvgIcon :name="'Setting'" style="margin-right: 5px" />
+              设置算法参数
+            </el-button>
+          </div>
+        </el-form-item>
+        <el-form-item label="备注" prop="remarks">
+          <el-input v-model="formAddTask.remarks" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="dialogVisibleAddTask = false">取消</el-button>
+        <el-button type="primary" @click="addAlgorithmTaskTrack"> 确定</el-button>
+      </template>
+    </el-dialog>
+    <el-dialog v-model="dialogVisibleView" @open="handleOpenView()" title="可辨识性分析总任务查看" width="90%">
+      <div style="width: 100%; height: auto; overflow: auto">
+        <el-table :data="viewData" border height="500px">
+          <el-table-column prop="id" label="主键ID" width="180" />
+          <el-table-column prop="name" label="任务名称" width="150">
+            <template #default="scope">
+              <el-tooltip :content="scope.row.name" raw-content placement="top-start" v-if="scope.row.name">
+                <span>{{ scope.row.name && scope.row.name.length > 15 ? scope.row.name.substring(0, 15) + '...' : scope.row.name }} </span>
+              </el-tooltip>
+            </template>
+          </el-table-column>
+          <el-table-column prop="status" label="任务状态" width="150">
+            <template #default="scope">
+              <el-tag type="success">
+                {{ Status__[scope.row.status] }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column prop="type" label="类型" width="120">
+            <template #default="scope">
+              <el-tag type="success">
+                {{ AlgorithmType[scope.row.type] }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column prop="subsystem" label="分系统" width="200">
+            <template #default="scope">
+              <el-tag type="success">
+                {{ SubSystem[scope.row.subsystem] }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column prop="algorithmName" label="算法名称" width="200" />
+          <el-table-column prop="modelName" label="模型名称" width="200" />
+          <el-table-column prop="algorithmParameters" label="算法参数" width="150">
+            <template #default="scope">
+              <el-tooltip :content="scope.row.algorithmParameters" raw-content placement="top-start" v-if="scope.row.algorithmParameters">
+                <span
+                  >{{
+                    scope.row.outputPath && scope.row.algorithmParameters.length > 15
+                      ? scope.row.algorithmParameters.substring(0, 15) + '...'
+                      : scope.row.algorithmParameters
+                  }}
+                </span>
+              </el-tooltip>
+            </template>
+          </el-table-column>
+          <el-table-column prop="startTime" label="开始时间" width="180" />
+          <el-table-column prop="endTime" label="结束时间" width="180" />
+          <el-table-column prop="costSecond" label="耗时" width="120" />
+          <el-table-column prop="log" label="日志" width="120">
+            <template #default="scope">
+              <el-tooltip :content="scope.row.log" raw-content placement="top-start" v-if="scope.row.log">
+                <span>{{ scope.row.outputPath && scope.row.log.length > 15 ? scope.row.log.substring(0, 15) + '...' : scope.row.log }} </span>
+              </el-tooltip>
+            </template>
+          </el-table-column>
+          <el-table-column prop="outputPath" label="输出路径" width="120">
+            <template #default="scope">
+              <el-tooltip :content="scope.row.outputPath" raw-content placement="top-start" v-if="scope.row.outputPath">
+                <span
+                  >{{
+                    scope.row.outputPath && scope.row.outputPath.length > 15 ? scope.row.outputPath.substring(0, 15) + '...' : scope.row.outputPath
+                  }}
+                </span>
+              </el-tooltip>
+            </template>
+          </el-table-column>
+          <el-table-column prop="remarks" label="备注" width="120" />
+          <el-table-column prop="operation" label="操作" width="300" fixed="right">
+            <template #default="scope">
+              <el-button
+                type="primary"
+                link
+                icon="View"
+                v-if="scope.row.status == '0' || scope.row.status == '3' || scope.row.status == '4'"
+                @click="startSubTask(scope.row)"
+              >
+                开始
+              </el-button>
+              <el-popconfirm title="确定终止此任务吗?" @confirm="stopSubTask(scope.row)" v-if="scope.row.status == '1'">
+                <template #reference>
+                  <el-button type="primary" link icon="Delete"> 终止</el-button>
+                </template>
+              </el-popconfirm>
+              <el-button type="primary" link icon="View" @click="openLogSubTask(scope.row)" v-if="scope.row.status != '0'"> 日志 </el-button>
+              <el-button
+                type="primary"
+                link
+                icon="View"
+                v-if="scope.row.status == '2' && scope.row.type == AlgorithmType2['预测/推理']"
+                @click="previewSubTask(scope.row)"
+              >
+                预览
+              </el-button>
+              <el-button
+                type="primary"
+                link
+                icon="View"
+                v-if="scope.row.status == '2' && scope.row.type == AlgorithmType2['预测/推理']"
+                @click="showStatisticResultSubTask(scope.row)"
+              >
+                结果
+              </el-button>
+              <el-button
+                type="primary"
+                link
+                icon="View"
+                v-if="scope.row.status == '2' && scope.row.type == AlgorithmType2['测试']"
+                @click="showEvaluateResultSubTask(scope.row)"
+              >
+                结果
+              </el-button>
+              <!-- <el-button
+                type="primary"
+                link
+                icon="View"
+                v-if="scope.row.subsystem === SubSystem__['注释轨迹序列'] &&  scope.row.status == '2' && scope.row.type === AlgorithmType2['预测/推理']"
+                @click="showEvaluateSubTask(scope.row)"
+              >
+                评估
+              </el-button> -->
+              <el-button type="primary" link icon="View" @click="openSubTaskViewDialog(3, '子任务查看', scope.row)"> 查看 </el-button>
+              <el-button type="primary" link icon="EditPen" @click="openSubTaskViewDialog(2, '子任务编辑', scope.row)"> 编辑 </el-button>
+              <el-button type="danger" link icon="Delete" @click="deletSubTask(scope.row)"> 删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </el-dialog>
+    <ViewLog ref="viewLogRef" />
+    <PreviewCompareImages ref="previewImagesRef" />
+    <ShowStatisticResult ref="showStatisticResultRef" />
+  </div>
+</template>
+
+<script setup lang="tsx" name="AlgorithmTaskTrack">
+import { ref, reactive, onMounted } 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 { ProTableInstance, ColumnProps } from '@/components/ProTable/interface'
+import {
+  listAlgorithmTaskTrackApi,
+  delAlgorithmTaskTrackApi,
+  addAlgorithmTaskTrackApi,
+  updateAlgorithmTaskTrackApi,
+  importTemplateApi,
+  importAlgorithmTaskTrackDataApi,
+  exportAlgorithmTaskTrackApi,
+  getAlgorithmTaskTrackApi,
+  listSubTaskAlgorithmTaskTrackApi
+} from '@/api/modules/demo/algorithmTaskTrack'
+import { AlgorithmType, AlgorithmType2, enumsAlgorithmType, enumsSubSystem, Status__, SubSystem, SubSystem__ } from '@/views/demo/utils'
+import { enumAlgorithmConfigTrackApi, getAlgorithmConfigTrackApi } from '@/api/modules/demo/AlgorithmConfigTrack'
+import SvgIcon from '@/components/SvgIcon/index.vue'
+import { listDataSeqApi } from '@/api/modules/demo/DataSeq'
+import File from '@/components/Upload/File.vue'
+import { enumAlgorithmModelTrackApi } from '@/api/modules/demo/AlgorithmModelTrack'
+import statusEnums from '@/utils/status'
+import {
+  addTrackSequenceApi,
+  delTrackSequenceApi,
+  getLogTrackSequenceApi,
+  getStatisticsResultTrackSequenceApi,
+  getTrackSequenceApi,
+  previewEvaluateTrackSequenceApi,
+  previewPredictResultTrackSequenceModelApi,
+  startTrackSequenceApi,
+  stopTrackSequenceApi,
+  updateTrackSequenceApi
+} from '@/api/modules/demo/trackSequence'
+import {
+  delToInfraredApi,
+  getLogToInfraredApi,
+  getStatisticsResultToInfraredApi,
+  getToInfraredApi,
+  previewPredictResultToInfraredModelApi,
+  startToInfraredApi,
+  stopToInfraredApi,
+  updateToInfraredApi
+} from '@/api/modules/demo/toInfrared'
+import {
+  getLogTargetDetectionApi,
+  getTargetDetectionApi,
+  startTargetDetectionApi,
+  stopTargetDetectionApi,
+  updateTargetDetectionApi
+} from '@/api/modules/demo/TargetDetection'
+import { delDataAugmentationApi } from '@/api/modules/demo/dataAugmentation'
+import ViewLog from '@/views/demo/components/ViewLog.vue'
+import PreviewCompareImages from '@/views/demo/components/PreviewCompareImages.vue'
+import ShowStatisticResult from '@/views/demo/components/ShowStatisticResult.vue'
+import useWebSocketStore from '@/stores/modules/websocket'
+import { resetHeart } from '@/utils/websocket'
+
+import { getDictsApi } from '@/api/modules/system/dictData'
+
+const zipFileDescDict = ref<any>({})
+onMounted(async () => {
+  const res = await getDictsApi('zip_file_format_description')
+  for (let i = 0; i < res.data.length; i++) {
+    const item = res.data[i]
+    zipFileDescDict.value[item.dictValue] = item.remark
+  }
+})
+
+onMounted(() => {
+  const websocketStore = useWebSocketStore()
+  websocketStore.websocket.onmessage = (e: any) => {
+    if (e.data.indexOf('heartbeat') > 0) {
+      resetHeart()
+    }
+    if (e.data.indexOf('ping') > 0) {
+      return
+    }
+    console.log(e)
+    handleOpenView()
+  }
+})
+
+const startSubTask = async (row: any) => {
+  let res: any = null
+  if (row.subsystem === SubSystem__['可见光转红外']) {
+    res = await startToInfraredApi(row.id)
+  } else if (row.subsystem === SubSystem__['目标检测']) {
+    res = await startTargetDetectionApi(row.id)
+  } else if (row.subsystem === SubSystem__['注释轨迹序列']) {
+    res = await startTrackSequenceApi(row.id)
+  } else {
+    ElMessage.error('暂不支持该子任务类型')
+    return
+  }
+  if (res.code === 200) {
+    ElMessage.success('任务已开始,请等待完成!')
+  } else {
+    ElMessage.error('任务开始失败,请检查!')
+  }
+  handleOpenView()
+}
+const stopSubTask = async (row: any) => {
+  let res: any = null
+  if (row.subsystem === SubSystem__['可见光转红外']) {
+    res = await stopToInfraredApi(row.id)
+  } else if (row.subsystem === SubSystem__['目标检测']) {
+    res = await stopTargetDetectionApi(row.id)
+  } else if (row.subsystem === SubSystem__['注释轨迹序列']) {
+    res = await stopTrackSequenceApi(row.id)
+  } else {
+    ElMessage.error('暂不支持该子任务类型')
+    return
+  }
+  if (res.code === 200) {
+    ElMessage.success('终止任务成功!')
+  } else {
+    ElMessage.error('终止任务失败,请检查!')
+  }
+  handleOpenView()
+}
+
+const viewLogRef = ref()
+const openLogSubTask = async (row: any) => {
+  if (row.subsystem === SubSystem__['可见光转红外']) {
+    viewLogRef.value.handleOpen(row.id, getLogToInfraredApi)
+  } else if (row.subsystem === SubSystem__['目标检测']) {
+    viewLogRef.value.handleOpen(row.id, getLogTargetDetectionApi)
+  } else if (row.subsystem === SubSystem__['注释轨迹序列']) {
+    viewLogRef.value.handleOpen(row.id, getLogTrackSequenceApi)
+  } else {
+    ElMessage.error('暂不支持该子任务类型')
+    return
+  }
+}
+const previewImagesRef = ref()
+const previewSubTask = async (row: any) => {
+  if (row.subsystem === SubSystem__['可见光转红外']) {
+    previewImagesRef.value?.handleOpen(previewPredictResultToInfraredModelApi, row.id)
+  } else if (row.subsystem === SubSystem__['目标检测']) {
+    ElMessage.error('暂不支持该子任务类型')
+    return
+  } else if (row.subsystem === SubSystem__['注释轨迹序列']) {
+    previewImagesRef.value?.handleOpen(previewPredictResultTrackSequenceModelApi, row.id)
+  } else {
+    ElMessage.error('暂不支持该子任务类型')
+    return
+  }
+}
+const showStatisticResultRef = ref()
+const showStatisticResultSubTask = async (row: any) => {
+  if (row.subsystem === SubSystem__['可见光转红外']) {
+    showStatisticResultRef.value.get_statistics_result(row.id, getStatisticsResultToInfraredApi)
+  } else if (row.subsystem === SubSystem__['目标检测']) {
+    ElMessage.error('暂不支持该子任务类型')
+    return
+  } else if (row.subsystem === SubSystem__['注释轨迹序列']) {
+    showStatisticResultRef.value.get_statistics_result(row.id, getStatisticsResultTrackSequenceApi)
+  } else {
+    ElMessage.error('暂不支持该子任务类型')
+    return
+  }
+}
+const showEvaluateResultSubTask = async (row: any) => {
+  console.log('=============')
+  console.log(row.subsystem)
+  if (row.subsystem === SubSystem__['可见光转红外']) {
+    ElMessage.error('暂不支持该子任务类型')
+    return
+  } else if (row.subsystem === SubSystem__['目标检测']) {
+    ElMessage.error('暂不支持该子任务类型')
+    return
+  } else if (row.subsystem === SubSystem__['注释轨迹序列']) {
+    showStatisticResultRef.value.get_statistics_result(row.id, previewEvaluateTrackSequenceApi, '评估结果')
+  } else {
+    ElMessage.error('暂不支持该子任务类型')
+    return
+  }
+}
+const showEvaluateSubTask = async (row: any) => {}
+
+const deletSubTask = async (row: any) => {
+  if (row.subsystem === SubSystem__['可见光转红外']) {
+    await useHandleData(delToInfraredApi, row.id, '删除【' + row.name + '】可见光转红外')
+  } else if (row.subsystem === SubSystem__['目标检测']) {
+    await useHandleData(delDataAugmentationApi, row.id, '删除任务【' + row.name + '】目标检测')
+  } else if (row.subsystem === SubSystem__['注释轨迹序列']) {
+    await useHandleData(delTrackSequenceApi, row.id, '删除【' + row.name + '】注视轨迹序列')
+  } else {
+    ElMessage.error('暂不支持该子任务类型')
+  }
+  handleOpenView()
+}
+
+const loadSomeData = async (row?: any) => {
+  datasetList.value = await getDatasetList()
+  if (row.subsystem === SubSystem__['可见光转红外']) {
+    enumsAlgorithmConfigTrack_toInfrared.value = await getEnumsAlgorithmConfigTrack('可见光转红外', ['预测/推理'])
+    await getToInfraredModelList()
+  } else if (row.subsystem === SubSystem__['目标检测']) {
+  } else if (row.subsystem === SubSystem__['注释轨迹序列']) {
+    enumsAlgorithmConfigTrack_trackSequence.value = await getEnumsAlgorithmConfigTrack('注释轨迹序列', [AlgorithmType[row.type]])
+    enumsAlgorithmModelTrack.value = await getEnumsAlgorithmModelTrack('注释轨迹序列')
+    enumsAlgorithmModelTrack_TD.value = await getEnumsAlgorithmModelTrack('目标检测')
+  }
+}
+
+const openSubTaskViewDialog = async (type: number, title: string, row?: any) => {
+  let res = { data: {} }
+  let api: any = null
+  if (row?.id) {
+    console.log(row)
+    if (row.subsystem === SubSystem__['可见光转红外']) {
+      console.log('可见光转红外')
+      res = await getToInfraredApi(row.id || null)
+      api = updateToInfraredApi
+
+      // 重置表单
+      setItemsOptions_ToInfrared()
+    } else if (row.subsystem === SubSystem__['目标检测']) {
+      console.log('目标检测')
+      res = await getTargetDetectionApi(row.id || null)
+      api = updateTargetDetectionApi
+    } else if (row.subsystem === SubSystem__['注释轨迹序列']) {
+      console.log('注释轨迹序列')
+      res = await getTrackSequenceApi(row.id || null)
+      api = updateTrackSequenceApi
+
+      // 重置表单
+      setItemsOptions_TrackSequence()
+    } else {
+      console.log('其他')
+      ElMessage.error('暂不支持该子任务类型')
+      return
+    }
+    const params = JSON.parse(res.data['algorithmParameters'])
+    if (params.otherParams) {
+      res.data = { ...res.data, ...params.otherParams }
+    }
+  }
+
+  if (row?.id) {
+    itemsOptions = await updateItemsOptions(row.algorithmId)
+  }
+  await loadSomeData(row)
+  const params = {
+    title: title,
+    width: 600,
+    isEdit: type !== 3,
+    itemsOptions: itemsOptions,
+    model: res.data,
+    api: api,
+    getTableList: handleOpenView
+  }
+  formDialogRef.value?.openDialog(params)
+}
+
+const remove_unnecessary_parameters = (itemsOptions: ProForm.ItemsOptions[]): ProForm.ItemsOptions[] => {
+  try {
+    const endIndex = itemsOptions.findIndex(option => option['label'] === '备注')
+    if (endIndex !== -1) {
+      itemsOptions = itemsOptions.slice(0, endIndex + 1)
+    }
+    return itemsOptions
+  } catch (error) {
+    console.error('移除不必要的参数时出错:', error)
+    // ElMessage.error('移除不必要的参数时出错,请检查!');
+    return itemsOptions // 返回原始选项,避免进一步的问题
+  }
+}
+
+const updateItemsOptions = async (algorithmId: any) => {
+  try {
+    const result = await getAlgorithmConfigTrackApi(algorithmId)
+    if (result.code === 200) {
+      // 处理结果
+      const parameters = JSON.parse(result.data['parameters'])
+      // console.log('parameters: ', parameters)
+
+      const itemsOptions_new = remove_unnecessary_parameters(itemsOptions)
+      for (const item of parameters) {
+        // 添加新的表单项选项
+        itemsOptions_new.push({
+          label: item['name'],
+          prop: item['agName'],
+          rules: [{ required: item['required'], message: item['agName'] + '不能为空', trigger: 'blur' }],
+          tooltip: item['prompt'],
+          compOptions: {
+            elTagName: 'input',
+            placeholder: item['defaultValue']
+            // value: item['defaultValue']
+          }
+        })
+      }
+      formDialogRef.value?.updateItemOptions(itemsOptions_new)
+      return itemsOptions_new
+    } else {
+      return itemsOptions // 返回原始选项,避免进一步的问题
+    }
+  } catch (err) {
+    console.log(err)
+    ElMessage.error('获取算法配置失败,请检查!')
+    return itemsOptions // 返回原始选项,避免进一步的问题
+  }
+}
+
+const setItemsOptions_ToInfrared = () => {
+  itemsOptions = [
+    {
+      label: '任务名称',
+      prop: 'name',
+      rules: [{ required: true, message: '任务名称不能为空', trigger: 'blur' }],
+      compOptions: {
+        elTagName: 'input',
+        placeholder: '请输入任务名称'
+      }
+    },
+    {
+      label: '选择数据集',
+      prop: 'inputOssId',
+      rules: [{ required: false, message: '数据集不能为空', trigger: 'blur' }],
+      compOptions: {
+        elTagName: 'select',
+        placeholder: '请选择或者上传数据集',
+        enum: datasetList,
+        clearable: true
+      }
+    },
+    {
+      label: '上传数据集',
+      prop: 'inputOssId',
+      rules: [{ required: false, message: '数据集不能为空', trigger: 'blur' }],
+      compOptions: {
+        elTagName: 'file-upload',
+        fileSize: 4096,
+        fileType: ['zip'],
+        placeholder: '请上传数据集'
+      }
+    },
+    {
+      label: '选择算法',
+      prop: 'algorithmId',
+      rules: [{ required: true, message: '算法不能为空', trigger: 'blur' }],
+      compOptions: {
+        elTagName: 'select',
+        placeholder: '请选择算法',
+        enum: enumsAlgorithmConfigTrack_toInfrared,
+        clearable: true,
+        onChange: async (value: any) => {
+          if (value != undefined && value != null && value != '') {
+            await updateItemsOptions(value)
+          }
+        }
+      }
+    },
+    {
+      label: '任务类型',
+      prop: 'type',
+      rules: [{ required: true, message: '任务类型不能为空', trigger: 'blur' }],
+      compOptions: {
+        disabled: true,
+        elTagName: 'select',
+        placeholder: '请选择任务类型',
+        enum: enumsAlgorithmType,
+        clearable: true,
+        value: ''
+      },
+      show: params => {
+        if (params.value.algorithmId != undefined) {
+          for (let i = 0; i < enumsAlgorithmConfigTrack_toInfrared.value.length; i++) {
+            if (enumsAlgorithmConfigTrack_toInfrared.value[i]['value'] === params.value.algorithmId) {
+              params.value.type = enumsAlgorithmConfigTrack_toInfrared.value[i]['type']
+              return true
+            }
+          }
+        }
+        return false
+      }
+    },
+    {
+      label: '选择模型',
+      prop: 'algorithmModelId',
+      rules: [{ required: true, message: '模型不能为空', trigger: 'blur' }],
+      show: params => {
+        if (params.value.type == AlgorithmType2['预测/推理']) {
+          return true
+        }
+        return false
+      },
+      compOptions: {
+        elTagName: 'select',
+        placeholder: '请选择模型',
+        enum: toInfraredModelList,
+        clearable: true
+      }
+    },
+    {
+      label: '备注',
+      prop: 'remarks',
+      rules: [],
+      compOptions: {
+        elTagName: 'input',
+        placeholder: '请输入备注'
+      }
+    }
+  ]
+}
+const enumsAlgorithmConfigTrack_trackSequence = ref<any[]>([])
+const enumsAlgorithmModelTrack = ref<any[]>([])
+const enumsAlgorithmModelTrack_TD = ref<any[]>([])
+const setItemsOptions_TrackSequence = () => {
+  itemsOptions = [
+    {
+      label: '任务名称',
+      prop: 'name',
+      rules: [{ required: true, message: '任务名称不能为空', trigger: 'blur' }],
+      compOptions: {
+        placeholder: '请输入任务名称'
+      }
+    },
+    {
+      label: '选择数据集',
+      prop: 'inputOssId',
+      rules: [{ required: false, message: '数据集不能为空', trigger: 'blur' }],
+      compOptions: {
+        elTagName: 'select',
+        placeholder: '请选择或者上传数据集',
+        enum: datasetList,
+        clearable: true
+      }
+    },
+    {
+      label: '上传数据集',
+      prop: 'inputOssId',
+      rules: [{ required: false, message: '数据集不能为空', trigger: 'blur' }],
+      compOptions: {
+        elTagName: 'file-upload',
+        fileSize: 4096,
+        fileType: ['zip'],
+        placeholder: '请上传数据集'
+      }
+    },
+    {
+      label: '选择算法',
+      prop: 'algorithmId',
+      rules: [{ required: true, message: '算法不能为空', trigger: 'blur' }],
+      compOptions: {
+        elTagName: 'select',
+        placeholder: '请选择算法',
+        enum: enumsAlgorithmConfigTrack_trackSequence,
+        clearable: true,
+        onChange: async (value: any) => {
+          if (value != undefined && value != null && value != '') {
+            await updateItemsOptions(value)
+          }
+        }
+      }
+    },
+    {
+      label: '任务类型',
+      prop: 'type',
+      rules: [{ required: true, message: '任务类型不能为空', trigger: 'blur' }],
+      compOptions: {
+        disabled: true,
+        elTagName: 'select',
+        placeholder: '请选择任务类型',
+        enum: enumsAlgorithmType,
+        clearable: true,
+        value: ''
+      },
+      show: params => {
+        if (params.value.algorithmId != undefined) {
+          for (let i = 0; i < enumsAlgorithmConfigTrack_trackSequence.value.length; i++) {
+            if (enumsAlgorithmConfigTrack_trackSequence.value[i]['value'] === params.value.algorithmId) {
+              params.value.type = enumsAlgorithmConfigTrack_trackSequence.value[i]['type']
+              return true
+            }
+          }
+        }
+        return false
+      }
+    },
+    {
+      label: '选择模型',
+      prop: 'algorithmModelId',
+      rules: [{ required: false, message: '模型不能为空', trigger: 'blur' }],
+      show: params => {
+        if (params.value.type == AlgorithmType2['预测/推理']) {
+          return true
+        }
+        params.value.algorithmModelId = ''
+        return false
+      },
+      compOptions: {
+        elTagName: 'select',
+        placeholder: '请选择模型',
+        enum: enumsAlgorithmModelTrack,
+        clearable: true
+      }
+    },
+    {
+      label: '选择目标检测模型',
+      prop: 'algorithmModelTargetDetectionId',
+      rules: [{ required: true, message: '目标检测模型不能为空', trigger: 'blur' }],
+      show: params => {
+        if (params.value.type == AlgorithmType2['预测/推理']) {
+          return true
+        }
+        params.value.algorithmModelTargetDetectionId = ''
+        return false
+      },
+      compOptions: {
+        elTagName: 'select',
+        placeholder: '请选择目标检测模型',
+        enum: enumsAlgorithmModelTrack_TD,
+        clearable: true
+      }
+    },
+    {
+      label: '上传标签',
+      prop: 'inputLabelOssId',
+      rules: [{ required: true, message: '标签不能为空', trigger: 'blur' }],
+      show: params => {
+        if (params.value.type == AlgorithmType2['测试']) {
+          return true
+        }
+        return false
+      },
+      compOptions: {
+        elTagName: 'file-upload',
+        fileSize: 4096,
+        fileType: ['txt', 'xlsx', 'xls'],
+        placeholder: '请上传标签'
+      }
+    },
+    {
+      label: '备注',
+      prop: 'remarks',
+      rules: [],
+      compOptions: {
+        placeholder: '请输入备注'
+      }
+    }
+  ]
+}
+
+const dialogVisibleView = ref(false)
+const viewData = ref<any[]>([])
+const subTaskAlgorithmTaskTrack_id = ref<any>(null)
+const openViewDialog = async (row: any) => {
+  dialogVisibleView.value = true
+  subTaskAlgorithmTaskTrack_id.value = row.id
+}
+const handleOpenView = async () => {
+  const res = await listSubTaskAlgorithmTaskTrackApi(subTaskAlgorithmTaskTrack_id.value)
+  if (res.code === 200) {
+    viewData.value = res.data
+  } else {
+    ElMessage.error('获取子任务失败')
+  }
+}
+
+const fileUploadRef = ref()
+const fileUploadDatasetChange = (value: any) => {
+  console.log('fileUploadChange: ', value)
+  formAddTask.value['inputDatasetOssId'] = value
+}
+const fileUploadEvaluateLabelRef = ref()
+const fileUploadChangeEvaluateLabel = (value: any) => {
+  console.log('fileUploadChangeEvaluateLabel: ', value)
+  formAddTask.value['inputEvaluateLabelOssId'] = value
+}
+
+const getEnumsAlgorithmModelTrack = async (subSystem: string) => {
+  const result: any = await enumAlgorithmModelTrackApi()
+  const res_list: any[] = []
+  const tmp_data: any = result['data']
+  for (const item of tmp_data) {
+    if (SubSystem[item['subsystem']] === subSystem) {
+      const tmp_item = { ...item }
+      tmp_item['label'] = item['label'] + '-' + SubSystem[item['subsystem']] + '-' + AlgorithmType[item['type']] + '-' + item['algorithmName']
+      res_list.push(tmp_item)
+    }
+  }
+  return res_list
+}
+
+const getEnumsAlgorithmConfigTrack = async (subSystem: string, type_list_: string[]) => {
+  const result = await enumAlgorithmConfigTrackApi()
+  const res_list: any[] = []
+  const tmp_data: any = result['data']
+
+  const type_list: any[] = type_list_.map(item => parseInt(AlgorithmType2[item]))
+
+  for (const item of tmp_data) {
+    if (parseInt(item.subsystem) === parseInt(SubSystem__[subSystem])) {
+      if (type_list !== undefined && type_list.length > 0) {
+        if (type_list.includes(parseInt(item.type))) {
+          const tmp_item = { ...item }
+          tmp_item['label'] = item['label'] + '-' + SubSystem[item['subsystem']] + '-' + AlgorithmType[item['type']]
+          res_list.push(tmp_item)
+        }
+      } else {
+        const tmp_item = { ...item }
+        tmp_item['label'] = item['label'] + '-' + SubSystem[item['subsystem']] + '-' + AlgorithmType[item['type']]
+        res_list.push(tmp_item)
+      }
+    }
+  }
+  return res_list
+}
+
+const dialogVisibleAddTask = ref(false)
+const handleClose = (done: () => void) => {
+  ElMessageBox.confirm('确定关闭吗?')
+    .then(() => {
+      done()
+    })
+    .catch(() => {
+      // catch error
+    })
+}
+const formAddTask = ref({ ifEvaluate: false, ifToInfrared: false })
+const formAddTaskRef = ref()
+const addAlgorithmTaskTrack = async () => {
+  formAddTaskRef.value
+    .validate()
+    .then(async () => {
+      console.log('formAddTask: ', formAddTask.value)
+      console.log(fileUploadRef.value.uploadFileListExport)
+      const res = await addAlgorithmTaskTrackApi(formAddTask.value)
+      if (res.code === 200) {
+        ElMessage.success('新增可辨识性分析总任务成功')
+        dialogVisibleAddTask.value = false
+        proTable.value?.getTableList()
+      } else {
+        ElMessage.error('新增可辨识性分析总任务失败')
+      }
+    })
+    .catch(() => {
+      console.log('error')
+      ElMessage.error('请检查表单')
+    })
+}
+
+const rulesAddTask = {
+  // todo: 校验规则
+  name: [{ required: true, message: '可见光转红外算法不能为空', trigger: 'blur' }],
+  ifToInfrared: [{ required: false, message: '是否转红外不能为空', trigger: 'blur' }],
+  toInfraredAlgorithmId: [{ required: false, message: '可见光转红外算法不能为空', trigger: 'blur' }],
+  inputDatasetOssId: [{ required: true, message: '数据集不能为空', trigger: 'blur' }],
+  targetDetectionModelList: [{ required: true, message: '目标模型不能为空', trigger: 'blur' }],
+  inputEvaluateLabelOssId: [{ required: false, message: '评估标签不能为空', trigger: 'blur' }],
+  remarks: [{ required: false, message: '备注不能为空', trigger: 'blur' }]
+}
+
+const enumsAlgorithmConfigTrack_toInfrared = ref<any[]>([])
+const setIfToInfrared = async () => {
+  formAddTask.value.toInfraredAlgorithmId = ''
+  if (formAddTask.value?.ifToInfrared === true) {
+    enumsAlgorithmConfigTrack_toInfrared.value = await getEnumsAlgorithmConfigTrack('可见光转红外', ['预测/推理'])
+  }
+}
+
+const getItemsOptions = async (algorithmId: any) => {
+  try {
+    const result = await getAlgorithmConfigTrackApi(algorithmId)
+    if (result.code === 200) {
+      // 处理结果
+      const parameters = JSON.parse(result.data['parameters'])
+      // console.log('parameters: ', parameters)
+
+      let itemsOptions_new: any[] = []
+      for (const item of parameters) {
+        // 添加新的表单项选项
+        itemsOptions_new.push({
+          label: item['name'],
+          labelWidth: '200px',
+          prop: item['agName'],
+          rules: [{ required: item['required'], message: item['agName'] + '不能为空', trigger: 'blur' }],
+          tooltip: item['prompt'],
+          compOptions: {
+            elTagName: 'input',
+            placeholder: item['defaultValue']
+            // value: item['defaultValue']
+          }
+        })
+      }
+      return itemsOptions_new
+    }
+  } catch (err) {
+    console.log(err)
+    ElMessage.error('获取算法配置失败,请检查!')
+    return []
+  }
+}
+
+const setAlgorithmParams = async (id: string | number, paramsName: string) => {
+  const itemsOptions__ = await getItemsOptions(id)
+  const params = {
+    title: '设置算法参数',
+    width: 650,
+    isEdit: true,
+    itemsOptions: itemsOptions__,
+    model: formAddTask,
+    api: async params => {
+      console.log('itemsOptions__: ', itemsOptions__)
+      let params_new = {}
+      if (itemsOptions__ && itemsOptions__.length > 0) {
+        for (const item of itemsOptions__) {
+          params_new[item['prop']] = params[item['prop']]
+        }
+        formAddTask.value[paramsName] = params_new
+        console.log('params: ', params)
+        console.log('params_new: ', params_new)
+        console.log('formAddTask: ', formAddTask.value)
+      }
+      return { code: 200, message: 'success' }
+    },
+    getTableList: proTable.value?.getTableList
+  }
+  formDialogRef.value?.openDialog(params)
+}
+
+const datasetList = ref<any[]>([])
+
+const getDatasetList = async (subSystem: string) => {
+  const qyery = {
+    subsystem: subSystem ? SubSystem__[subSystem] : undefined,
+    pageNum: 1,
+    pageSize: 1000
+  }
+  const result: any = await listDataSeqApi(qyery)
+  const data = result['data']['list']
+  let res_list: any[] = []
+  for (const item of data) {
+    res_list.push({
+      value: item['inputOssId'],
+      label: item['name'] + '-' + SubSystem[item['subsystem']]
+    })
+  }
+  return res_list
+}
+
+const getDatasetList__ = async () => {
+  datasetList.value = await getDatasetList('')
+}
+
+const toInfraredModelList = ref<any[]>([])
+const getToInfraredModelList = async () => {
+  toInfraredModelList.value = await getEnumsAlgorithmModelTrack('可见光转红外')
+}
+
+const visionAlgorithmList = ref<any[]>([])
+const getVisionAlgorithmList = async () => {
+  visionAlgorithmList.value = await getEnumsAlgorithmConfigTrack('注释轨迹序列', ['预测/推理'])
+}
+
+const targetDetectionModelList = ref<any[]>([])
+const getTargetDetectionModelList = async () => {
+  targetDetectionModelList.value = await getEnumsAlgorithmModelTrack('目标检测')
+}
+
+const visionAlgorithmModelList = ref<any[]>([])
+const getVisionAlgorithmModelList = async () => {
+  visionAlgorithmModelList.value = await getEnumsAlgorithmModelTrack('注释轨迹序列')
+}
+
+const visionEvaluateAlgorithmList = ref<any[]>([])
+const getVisionEvaluateAlgorithmList = async () => {
+  visionEvaluateAlgorithmList.value = await getEnumsAlgorithmConfigTrack('注释轨迹序列', ['测试'])
+}
+
+const handleOpenAddTask = async () => {
+  formAddTask.value = { ifEvaluate: false, ifToInfrared: false }
+}
+
+onMounted(async () => {
+  await getDatasetList__()
+  await getToInfraredModelList()
+  await getVisionAlgorithmList()
+  await getTargetDetectionModelList()
+  await getVisionAlgorithmModelList()
+  await getVisionEvaluateAlgorithmList()
+})
+
+// ProTable 实例
+const proTable = ref<ProTableInstance>()
+
+// 删除可辨识性分析总任务信息
+const deleteAlgorithmTaskTrack = async (params: any) => {
+  await useHandleData(delAlgorithmTaskTrackApi, params.id, '删除【' + params.id + '】可辨识性分析总任务')
+  proTable.value?.getTableList()
+}
+
+// 批量删除可辨识性分析总任务信息
+const batchDelete = async (ids: string[]) => {
+  await useHandleData(delAlgorithmTaskTrackApi, ids, '删除所选可辨识性分析总任务信息')
+  proTable.value?.clearSelection()
+  proTable.value?.getTableList()
+}
+
+// 导出可辨识性分析总任务列表
+const downloadFile = async () => {
+  ElMessageBox.confirm('确认导出可辨识性分析总任务数据?', '温馨提示', { type: 'warning' }).then(() =>
+    useDownload(exportAlgorithmTaskTrackApi, '可辨识性分析总任务列表', proTable.value?.searchParam)
+  )
+}
+
+// 批量添加可辨识性分析总任务
+const dialogRef = ref<InstanceType<typeof ImportExcel> | null>(null)
+const batchAdd = () => {
+  const params = {
+    title: '可辨识性分析总任务',
+    tempApi: importTemplateApi,
+    importApi: importAlgorithmTaskTrackDataApi,
+    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 getAlgorithmTaskTrackApi(row?.id || null)
+  }
+  // 重置表单
+  setItemsOptions()
+  const params = {
+    title,
+    width: 580,
+    isEdit: type !== 3,
+    itemsOptions: itemsOptions,
+    model: type == 1 ? {} : res.data,
+    api: type == 1 ? addAlgorithmTaskTrackApi : updateAlgorithmTaskTrackApi,
+    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'
+    }
+  },
+  {
+    prop: 'status',
+    label: '任务状态',
+    search: {
+      el: 'select'
+    },
+    tag: true,
+    enum: statusEnums,
+    width: 150
+  },
+  {
+    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: 'log',
+    label: '日志',
+    search: {
+      el: 'input'
+    }
+  },
+  {
+    prop: 'remarks',
+    label: '备注',
+    search: {
+      el: 'input'
+    }
+  },
+  // {
+  //   prop: 'system',
+  //   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: '请输入任务名称'
+      }
+    }
+  ]
+}
+</script>
+
+<style lang="scss" scoped>
+.form-item1 {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  width: 100%;
+}
+</style>

+ 20 - 0
src/views/demo/components/PreviewImages.vue

@@ -114,6 +114,25 @@ const handleOpen = async (api: any, params: any) => {
   }
 }
 
+const handleOpenWithPicArray = (picArr: any) => {
+  dialogVisible.value = true
+  imageIdx.value = 0
+  imageFps.value = 0
+  newImageIdx.value = ''
+  imageUrlList.value = []
+  playMode.value = 'normal'
+  step.value = 1
+  flag_direction.value = 1
+
+  imageUrlList.value = picArr
+  if (imageUrlList.value.length >= 1) {
+    updateCanvas()
+    return true
+  } else {
+    return false
+  }
+}
+
 const closeDialog = () => {
   dialogVisible.value = false
 }
@@ -223,6 +242,7 @@ const pre_picture = () => {
 
 defineExpose({
   handleOpen,
+  handleOpenWithPicArray,
   closeDialog
 })
 </script>

+ 16 - 4
src/views/demo/components/ShowStatisticResult.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-dialog v-model="showResultDialogVisible" :title="props.title" width="700">
+  <el-dialog v-model="showResultDialogVisible" :title="title" width="700">
     <el-card style="width: 100%; margin-bottom: 10px">
       <div class="evaluate-data">
         <template v-for="(item, index) in ResultData" :key="index">
@@ -13,10 +13,12 @@
 
 <script setup lang="ts">
 import { ref } from 'vue'
+
 const props = defineProps({
   api: {
     type: Function,
-    required: true
+    required: false,
+    default: () => {}
   },
   title: {
     type: String,
@@ -25,10 +27,20 @@ const props = defineProps({
   }
 })
 
+const title = ref(props.title)
+
 const showResultDialogVisible = ref(false)
 const ResultData = ref([])
-const get_statistics_result = async (id: number | string) => {
-  const res: any = await props.api(id)
+const get_statistics_result = async (id: number | string, api: Function = undefined, title__: string = undefined) => {
+  let res: any = {}
+  if (!api) {
+    res = await props.api(id)
+  } else {
+    res = await api(id)
+  }
+  if (title__) {
+    title.value = title__
+  }
   ResultData.value = res.data
   showResultDialogVisible.value = true
 }

+ 10 - 5
src/views/demo/components/ViewLog.vue

@@ -39,9 +39,14 @@ const innerRef = ref()
 const isAutoScroll = ref(true)
 const listenerMouse = ref()
 
-const getLog = async () => {
+const getLog = async (api: Function = undefined) => {
   try {
-    const result: any = await props.getLogApi(logId.value)
+    let result: any = null
+    if (!api) {
+      result = await props.getLogApi(logId.value)
+    } else {
+      result = await api(logId.value)
+    }
     if (result.code == 200) {
       log.value = result.data
       if (isAutoScroll.value) {
@@ -56,15 +61,15 @@ const getLog = async () => {
     clearInterval(intervalLog.value)
   }
 }
-const handleOpen = id => {
+const handleOpen = (id: String | Number, api: Function = undefined) => {
   logId.value = id
   logVisible.value = true
   isAutoScroll.value = true
   log.value = ''
 
-  getLog()
+  getLog(api)
   intervalLog.value = setInterval(() => {
-    getLog()
+    getLog(api)
   }, logRefreshTime.value)
 
   nextTick(function () {

+ 21 - 5
src/views/demo/components/img-maker.vue

@@ -5,10 +5,11 @@
       <el-button plain type="primary" class="shape-border" @click="enableDragMode" :disabled="state.dragMode">移动图片</el-button>
 
       <el-button plain type="primary" style="margin-left: 30px" class="shape-border" @click="selectLastObject" :disabled="!!state.activeTarget"
-        >选择最后一个标注(w)</el-button
+        >选择标注(w)</el-button
       >
       <el-button plain type="primary" class="shape-border" @click="rotate(8)" :disabled="!state.activeTarget"> 顺时针旋转(r) </el-button>
       <el-button plain type="primary" class="shape-border" @click="rotate(-8)" :disabled="!state.activeTarget">逆时针旋转(e)</el-button>
+      <el-button plain type="primary" class="shape-border" @click="deleteOne">删除(Back)</el-button>
       <el-button plain type="primary" style="margin-left: 30px" class="shape-border" @click="changeZoom(1.1)">放大图片</el-button>
       <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> -->
@@ -18,7 +19,7 @@
 </template>
 <script lang="ts" setup>
 import { fabric } from 'fabric'
-import { reactive, watch, onMounted } from 'vue'
+import { reactive, watch, onMounted, computed } from 'vue'
 import { ElMessage } from 'element-plus'
 // import { sortPoints } from '@/utils/fabric'
 
@@ -65,6 +66,7 @@ const props = defineProps({
 const state = reactive({
   loading: true,
   radio: 1,
+  radioBackup: 1,
   realRadioX: 0.5,
   realRadioY: 0.5,
   imgPoint: { x: 0, y: 0 },
@@ -93,6 +95,7 @@ const state = reactive({
   activeLine: '' as any,
   line: {} as canvasPoint
 })
+
 watch(
   () => props.classDef,
   value => {
@@ -133,14 +136,23 @@ const changeZoom = multi => {
   state.canvas.renderAll()
 }
 
+const deleteOne = () => {
+  const obj = state.canvas.getActiveObject()
+  state.canvas.remove(obj)
+}
+
 const loadInit = () => {
   drawTypeChange('rectangle')
   state.color = props.classDef && props.classDef.color ? props.classDef.color : '#E34F51'
   if (!props.isPicOnly) {
     document.addEventListener('keydown', function (e) {
+      console.log(e.key, state.activeTarget, state.canvas.getActiveObject())
       if (e.key === 'w' || e.key === 'W') {
         selectLastObject()
         return
+      } else if (e.key === 'Backspace') {
+        const obj = state.canvas.getActiveObject()
+        state.canvas.remove(obj)
       }
       if (state.activeTarget) {
         if (e.key === 'r' || e.key === 'R') {
@@ -199,6 +211,8 @@ const loadInit = () => {
       for (let i = 0; i < props.jsonData.length; i++) {
         let config = props.jsonData[i]
         let subArr = config.subArr
+        console.log('ratio', state.radio)
+        state.radioBackup = state.radio
         const lW = imgInstance.width * state.radio
         const lH = imgInstance.height * state.radio
         let obj = new fabric.Path(
@@ -742,7 +756,7 @@ const clearAll = () => {
   state.drawType = 'rectangle'
 }
 const getPoint = pi => {
-  return Math.floor(pi / state.radio)
+  return Math.floor(pi)// / state.radio
 }
 const getRealPoint = poi => {
   let dx = Math.abs(state.imgPoint.x > poi.x ? state.imgPoint.x - poi.x : state.imgPoint.x + poi.x) * state.realRadioX
@@ -786,6 +800,7 @@ const getData = () => {
           // }
         })
       } else {
+        // console.log('else')
         marks.forEach(mark => {
           let poi = {
             x: getPoint(aCoords[mark].x),
@@ -794,8 +809,9 @@ const getData = () => {
           // console.log(poi)
           poi = getRealPoint(poi)
           // console.log(poi)
-          poi.x = poi.x / state.realRadioX / 1920
-          poi.y = poi.y / state.realRadioY / 1080
+          console.log('radio final:', state.radio, state.radioBackup)
+          poi.x = poi.x / 1920 / state.radioBackup
+          poi.y = poi.y / 1080 / state.radioBackup
           // console.log(poi)
           point['nodes'].push(poi)
           // point['nodes'].push(getRealPoint(poi))

+ 15 - 12
src/views/demo/data/AmplifyForm.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="amplify-main">
-    <ProForm :items-options="items" :model="model"></ProForm>
+    <ProForm ref="proFormRef" :items-options="items"></ProForm>
     <el-button type="primary" v-if="showSelectBatchButton" style="margin-left: 50px" @click="showDataSelectionDialog()">选择批次</el-button>
 
     <el-dialog v-model="dataDialogVisible" title="选择数据批次" style="width: 70vw">
@@ -37,14 +37,15 @@ import { reactive, ref, computed, onMounted, defineEmits } from 'vue'
 import ProForm from '@/components/ProForm/index.vue'
 import { batchListDataApi } from '@/api/modules/demo/data'
 import { getDictsApi } from '@/api/modules/system/dictData'
+import ProFrom from '@/components/ProForm/index.vue'
 
 const emit = defineEmits(['updateData', 'updateModel', 'updateParams'])
-
+const proFormRef = ref<InstanceType<typeof ProFrom> | null>(null)
 // 数据
-let model = {
-  taskName: 'sss',
+const model = ref({
+  taskName: '',
   transfer: null
-}
+})
 
 const dataDialogVisible = ref(false)
 let batchDataList = ref(reactive([] as any[]))
@@ -54,12 +55,14 @@ let tempDeselectedBatchDataList = ref(reactive([] as any[]))
 let parameList = ref(reactive([] as any[]))
 let queryBatchData = ref(reactive([] as any[]))
 
-const props = defineProps({ showSelectBatchButton: Boolean })
+const props = defineProps({ showSelectBatchButton: Boolean, dataList: Array, useData: Boolean })
 
 onMounted(() => {
-  batchListDataApi().then(res => {
-    queryBatchData.value = reactive(res.data)
-  })
+  !props.useData &&
+    batchListDataApi().then(res => {
+      queryBatchData.value = reactive(res.data)
+    })
+  props.useData && (queryBatchData.value = props.dataList) // && console.log('load data', props.dataList)
 
   getDictsApi('expand_data_params').then(res => {
     parameList.value = reactive(JSON.parse(res.data[0].remark))
@@ -75,9 +78,9 @@ onMounted(() => {
           placeholder: '请输入' + item.name
         }
       })
-      model[`${item.agName}`] = item.defaultValue
+      // model.value[`${item.agName}`] = item.defaultValue
     })
-    emit('updateModel', model)
+    emit('updateModel', proFormRef.value.formModel)
     // Emit parameList 给父组件
     emit('updateParams', parameList.value)
   })
@@ -149,7 +152,7 @@ let items: ProForm.ItemsOptions[] = reactive([
     compOptions: {
       elTagName: 'input',
       clearable: true,
-      placeholder: '请输入用户名'
+      placeholder: '请输入任务名称'
     }
   },
   {

+ 16 - 7
src/views/demo/data/index.vue

@@ -133,8 +133,9 @@ const getTrainAugmentationParams = () => {
   })
 
   return {
-    batchNum,
+    batchNum: batchNum,
     taskName: model.value.taskName,
+    augmentationType: model.value.augmentationType,
     otherParams: parameList.value
   }
 }
@@ -212,6 +213,7 @@ const deleteData = async (params: any) => {
   await useHandleData(delDataApi, params.id, `删除【${params.name}】数据`)
   proTable.value?.getTableList()
 }
+import { fourNodes2xywh, xywh2fourNodes } from './reformat'
 
 // 标注图片
 const markImg = data => {
@@ -242,12 +244,14 @@ const markImg = data => {
       if (state.cacheData.labelurl && state.cacheData.labelurl.length > 0) {
         console.log('get label jsonData', state.cacheData.labelurl)
         http
-          .get<any>(state.cacheData.labelurl)
+          .get<any>(state.cacheData.labelurl + '?version=' + new Date().getTime())
           .then(res => {
             state.jsonData = []
-            console.log(res)
+            res = xywh2fourNodes(res)
+            // console.log('check3', res)
+
             let arr = res.replace('\r', '').split('\n')
-            console.log(arr)
+            // console.log(arr)
             for (let i = 0; i < arr.length; i++) {
               let subArr = arr[i].split(' ')
               // console.log(subArr)
@@ -352,7 +356,12 @@ const handleImgSuccess = data => {
     filename = filename.substring(1)
   }
   // console.log(filename)
-
+  let pData = fourNodes2xywh(data['data'])
+  // console.log('check1', data['data'])
+  data['data'] = pData
+  // let a = xywh2fourNodes(pData)
+  // console.log('check2', a)
+  // let rData = xywh2fourNodes(pData)
   labelFile(data['data'], filename).then(res => {
     // console.log(res)
     if (res.code === 200) {
@@ -472,7 +481,7 @@ const openDialog = async (type: number, title: string, row?: any) => {
 
 // 表格配置项
 const columns = reactive<ColumnProps<any>[]>([
-  { type: 'selection', fixed: 'left', width: 70 },
+  { type: 'selection', width: 70 },
   { prop: 'yuan', label: '原图', width: 200 },
   {
     prop: 'batchNum',
@@ -573,7 +582,7 @@ const columns = reactive<ColumnProps<any>[]>([
     },
     width: 120
   },
-  { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
+  { prop: 'operation', label: '操作', width: 230 }
 ])
 // 表单配置项
 let formItems: ProForm.ItemsOptions[] = []

+ 41 - 0
src/views/demo/data/reformat.js

@@ -0,0 +1,41 @@
+export const fourNodes2xywh = function (data) {
+  let lines = data.replace('\r', '').split('\n')
+  let res = []
+  lines.forEach(line => {
+    const arr = line.split(' ')
+    let tmp = []
+    tmp.push(arr[0])
+    tmp.push((parseFloat(arr[3]) + parseFloat(arr[5])) / 2)
+    tmp.push((parseFloat(arr[2]) + parseFloat(arr[4])) / 2)
+    tmp.push(Math.abs(arr[5] - arr[3]))
+    tmp.push(Math.abs(arr[4] - arr[2]))
+    res.push(tmp.join(' '))
+  })
+  // console.log(res)
+  return res.join('\r\n')
+}
+
+export const xywh2fourNodes = function (data) {
+  let lines = data.replace('\r', '').split('\n')
+  let res = []
+  lines.forEach(line => {
+    const arr = line.split(' ')
+    let tmp = []
+    tmp.push(arr[0])
+    tmp.push(parseFloat(arr[1]) + parseFloat(arr[3]) / 2)
+    tmp.push(parseFloat(arr[2]) - parseFloat(arr[4]) / 2)
+
+    tmp.push(parseFloat(arr[1]) + parseFloat(arr[3]) / 2)
+    tmp.push(parseFloat(arr[2]) + parseFloat(arr[4]) / 2)
+
+    tmp.push(parseFloat(arr[1]) - parseFloat(arr[3]) / 2)
+    tmp.push(parseFloat(arr[2]) + parseFloat(arr[4]) / 2)
+
+    tmp.push(parseFloat(arr[1]) - parseFloat(arr[3]) / 2)
+    tmp.push(parseFloat(arr[2]) - parseFloat(arr[4]) / 2)
+
+    res.push(tmp.join(' '))
+  })
+  // console.log(res)
+  return res.join('\r\n')
+}

+ 210 - 166
src/views/demo/dataAugmentation/index.vue

@@ -20,11 +20,17 @@
       <!-- 表格操作 -->
       <template #operation="scope">
         <el-button type="primary" link icon="View" @click="startDataAugmentation(scope.row)" v-if="scope.row.status == '0'"> 开始 </el-button>
+        <el-button type="primary" link icon="View" @click="startDataAugmentation(scope.row)" v-if="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-popconfirm title="确定暂停此任务吗?" @confirm="pauseDataAugmentation(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="preview(scope.row)" v-if="scope.row.status == '2'"> 预览 </el-button>
         <el-button type="primary" link icon="View" @click="downloadFile(scope.row)" v-if="scope.row.status == '2'"> 导出 </el-button>
         <el-button
@@ -39,16 +45,16 @@
         <el-button type="primary" link icon="View" v-auth="['demo:DataAugmentation:query']" @click="openDialog(3, '任务查看', scope.row)">
           查看
         </el-button>
-        <!-- <el-button
+        <el-button
           type="primary"
           link
           icon="View"
           v-auth="['demo:DataAugmentation:query']"
           @click="viewLogRef.handleOpen(scope.row.id)"
-          v-if="scope.row.status != '0' && scope.row.status != '1'"
+          v-if="scope.row.status != '0'"
         >
           日志
-        </el-button> -->
+        </el-button>
         <el-button type="primary" link icon="Delete" v-auth="['demo:DataAugmentation:remove']" @click="deleteDataAugmentation(scope.row)">
           删除
         </el-button>
@@ -105,6 +111,7 @@ import DataAugmentationFormDialog from '@/components/DataAugmentationFormDialog/
 import PreviewCompareImages from '@/views/demo/components/PreviewCompareImages.vue'
 import { ProTableInstance, ColumnProps, EnumProps } from '@/components/ProTable/interface'
 import ViewLog from '@/views/demo/components/ViewLog.vue'
+
 import {
   listDataAugmentationApi,
   delDataAugmentationApi,
@@ -121,11 +128,14 @@ import {
   getDialogApi,
   getTaskDictData,
   getMetricApi,
-  getCompareImageApiNew
+  getCompareImageApiNew,
+  pauseDataAugmentationApi
 } from '@/api/modules/demo/dataAugmentation'
+import { getDictsApi } from '@/api/modules/system/dictData'
+import { any } from 'vue-types'
 // import {  } from '@/api/modules/system/dictData'
-import { S } from 'vite/dist/node/types.d-aGj9QkWt'
-import { servicesVersion } from 'typescript'
+// import { S } from 'vite/dist/node/types.d-aGj9QkWt'
+// import { servicesVersion } from 'typescript'
 
 const previewCompareImagesRef = ref()
 const preview = async row => {
@@ -183,32 +193,27 @@ const openLogDialog = async (id: string | number) => {
   logDialogVisible.value = true
 }
 const getTaskType = async () => {
-  const res: any = await getTaskDictData()
+  const res: any = await getTaskDictData('数据增强')
+  console.log(res.data)
   if (res.data.length != 0) {
     taskType.value = res.data
       .map(item => {
-        if (item.taskType === '图像逆光' || item.taskType === '图像增强') {
-          return {
-            label: item.taskType,
-            value: item.taskType
-          }
-        } else {
-          return null
+        return {
+          label: item.taskType,
+          value: item.taskType
         }
       })
       .filter(item => item !== null)
     res.data.forEach(item => {
-      if (item.taskType === '图像增强' || item.taskType === '图像逆光') {
-        taskTypeEnums.push({
-          label: item.taskType,
-          value: item.taskType,
-          disabled: false,
-          tagType: 'default'
-        })
-        let obj = {}
-        obj[item.taskType] = item.hyperparameterConfiguration
-        hyperparameterConfiguration.push(obj)
-      }
+      taskTypeEnums.push({
+        label: item.taskType,
+        value: item.taskType,
+        disabled: false,
+        tagType: 'default'
+      })
+      let obj = {}
+      obj[item.taskType] = item.hyperparameterConfiguration
+      hyperparameterConfiguration.push(obj)
     })
   }
 }
@@ -226,8 +231,19 @@ onMounted(() => {
     proTable.value?.getTableList()
   }, 5000)
   getTaskType()
+  getZipFileDes()
 })
+const zipFileDes = ref('')
+const getZipFileDes = async () => {
+  let res = await getDictsApi('zip_file_format_description')
 
+  res.data.forEach(item => {
+    // 检查item对象是否包含dict和des属性
+    if (item.dictLabel === '图像增强') {
+      zipFileDes.value = item.remark
+    }
+  })
+}
 const startDataAugmentation = async (params: any) => {
   const res = await startDataAugmentationApi(params.id)
   if (res.code === 200) {
@@ -248,6 +264,16 @@ const stopDataAugmentation = async (params: any) => {
   proTable.value?.getTableList()
 }
 
+const pauseDataAugmentation = async (params: any) => {
+  const res = await pauseDataAugmentationApi(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
@@ -517,6 +543,7 @@ let itemsOptions: ProForm.ItemsOptions[] = [
   {
     label: '图片集压缩包',
     prop: 'inputOssId',
+    tooltip: zipFileDes,
     rules: [{ required: true, message: '数据压缩包不能为空', trigger: 'change' }],
     compOptions: {
       elTagName: 'file-upload',
@@ -553,148 +580,165 @@ const addParams = params => {
   }
   let validJsonString = params.replace(/'/g, '"')
   try {
-    const obj: { [key: string]: number } = JSON.parse(validJsonString)
-    Object.keys(obj).forEach(key => {
-      model.value[key] = obj[key]
-      if (key === 'ratio_mix' || key === 'alpha') {
-        itemsOptions.push({
-          label: key,
-          prop: key,
-          rules: [
-            {
-              trigger: 'change',
-              validator: (rule, value, callback) => {
-                if (value === '' || value === undefined) {
-                  return callback()
-                }
-                if (!value) {
-                  return callback(new Error('请输入一个0到1之间的浮点数'))
-                }
-                const regex = /^(0(\.\d+)?|1(\.0+)?)$/
-                if (!regex.test(value)) {
-                  return callback(new Error('请输入一个0到1之间的浮点数'))
-                }
-                callback()
-              }
-            }
-          ],
-          compOptions: {
-            type: 'input',
-            clearable: true,
-            placeholder: '默认值为' + obj[key]
-          }
-        })
-      } else if (key === 'light') {
-        itemsOptions.push({
-          label: key,
-          prop: key,
-          rules: [
-            {
-              trigger: 'change',
-              validator: (rule, value, callback) => {
-                if (value === '' || value === undefined) {
-                  return callback()
-                }
-                const minValue = 40
-                const maxValue = 60
-
-                const intValue = parseInt(value, 10)
-                if (isNaN(intValue) || intValue < minValue || intValue > maxValue) {
-                  return callback(new Error('请输入一个40到60之间的整数'))
-                }
-                callback()
-              }
-            }
-          ],
-          compOptions: {
-            type: 'input',
-            clearable: true,
-            placeholder: '默认值为' + obj[key]
-          }
-        })
-      } else if (key === 'beta') {
-        itemsOptions.push({
-          label: key,
-          prop: key,
-          rules: [
-            {
-              trigger: 'change',
-              validator: (rule, value, callback) => {
-                if (value === '' || value === undefined) {
-                  return callback()
-                }
-                const minValue = -30
-                const maxValue = -10
-
-                const intValue = parseInt(value, 10)
-                if (isNaN(intValue) || intValue < minValue || intValue > maxValue) {
-                  return callback(new Error('请输入一个-30到-10之间的负整数'))
-                }
-                callback()
-              }
-            }
-          ],
-          compOptions: {
-            type: 'input',
-            clearable: true,
-            placeholder: '默认值为' + obj[key]
-          }
-        })
-      } else if (key === 'beta') {
-        itemsOptions.push({
-          label: key,
-          prop: key,
-          rules: [
-            {
-              trigger: 'change',
-              validator: (rule, value, callback) => {
-                if (value === '' || value === undefined) {
-                  return callback()
-                }
-                const minValue = -30
-                const maxValue = -10
-
-                const intValue = parseInt(value, 10)
-                if (isNaN(intValue) || intValue < minValue || intValue > maxValue) {
-                  return callback(new Error('请输入一个-30到-10之间的负整数'))
-                }
-                callback()
-              }
-            }
-          ],
-          compOptions: {
-            type: 'input',
-            clearable: true,
-            placeholder: '默认值为' + obj[key]
-          }
-        })
-      } else if (key === 's_v') {
-        itemsOptions.push({
-          label: key,
-          prop: key,
-          rules: [
-            {
-              trigger: 'change',
-              validator: (rule, value, callback) => {
-                if (value === '' || value === undefined) {
-                  return callback()
-                }
-                const intValue = parseInt(value, 10)
-                if (isNaN(intValue) || intValue <= 0 || intValue % 2 === 0) {
-                  return callback(new Error('请输入一个大于0的奇整数'))
-                }
-                callback()
-              }
-            }
-          ],
-          compOptions: {
-            type: 'input',
-            clearable: true,
-            placeholder: '默认值为' + obj[key]
-          }
-        })
-      }
+    const obj = JSON.parse(validJsonString)
+    obj.forEach(param => {
+      model.value[param.agName] = param.defaultValue
+
+      itemsOptions.push({
+        // hideLabelSuffix: false,
+        label: param.name,
+        tooltip: param.prompt,
+        prop: param.agName,
+        rules: [],
+        compOptions: {
+          type: 'input',
+          clearable: true,
+          placeholder: '默认值为' + param.defaultValue
+        }
+      })
     })
+    //console.log(obj)
+    // Object.keys(obj).forEach(key => {
+    //   model.value[key] = obj[key]
+    //   if (key === 'ratio_mix' || key === 'alpha') {
+    //     itemsOptions.push({
+    //       label: key,
+    //       prop: key,
+    //       rules: [
+    //         {
+    //           trigger: 'change',
+    //           validator: (rule, value, callback) => {
+    //             if (value === '' || value === undefined) {
+    //               return callback()
+    //             }
+    //             if (!value) {
+    //               return callback(new Error('请输入一个0到1之间的浮点数'))
+    //             }
+    //             const regex = /^(0(\.\d+)?|1(\.0+)?)$/
+    //             if (!regex.test(value)) {
+    //               return callback(new Error('请输入一个0到1之间的浮点数'))
+    //             }
+    //             callback()
+    //           }
+    //         }
+    //       ],
+    //       compOptions: {
+    //         type: 'input',
+    //         clearable: true,
+    //         placeholder: '默认值为' + obj[key]
+    //       }
+    //     })
+    //   } else if (key === 'light') {
+    //     itemsOptions.push({
+    //       label: key,
+    //       prop: key,
+    //       rules: [
+    //         {
+    //           trigger: 'change',
+    //           validator: (rule, value, callback) => {
+    //             if (value === '' || value === undefined) {
+    //               return callback()
+    //             }
+    //             const minValue = 40
+    //             const maxValue = 60
+
+    //             const intValue = parseInt(value, 10)
+    //             if (isNaN(intValue) || intValue < minValue || intValue > maxValue) {
+    //               return callback(new Error('请输入一个40到60之间的整数'))
+    //             }
+    //             callback()
+    //           }
+    //         }
+    //       ],
+    //       compOptions: {
+    //         type: 'input',
+    //         clearable: true,
+    //         placeholder: '默认值为' + obj[key]
+    //       }
+    //     })
+    //   } else if (key === 'beta') {
+    //     itemsOptions.push({
+    //       label: key,
+    //       prop: key,
+    //       rules: [
+    //         {
+    //           trigger: 'change',
+    //           validator: (rule, value, callback) => {
+    //             if (value === '' || value === undefined) {
+    //               return callback()
+    //             }
+    //             const minValue = -30
+    //             const maxValue = -10
+
+    //             const intValue = parseInt(value, 10)
+    //             if (isNaN(intValue) || intValue < minValue || intValue > maxValue) {
+    //               return callback(new Error('请输入一个-30到-10之间的负整数'))
+    //             }
+    //             callback()
+    //           }
+    //         }
+    //       ],
+    //       compOptions: {
+    //         type: 'input',
+    //         clearable: true,
+    //         placeholder: '默认值为' + obj[key]
+    //       }
+    //     })
+    //   } else if (key === 'beta') {
+    //     itemsOptions.push({
+    //       label: key,
+    //       prop: key,
+    //       rules: [
+    //         {
+    //           trigger: 'change',
+    //           validator: (rule, value, callback) => {
+    //             if (value === '' || value === undefined) {
+    //               return callback()
+    //             }
+    //             const minValue = -30
+    //             const maxValue = -10
+
+    //             const intValue = parseInt(value, 10)
+    //             if (isNaN(intValue) || intValue < minValue || intValue > maxValue) {
+    //               return callback(new Error('请输入一个-30到-10之间的负整数'))
+    //             }
+    //             callback()
+    //           }
+    //         }
+    //       ],
+    //       compOptions: {
+    //         type: 'input',
+    //         clearable: true,
+    //         placeholder: '默认值为' + obj[key]
+    //       }
+    //     })
+    //   } else if (key === 's_v') {
+    //     itemsOptions.push({
+    //       label: key,
+    //       prop: key,
+    //       rules: [
+    //         {
+    //           trigger: 'change',
+    //           validator: (rule, value, callback) => {
+    //             if (value === '' || value === undefined) {
+    //               return callback()
+    //             }
+    //             const intValue = parseInt(value, 10)
+    //             if (isNaN(intValue) || intValue <= 0 || intValue % 2 === 0) {
+    //               return callback(new Error('请输入一个大于0的奇整数'))
+    //             }
+    //             callback()
+    //           }
+    //         }
+    //       ],
+    //       compOptions: {
+    //         type: 'input',
+    //         clearable: true,
+    //         placeholder: '默认值为' + obj[key]
+    //       }
+    //     })
+    //   }
+    // })
   } catch (error) {
     console.error('解析 JSON 字符串时出错:', error)
   }

+ 56 - 12
src/views/demo/imageMosaic/index.vue

@@ -19,12 +19,18 @@
       </template>
       <!-- 表格操作 -->
       <template #operation="scope">
+        <el-button type="primary" link icon="View" @click="startDataAugmentation(scope.row)" v-if="scope.row.status == '4'"> 继续 </el-button>
         <el-button type="primary" link icon="View" @click="startDataAugmentation(scope.row)" v-if="scope.row.status == '0'"> 开始 </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-popconfirm title="确定暂停此任务吗?" @confirm="pauseDataAugmentation(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" @click="downloadFile(scope.row)" v-if="scope.row.status == '2'"> 导出 </el-button>
         <el-button type="primary" link icon="View" @click="openMetricDialog(scope.row.id)" v-if="scope.row.status == '2'"> 指标 </el-button>
@@ -37,7 +43,7 @@
           icon="View"
           v-auth="['demo:DataAugmentation:query']"
           @click="viewLogRef.handleOpen(scope.row.id)"
-          v-if="scope.row.status != '0' && scope.row.status != '1'"
+          v-if="scope.row.status != '0'"
         >
           日志
         </el-button>
@@ -110,8 +116,10 @@ import {
   getCompareImageCountApi,
   getDialogApi,
   getTaskDictData,
-  getMetricApi
+  getMetricApi,
+  pauseDataAugmentationApi
 } from '@/api/modules/demo/dataAugmentation'
+import { getDictsApi } from '@/api/modules/system/dictData'
 // import {  } from '@/api/modules/system/dictData'
 
 const viewLogRef = ref()
@@ -165,7 +173,7 @@ const openLogDialog = async (id: string | number) => {
   logDialogVisible.value = true
 }
 const getTaskType = async () => {
-  const res: any = await getTaskDictData()
+  const res: any = await getTaskDictData('图像拼接')
   if (res.data.length != 0) {
     taskType.value = res.data
       .map(item => {
@@ -208,7 +216,19 @@ onMounted(() => {
     proTable.value?.getTableList()
   }, 5000)
   getTaskType()
+  getZipFileDes()
 })
+const zipFileDes = ref('')
+const getZipFileDes = async () => {
+  let res = await getDictsApi('zip_file_format_description')
+
+  res.data.forEach(item => {
+    // 检查item对象是否包含dict和des属性
+    if (item.dictLabel === '图像拼接') {
+      zipFileDes.value = item.remark
+    }
+  })
+}
 
 const startDataAugmentation = async (params: any) => {
   const res = await startDataAugmentationApi(params.id)
@@ -229,7 +249,15 @@ const stopDataAugmentation = async (params: any) => {
   }
   proTable.value?.getTableList()
 }
-
+const pauseDataAugmentation = async (params: any) => {
+  const res = await pauseDataAugmentationApi(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
@@ -499,6 +527,7 @@ let itemsOptions: ProForm.ItemsOptions[] = [
   {
     label: '图片集压缩包',
     prop: 'inputOssId',
+    tooltip: zipFileDes,
     rules: [{ required: true, message: '数据压缩包不能为空', trigger: 'change' }],
     compOptions: {
       elTagName: 'file-upload',
@@ -535,21 +564,36 @@ const addParams = params => {
   }
   let validJsonString = params.replace(/'/g, '"')
   try {
-    const obj: { [key: string]: number } = JSON.parse(validJsonString)
-    Object.keys(obj).forEach(key => {
-      model.value[key] = obj[key]
-
+    const obj = JSON.parse(validJsonString)
+    obj.forEach(param => {
+      model.value[param.agName] = param.defaultValue
       itemsOptions.push({
-        label: key,
-        prop: key,
-        rules: [{ trigger: 'blur' }],
+        tooltip: param.prompt,
+        label: param.name,
+        prop: param.agName,
+        rules: [],
         compOptions: {
           type: 'input',
           clearable: true,
-          placeholder: '默认值为' + obj[key]
+          placeholder: '默认值为' + param.defaultValue
         }
       })
     })
+    // 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: [{ trigger: 'blur' }],
+    //     compOptions: {
+    //       type: 'input',
+    //       clearable: true,
+    //       placeholder: '默认值为' + obj[key]
+    //     }
+    //   })
+    // })
   } catch (error) {
     console.error('解析 JSON 字符串时出错:', error)
   }

+ 51 - 5
src/views/demo/match/index.vue

@@ -28,7 +28,9 @@
       <!-- 表格操作 -->
       <template #operation="scope">
         <el-button type="primary" icon="View" link @click="doExecute(scope.row)">开始任务</el-button>
-
+        <el-button type="primary" link icon="View" @click="hangupTask(scope.row)"> 暂停任务 </el-button>
+        <el-button type="primary" link icon="View" @click="doExecute(scope.row)"> 继续任务 </el-button>
+        <el-button type="primary" link icon="View" @click="stopTask(scope.row)"> 停止任务 </el-button>
         <el-button type="primary" icon="View" link @click="showData(scope.row)">执行结果</el-button>
 
         <el-button type="primary" icon="View" link @click="showLog(scope.row)">查看日志</el-button>
@@ -64,9 +66,23 @@
         <el-input v-model="formData.name" placeholder="请输入任务名称"></el-input>
       </el-container>
       <el-container style="margin-top: 20px">
-        <span class="span_class">任务文件</span>
+        <span class="span_class">
+            任务文件
+            <el-tooltip :content="fileDescription" placement="top">
+              <el-icon><InfoFilled /></el-icon>
+            </el-tooltip>
+        </span>
         <file @update:model-value="updateFile" :file-size="2048" :file-type="['zip']"></file>
       </el-container>
+
+      <el-container v-for="(item, index) in jsonParams" :key="index" style="align-items: center; margin-top: 5px">
+        <span style="min-width: 80px; max-width: 150px">{{ item.name }}</span>
+        <el-tooltip :content="item.prompt" placement="top">
+          <el-icon><InfoFilled /></el-icon>
+        </el-tooltip>
+        <el-input v-model="item.value" :placeholder="item.defaultValue" style="max-width: 300px" />
+      </el-container>
+
       <el-button type="primary" @click="doCreateTask">创建</el-button>
     </el-dialog>
 
@@ -146,12 +162,15 @@ import {
   getMatchApi,
   createTask,
   execute,
-  getResult
+  getResult,
+  hangupApi,
+  stopApi
 } from '@/api/modules/demo/match'
 import File from '@/components/Upload/File.vue'
 import { getDictsApi } from '@/api/modules/system/dictData'
 import ResultDialog from '@/components/ResultDialog/ResultDialog.vue'
 import http from '@/api'
+import { getJsonParams, getOneAlgorithmConfigApi } from '@/api/modules/demo/algorithmConfig'
 
 const logVisible = ref(false)
 const logData = ref([])
@@ -219,12 +238,39 @@ const doExecute = function (row) {
   })
 }
 
+const hangupTask = function (row) {
+  hangupApi({ taskId: row.id }).then(res => {
+    console.log(res)
+  })
+}
+
+const stopTask = function (row) {
+  stopApi({ taskId: row.id }).then(res => {
+    console.log(res)
+  })
+}
+
+const fileDescription = ref('')
+const jsonParams = ref([])
 const dialogVisible = ref(false)
-const openCreateDialog = function () {
+const openCreateDialog = async function () {
+  const res = await getOneAlgorithmConfigApi({ algorithmName: '异源图像匹配定位' })
+  // console.log(res)
+  jsonParams.value = JSON.parse(res.data.parameters)
   formData.value = {
     name: '',
     file: null
   }
+
+  let _res = await getDictsApi('zip_file_format_description')
+
+  _res.data.forEach(item => {
+    // 检查item对象是否包含dict和des属性
+    if (item.dictLabel === '异源图像匹配') {
+      fileDescription.value = item.remark
+    }
+  })
+
   dialogVisible.value = true
 }
 const formData = ref({
@@ -232,7 +278,7 @@ const formData = ref({
   file: null
 })
 const doCreateTask = function () {
-  createTask(formData.value).then(res => {
+  createTask({ parameters: JSON.stringify(getJsonParams(jsonParams.value)), ...formData.value }).then(res => {
     if (res.code === 200) {
       dialogVisible.value = false
       ElMessage.success('创建成功')

+ 67 - 30
src/views/demo/targetDamageAcess/index.vue

@@ -19,12 +19,18 @@
       </template>
       <!-- 表格操作 -->
       <template #operation="scope">
+        <el-button type="primary" link icon="View" @click="startDataAugmentation(scope.row)" v-if="scope.row.status == '4'"> 继续 </el-button>
         <el-button type="primary" link icon="View" @click="startDataAugmentation(scope.row)" v-if="scope.row.status == '0'"> 开始 </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-popconfirm title="确定暂停此任务吗?" @confirm="pauseDataAugmentation(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" @click="downloadFile(scope.row)" v-if="scope.row.status == '2'"> 导出 </el-button>
         <el-button
@@ -45,7 +51,7 @@
           icon="View"
           v-auth="['demo:DataAugmentation:query']"
           @click="viewLogRef.handleOpen(scope.row.id)"
-          v-if="scope.row.status != '0' && scope.row.status != '1'"
+          v-if="scope.row.status != '0'"
         >
           日志
         </el-button>
@@ -118,10 +124,11 @@ import {
   getCompareImageCountApi,
   getDialogApi,
   getTaskDictData,
-  getMetricApi
+  getMetricApi,
+  pauseDataAugmentationApi
 } from '@/api/modules/demo/dataAugmentation'
 // import {  } from '@/api/modules/system/dictData'
-
+import { getDictsApi } from '@/api/modules/system/dictData'
 const viewLogRef = ref()
 //打开指标窗口查看算法指标信息
 const metricDialogVisible = ref(false)
@@ -173,32 +180,26 @@ const openLogDialog = async (id: string | number) => {
   logDialogVisible.value = true
 }
 const getTaskType = async () => {
-  const res: any = await getTaskDictData()
+  const res: any = await getTaskDictData('目标毁伤模块')
   if (res.data.length != 0) {
     taskType.value = res.data
       .map(item => {
-        if (item.taskType === '目标毁伤评估') {
-          return {
-            label: item.taskType,
-            value: item.taskType
-          }
-        } else {
-          return null
+        return {
+          label: item.taskType,
+          value: item.taskType
         }
       })
       .filter(item => item !== null)
     res.data.forEach(item => {
-      if (item.taskType === '目标毁伤评估') {
-        taskTypeEnums.push({
-          label: item.taskType,
-          value: item.taskType,
-          disabled: false,
-          tagType: 'default'
-        })
-        let obj = {}
-        obj[item.taskType] = item.hyperparameterConfiguration
-        hyperparameterConfiguration.push(obj)
-      }
+      taskTypeEnums.push({
+        label: item.taskType,
+        value: item.taskType,
+        disabled: false,
+        tagType: 'default'
+      })
+      let obj = {}
+      obj[item.taskType] = item.hyperparameterConfiguration
+      hyperparameterConfiguration.push(obj)
     })
   }
 }
@@ -216,8 +217,19 @@ onMounted(() => {
     proTable.value?.getTableList()
   }, 5000)
   getTaskType()
+  getZipFileDes()
 })
+const zipFileDes = ref('')
+const getZipFileDes = async () => {
+  let res = await getDictsApi('zip_file_format_description')
 
+  res.data.forEach(item => {
+    // 检查item对象是否包含dict和des属性
+    if (item.dictLabel === '目标毁伤评估') {
+      zipFileDes.value = item.remark
+    }
+  })
+}
 const startDataAugmentation = async (params: any) => {
   const res = await startDataAugmentationApi(params.id)
   if (res.code === 200) {
@@ -237,6 +249,15 @@ const stopDataAugmentation = async (params: any) => {
   }
   proTable.value?.getTableList()
 }
+const pauseDataAugmentation = async (params: any) => {
+  const res = await pauseDataAugmentationApi(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)
@@ -506,6 +527,7 @@ let itemsOptions: ProForm.ItemsOptions[] = [
   {
     label: '图片集压缩包',
     prop: 'inputOssId',
+    tooltip: zipFileDes,
     rules: [{ required: true, message: '数据压缩包不能为空', trigger: 'change' }],
     compOptions: {
       elTagName: 'file-upload',
@@ -542,21 +564,36 @@ const addParams = params => {
   }
   let validJsonString = params.replace(/'/g, '"')
   try {
-    const obj: { [key: string]: number } = JSON.parse(validJsonString)
-    Object.keys(obj).forEach(key => {
-      model.value[key] = obj[key]
-
+    const obj = JSON.parse(validJsonString)
+    obj.forEach(param => {
+      model.value[param.agName] = param.defaultValue
       itemsOptions.push({
-        label: key,
-        prop: key,
-        rules: [{ trigger: 'blur' }],
+        tooltip: param.prompt,
+        label: param.name,
+        prop: param.agName,
+        rules: [],
         compOptions: {
           type: 'input',
           clearable: true,
-          placeholder: '默认值为' + obj[key]
+          placeholder: '默认值为' + param.defaultValue
         }
       })
     })
+    // 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: [{ trigger: 'blur' }],
+    //     compOptions: {
+    //       type: 'input',
+    //       clearable: true,
+    //       placeholder: '默认值为' + obj[key]
+    //     }
+    //   })
+    // })
   } catch (error) {
     console.error('解析 JSON 字符串时出错:', error)
   }

+ 146 - 106
src/views/demo/targetTrack/index.vue

@@ -19,12 +19,18 @@
       </template>
       <!-- 表格操作 -->
       <template #operation="scope">
+        <el-button type="primary" link icon="View" @click="startDataAugmentation(scope.row)" v-if="scope.row.status == '4'"> 继续 </el-button>
         <el-button type="primary" link icon="View" @click="startDataAugmentation(scope.row)" v-if="scope.row.status == '0'"> 开始 </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-popconfirm title="确定暂停此任务吗?" @confirm="pauseDataAugmentation(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="preview(scope.row)" v-if="scope.row.status == '2'"> 预览 </el-button>
         <el-button type="primary" link icon="View" @click="downloadFile(scope.row)" v-if="scope.row.status == '2'"> 导出 </el-button>
         <el-button type="primary" link icon="View" @click="openMetricDialog(scope.row.id)" v-if="scope.row.status == '2'"> 指标 </el-button>
@@ -37,7 +43,7 @@
           icon="View"
           v-auth="['demo:DataAugmentation:query']"
           @click="viewLogRef.handleOpen(scope.row.id)"
-          v-if="scope.row.status != '0' && scope.row.status != '1'"
+          v-if="scope.row.status != '0'"
         >
           日志
         </el-button>
@@ -124,8 +130,10 @@ import {
   getTaskDictData,
   getMetricApi,
   getVideoUrl,
-  getCompareImageApiNew
+  getCompareImageApiNew,
+  pauseDataAugmentationApi
 } from '@/api/modules/demo/dataAugmentation'
+import { getDictsApi } from '@/api/modules/system/dictData'
 // import { VideoPlayer } from 'vue-video-player'
 // import 'vue-video-player/dist/simple.css'
 
@@ -350,32 +358,26 @@ const hyperparameterConfiguration = []
 const viewLogRef = ref()
 
 const getTaskType = async () => {
-  const res: any = await getTaskDictData()
+  const res: any = await getTaskDictData('多目标跟踪')
   if (res.data.length != 0) {
     taskType.value = res.data
       .map(item => {
-        if (item.taskType === '多目标跟踪') {
-          return {
-            label: item.taskType,
-            value: item.taskType
-          }
-        } else {
-          return null
+        return {
+          label: item.taskType,
+          value: item.taskType
         }
       })
       .filter(item => item !== null)
     res.data.forEach(item => {
-      if (item.taskType === '多目标跟踪') {
-        taskTypeEnums.push({
-          label: item.taskType,
-          value: item.taskType,
-          disabled: false,
-          tagType: 'default'
-        })
-        let obj = {}
-        obj[item.taskType] = item.hyperparameterConfiguration
-        hyperparameterConfiguration.push(obj)
-      }
+      taskTypeEnums.push({
+        label: item.taskType,
+        value: item.taskType,
+        disabled: false,
+        tagType: 'default'
+      })
+      let obj = {}
+      obj[item.taskType] = item.hyperparameterConfiguration
+      hyperparameterConfiguration.push(obj)
     })
   }
 }
@@ -393,8 +395,21 @@ onMounted(() => {
     proTable.value?.getTableList()
   }, 5000)
   getTaskType()
+  getZipFileDes()
 })
 
+const zipFileDes = ref('')
+const getZipFileDes = async () => {
+  let res = await getDictsApi('zip_file_format_description')
+
+  res.data.forEach(item => {
+    // 检查item对象是否包含dict和des属性
+    if (item.dictLabel === '多目标追踪') {
+      zipFileDes.value = item.remark
+    }
+  })
+}
+
 const startDataAugmentation = async (params: any) => {
   const res = await startDataAugmentationApi(params.id)
   if (res.code === 200) {
@@ -414,6 +429,15 @@ const stopDataAugmentation = async (params: any) => {
   }
   proTable.value?.getTableList()
 }
+const pauseDataAugmentation = async (params: any) => {
+  const res = await pauseDataAugmentationApi(params.id)
+  if (res.code === 200) {
+    ElMessage.success('任务暂停成功')
+  } else {
+    ElMessage.error('任务暂停失败!')
+  }
+  proTable.value?.getTableList()
+}
 
 // ProTable 实例
 const proTable = ref<ProTableInstance>()
@@ -612,6 +636,7 @@ let itemsOptions: ProForm.ItemsOptions[] = [
   {
     label: '图片集压缩包',
     prop: 'inputOssId',
+    tooltip: zipFileDes,
     rules: [{ required: true, message: '数据压缩包不能为空', trigger: 'change' }],
     compOptions: {
       elTagName: 'file-upload',
@@ -647,94 +672,109 @@ const addParams = (params, task_Type) => {
     return
   }
   let validJsonString = params.replace(/'/g, '"')
-  if (task_Type === '多目标跟踪') {
-    itemsOptions.push({
-      label: '模型',
-      prop: 'yolo_model',
-      rules: [{ trigger: 'blur' }],
-      compOptions: {
-        elTagName: 'select',
-        enum: modelType,
-        placeholder: '默认值为' + 'yolov8__best.pt'
-      }
-    })
-    itemsOptions.push({
-      label: '跟踪方法',
-      prop: 'tracking_method',
-      rules: [{ trigger: 'blur' }],
-
-      compOptions: {
-        elTagName: 'select',
-        enum: trackingMethod,
-        placeholder: '默认值为' + 'bytetrack'
-      }
-    })
-  }
-  model.value['tracking_method'] = 'bytetrack'
+  // if (task_Type === '多目标跟踪') {
+  //   itemsOptions.push({
+  //     label: '模型',
+  //     prop: 'yolo_model',
+  //     rules: [{ trigger: 'blur' }],
+  //     compOptions: {
+  //       elTagName: 'select',
+  //       enum: modelType,
+  //       placeholder: '默认值为' + 'yolov8__best.pt'
+  //     }
+  //   })
+  //   itemsOptions.push({
+  //     label: '跟踪方法',
+  //     prop: 'tracking_method',
+  //     rules: [{ trigger: 'blur' }],
+
+  //     compOptions: {
+  //       elTagName: 'select',
+  //       enum: trackingMethod,
+  //       placeholder: '默认值为' + 'bytetrack'
+  //     }
+  //   })
+  // }
+  // model.value['tracking_method'] = 'bytetrack'
   model.value['yolo_model'] = 'yolov8__best.pt'
   try {
-    const obj: { [key: string]: number } = JSON.parse(validJsonString)
-    Object.keys(obj).forEach(key => {
-      model.value[key] = obj[key]
-      if (key === 'conf' || key === 'iou') {
-        itemsOptions.push({
-          label: key,
-          prop: key,
-          rules: [
-            {
-              trigger: 'change',
-              validator: (rule, value, callback) => {
-                if (value === '' || value === undefined) {
-                  return callback()
-                }
-                if (!value) {
-                  return callback(new Error('请输入一个0到1之间的浮点数'))
-                }
-                const regex = /^(0(\.\d+)?|1(\.0+)?)$/
-                if (!regex.test(value)) {
-                  return callback(new Error('请输入一个0到1之间的浮点数'))
-                }
-                callback()
-              }
-            }
-          ],
-          compOptions: {
-            type: 'input',
-            clearable: true,
-            placeholder: '默认值为' + obj[key]
-          }
-        })
-      } else if (key === 'imgsz') {
-        itemsOptions.push({
-          label: key,
-          prop: key,
-          rules: [
-            {
-              trigger: 'change',
-              validator: (rule, value, callback) => {
-                //console.log(value)
-                if (value === '' || value === undefined) {
-                  return callback()
-                }
-                if (!value) {
-                  return callback(new Error('请输入一个大于0的整数'))
-                }
-                const regex = /^[1-9]\d*$/
-                if (!regex.test(value)) {
-                  return callback(new Error('请输入一个大于0的整数'))
-                }
-                callback()
-              }
-            }
-          ],
-          compOptions: {
-            type: 'input',
-            clearable: true,
-            placeholder: '默认值为' + obj[key]
-          }
-        })
-      }
+    const obj = JSON.parse(validJsonString)
+    obj.forEach(param => {
+      model.value[param.agName] = param.defaultValue
+      itemsOptions.push({
+        tooltip: param.prompt,
+        label: param.name,
+        prop: param.agName,
+        rules: [],
+        compOptions: {
+          type: 'input',
+          clearable: true,
+          placeholder: '默认值为' + param.defaultValue
+        }
+      })
     })
+    // const obj: { [key: string]: number } = JSON.parse(validJsonString)
+    // Object.keys(obj).forEach(key => {
+    //   model.value[key] = obj[key]
+    //   if (key === 'conf' || key === 'iou') {
+    //     itemsOptions.push({
+    //       label: key,
+    //       prop: key,
+    //       rules: [
+    //         {
+    //           trigger: 'change',
+    //           validator: (rule, value, callback) => {
+    //             if (value === '' || value === undefined) {
+    //               return callback()
+    //             }
+    //             if (!value) {
+    //               return callback(new Error('请输入一个0到1之间的浮点数'))
+    //             }
+    //             const regex = /^(0(\.\d+)?|1(\.0+)?)$/
+    //             if (!regex.test(value)) {
+    //               return callback(new Error('请输入一个0到1之间的浮点数'))
+    //             }
+    //             callback()
+    //           }
+    //         }
+    //       ],
+    //       compOptions: {
+    //         type: 'input',
+    //         clearable: true,
+    //         placeholder: '默认值为' + obj[key]
+    //       }
+    //     })
+    //   } else if (key === 'imgsz') {
+    //     itemsOptions.push({
+    //       label: key,
+    //       prop: key,
+    //       rules: [
+    //         {
+    //           trigger: 'change',
+    //           validator: (rule, value, callback) => {
+    //             //console.log(value)
+    //             if (value === '' || value === undefined) {
+    //               return callback()
+    //             }
+    //             if (!value) {
+    //               return callback(new Error('请输入一个大于0的整数'))
+    //             }
+    //             const regex = /^[1-9]\d*$/
+    //             if (!regex.test(value)) {
+    //               return callback(new Error('请输入一个大于0的整数'))
+    //             }
+    //             callback()
+    //           }
+    //         }
+    //       ],
+    //       compOptions: {
+    //         type: 'input',
+    //         clearable: true,
+    //         placeholder: '默认值为' + obj[key]
+    //       }
+    //     })
+    //   }
+    // })
   } catch (error) {
     console.error('解析 JSON 字符串时出错:', error)
   }

+ 134 - 98
src/views/demo/toInfrared/index.vue

@@ -24,10 +24,8 @@
       </template>
       <!-- 表格操作 -->
       <template #operation="scope">
-        <el-button type="primary" link icon="View" v-if="scope.row.algorithmModelId != null" @click="openModelDialog(scope.row)">
-          <!--@click="openStartDialog(scope.row)"  -->
-          详情
-        </el-button>
+        <el-button type="primary" link icon="View" @click="openDialog(3, '详情', scope.row)"> 详情</el-button>
+        <el-button type="primary" link icon="EditPen" v-auth="['demo:toInfrared:edit']" @click="openDialog(2, '编辑', scope.row)"> 编辑 </el-button>
         <el-button
           type="primary"
           link
@@ -94,8 +92,6 @@
         >
           日志
         </el-button>
-        <!-- <el-button type="primary" link icon="View" v-auth="['demo:toInfrared:query']" @click="openDialog(3, '查看', scope.row)"> 查看 </el-button> -->
-        <!-- <el-button type="primary" link icon="EditPen"v-auth="['demo:toInfrared:edit']" @click="openDialog(2, '编辑', scope.row)"> 编辑 </el-button> -->
         <el-button
           type="primary"
           link
@@ -174,22 +170,29 @@ import {
 } from '@/api/modules/demo/toInfrared'
 
 import { getImagesApi, listDataSeqApi } from '@/api/modules/demo/DataSeq'
+import { getDictsApi } from '@/api/modules/system/dictData'
 
-import { enumAlgorithmModelTrackApi } from '@/api/modules/demo/AlgorithmModelTrack'
-import { getAlgorithmModelTrackApi } from '@/api/modules/demo/AlgorithmModelTrack'
-import { enumAlgorithmConfigTrackApi } from '@/api/modules/demo/AlgorithmConfigTrack'
+import { enumAlgorithmModelTrackApi, addAlgorithmModelTrackApi, getAlgorithmModelTrackApi } from '@/api/modules/demo/AlgorithmModelTrack'
+import { enumAlgorithmConfigTrackApi, getAlgorithmConfigTrackApi } from '@/api/modules/demo/AlgorithmConfigTrack'
 import statusEnums from '@/utils/status'
 import { AlgorithmType, SubSystem, SubSystem__, enumsAlgorithmType, enumsSubSystem, AlgorithmType2 } from '@/views/demo/utils'
 import PreviewCompareImages from '@/views/demo/components/PreviewCompareImages.vue'
-import { addAlgorithmModelTrackApi } from '@/api/modules/demo/AlgorithmModelTrack'
 import ViewLog from '@/views/demo/components/ViewLog.vue'
 import useWebSocketStore from '@/stores/modules/websocket'
 import { resetHeart } from '@/utils/websocket'
-
 import ShowStatisticResult from '@/views/demo/components/ShowStatisticResult.vue'
 
 const showStatisticResultRef = ref()
 
+const zipFileDescDict = ref<any>({})
+onMounted(async () => {
+  const res = await getDictsApi('zip_file_format_description')
+  for (let i = 0; i < res.data.length; i++) {
+    const item = res.data[i]
+    zipFileDescDict.value[item.dictValue] = item.remark
+  }
+})
+
 onMounted(() => {
   const websocketStore = useWebSocketStore()
   websocketStore.websocket.onmessage = (e: any) => {
@@ -217,7 +220,7 @@ onMounted(async () => {
   enumsAlgorithmConfigTrack.value = []
   const tmp_data: any = result['data']
   for (const item of tmp_data) {
-    if (item.subsystem === SubSystem__['可见光转红外'] && item.type === AlgorithmType2['预测/推理']) {
+    if (item.subsystem === SubSystem__['可见光转红外']) {
       item['label'] = item['label'] + '-' + SubSystem[item['subsystem']] + '-' + AlgorithmType[item['type']]
       enumsAlgorithmConfigTrack.value.push(item)
     }
@@ -252,6 +255,7 @@ const setItemsOptions222 = () => {
       prop: 'modelName',
       rules: [{ required: true, message: '模型名称不能为空', trigger: 'blur' }],
       compOptions: {
+        elTagName: 'input',
         placeholder: '请输入模型名称'
       }
     },
@@ -260,6 +264,7 @@ const setItemsOptions222 = () => {
       prop: 'modelPath',
       rules: [{ required: false, message: '模型文件不能为空', trigger: 'blur' }],
       compOptions: {
+        elTagName: 'input',
         placeholder: '请输入模型名称',
         disabled: true
       }
@@ -269,6 +274,7 @@ const setItemsOptions222 = () => {
       prop: 'remarks',
       rules: [{ required: false, message: '备注不能为空', trigger: 'blur' }],
       compOptions: {
+        elTagName: 'input',
         placeholder: '请输入备注'
       }
     }
@@ -334,24 +340,6 @@ const showToInfraredModel = async (id: any) => {
 
 const viewLogRef = ref()
 
-const openModelDialog = async row => {
-  const algorithmModelId = row.algorithmModelId
-  const result: any = await getAlgorithmModelTrackApi(algorithmModelId)
-
-  // console.log(result.data)
-  setItemsOptionsModel()
-  const params = {
-    title: '模型',
-    width: 580,
-    isEdit: false,
-    itemsOptions: itemsOptions,
-    model: result.data,
-    api: updateToInfraredApi,
-    getTableList: proTable.value?.getTableList
-  }
-  formDialogRef.value?.openDialog(params)
-}
-
 const startToInfrared = async (params: any) => {
   const res: any = await startToInfraredApi(params.id)
   if (res.code === 200) {
@@ -438,13 +426,20 @@ 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 getToInfraredApi(row?.id || null)
+    res = await getToInfraredApi(row.id || null)
+    const params = JSON.parse(res.data['algorithmParameters'])
+    if (params.otherParams) {
+      res.data = { ...res.data, ...params.otherParams }
+    }
   }
   // 重置表单
   setItemsOptions()
+  if (row?.id) {
+    itemsOptions = await updateItemsOptions(row.algorithmId)
+  }
   const params = {
     title,
-    width: 580,
+    width: 600,
     isEdit: type !== 3,
     itemsOptions: itemsOptions,
     model: type == 1 ? {} : res.data,
@@ -501,6 +496,14 @@ const columns = reactive<ColumnProps<any>[]>([
     label: '模型名称',
     width: 200
   },
+  {
+    prop: 'algorithmParameters',
+    label: '算法参数',
+    search: {
+      el: 'input'
+    },
+    width: 150
+  },
   // {
   //   prop: 'algorithmModelId',
   //   label: '模型',
@@ -544,6 +547,52 @@ const columns = reactive<ColumnProps<any>[]>([
   },
   { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
 ])
+
+const remove_unnecessary_parameters = (itemsOptions: ProForm.ItemsOptions[]): ProForm.ItemsOptions[] => {
+  try {
+    const endIndex = itemsOptions.findIndex(option => option['label'] === '备注')
+    if (endIndex !== -1) {
+      itemsOptions = itemsOptions.slice(0, endIndex + 1)
+    }
+    return itemsOptions
+  } catch (error) {
+    console.error('移除不必要的参数时出错:', error)
+    // ElMessage.error('移除不必要的参数时出错,请检查!');
+    return itemsOptions // 返回原始选项,避免进一步的问题
+  }
+}
+
+const updateItemsOptions = async (algorithmId: any) => {
+  try {
+    const result = await getAlgorithmConfigTrackApi(algorithmId)
+    if (result.code === 200) {
+      // 处理结果
+      const parameters = JSON.parse(result.data['parameters'])
+      // console.log('parameters: ', parameters)
+
+      const itemsOptions_new = remove_unnecessary_parameters(itemsOptions)
+      for (const item of parameters) {
+        // 添加新的表单项选项
+        itemsOptions_new.push({
+          label: item['name'],
+          prop: item['agName'],
+          rules: [{ required: item['required'], message: item['agName'] + '不能为空', trigger: 'blur' }],
+          tooltip: item['prompt'],
+          compOptions: {
+            elTagName: 'input',
+            placeholder: item['defaultValue']
+            // value: item['defaultValue']
+          }
+        })
+      }
+      formDialogRef.value?.updateItemOptions(itemsOptions_new)
+      return itemsOptions_new
+    }
+  } catch (err) {
+    console.log(err)
+    ElMessage.error('获取算法配置失败,请检查!')
+  }
+}
 // 表单配置项
 let itemsOptions: ProForm.ItemsOptions[] = []
 const setItemsOptions = () => {
@@ -553,6 +602,7 @@ const setItemsOptions = () => {
       prop: 'name',
       rules: [{ required: true, message: '任务名称不能为空', trigger: 'blur' }],
       compOptions: {
+        elTagName: 'input',
         placeholder: '请输入任务名称'
       }
     },
@@ -571,6 +621,7 @@ const setItemsOptions = () => {
       label: '上传数据集',
       prop: 'inputOssId',
       rules: [{ required: false, message: '数据集不能为空', trigger: 'blur' }],
+      tooltip: zipFileDescDict.value['to_infrared'],
       compOptions: {
         elTagName: 'file-upload',
         fileSize: 4096,
@@ -578,14 +629,61 @@ const setItemsOptions = () => {
         placeholder: '请上传数据集'
       }
     },
+    {
+      label: '选择算法',
+      prop: 'algorithmId',
+      rules: [{ required: true, message: '算法不能为空', trigger: 'blur' }],
+      compOptions: {
+        elTagName: 'select',
+        placeholder: '请选择算法',
+        enum: enumsAlgorithmConfigTrack,
+        clearable: true,
+        onChange: async (value: any) => {
+          if (value != undefined && value != null && value != '') {
+            await updateItemsOptions(value)
+          }
+        }
+      }
+    },
+    {
+      label: '任务类型',
+      prop: 'type',
+      rules: [{ required: true, message: '任务类型不能为空', trigger: 'blur' }],
+      compOptions: {
+        disabled: true,
+        elTagName: 'select',
+        placeholder: '请选择模任务类型',
+        enum: enumsAlgorithmType,
+        clearable: true,
+        value: ''
+      },
+      show: params => {
+        if (params.value.algorithmId != undefined) {
+          for (let i = 0; i < enumsAlgorithmConfigTrack.value.length; i++) {
+            if (enumsAlgorithmConfigTrack.value[i]['value'] === params.value.algorithmId) {
+              params.value.type = enumsAlgorithmConfigTrack.value[i]['type']
+              return true
+            }
+          }
+        }
+        return false
+      }
+    },
     {
       label: '选择模型',
       prop: 'algorithmModelId',
       rules: [{ required: true, message: '模型不能为空', trigger: 'blur' }],
+      show: params => {
+        if (params.value.type == AlgorithmType2['预测/推理']) {
+          return true
+        }
+        return false
+      },
       compOptions: {
         elTagName: 'select',
         placeholder: '请选择模型',
-        enum: enumsAlgorithmModelTrack
+        enum: enumsAlgorithmModelTrack,
+        clearable: true
       }
     },
     {
@@ -593,6 +691,7 @@ const setItemsOptions = () => {
       prop: 'remarks',
       rules: [],
       compOptions: {
+        elTagName: 'input',
         placeholder: '请输入备注'
       }
     }
@@ -655,6 +754,7 @@ const setItemsOptions2 = () => {
       prop: 'name',
       rules: [{ required: true, message: '任务名称不能为空', trigger: 'blur' }],
       compOptions: {
+        elTagName: 'input',
         disabled: true,
         placeholder: '请输入任务名称'
       }
@@ -674,71 +774,7 @@ const setItemsOptions2 = () => {
       prop: 'remarks',
       rules: [],
       compOptions: {
-        placeholder: '请输入备注'
-      }
-    }
-  ]
-}
-
-const setItemsOptionsModel = () => {
-  itemsOptions = [
-    {
-      label: '算法ID',
-      prop: 'algorithmId',
-      rules: [{ required: true, message: '算法不能为空', trigger: 'blur' }],
-      compOptions: {
-        disabled: true,
-        placeholder: '请输入算法'
-      }
-    },
-    {
-      label: '算法类型',
-      prop: 'algorithmType',
-      rules: [{ required: true, message: '算法不能为空', trigger: 'blur' }],
-      compOptions: {
-        disabled: true,
-        elTagName: 'select',
-        placeholder: '请输入算法',
-        enum: enumsAlgorithmConfigTrack
-      }
-    },
-    {
-      label: '算法参数',
-      prop: 'parameterConfig',
-      rules: [{ required: true, message: '模型名称不能为空', trigger: 'blur' }],
-      compOptions: {
-        placeholder: '请输入模型名称'
-      }
-    },
-    {
-      label: '模型ID',
-      prop: 'id',
-      rules: [{ required: true, message: '模型名称不能为空', trigger: 'blur' }],
-      compOptions: {
-        placeholder: '请输入模型名称'
-      }
-    },
-    {
-      label: '模型名称',
-      prop: 'modelName',
-      rules: [{ required: true, message: '模型名称不能为空', trigger: 'blur' }],
-      compOptions: {
-        placeholder: '请输入模型名称'
-      }
-    },
-    {
-      label: '模型保存路径',
-      prop: 'modelAddress',
-      rules: [{ required: true, message: '模型名称不能为空', trigger: 'blur' }],
-      compOptions: {
-        placeholder: '请输入模型名称'
-      }
-    },
-    {
-      label: '备注',
-      prop: 'remarks',
-      rules: [{ required: false, message: '备注不能为空', trigger: 'blur' }],
-      compOptions: {
+        elTagName: 'input',
         placeholder: '请输入备注'
       }
     }

+ 71 - 10
src/views/demo/traceMerge/index.vue

@@ -26,7 +26,10 @@
         <!--          编辑-->
         <!--        </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="execute(scope.row)"> 开始任务 </el-button>
+        <el-button type="primary" link icon="View" @click="hangupTask(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="stopTask(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>
         <el-button type="primary" link icon="View" @click="showResult(scope.row)"> 查看指标 </el-button>
@@ -42,8 +45,25 @@
           <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>
+          <span style="min-width: 80px">
+            任务文件
+            <el-tooltip :content="fileDescription" placement="top">
+              <el-icon>
+                <InfoFilled />
+              </el-icon>
+            </el-tooltip>
+          </span>
+
+          <file @update:model-value="updateFiles" :file-size="20" :file-type="['mat', 'json', 'txt']"></file>
+        </el-container>
+        <el-container v-for="(item, index) in jsonParams" :key="index" style="align-items: center; margin-top: 5px">
+          <span style="min-width: 80px; max-width: 150px">{{ item.name }}</span>
+          <el-tooltip :content="item.prompt" placement="top">
+            <el-icon>
+              <InfoFilled />
+            </el-icon>
+          </el-tooltip>
+          <el-input v-model="item.value" :placeholder="item.defaultValue" style="max-width: 300px" />
         </el-container>
       </el-container>
       <span class="dialog-footer">
@@ -56,7 +76,7 @@
       <el-container direction="vertical">
         <el-header>第 {{ dataIndex + 1 }} 张, 共 {{ resultData.length }} 张</el-header>
         <el-container direction="horizontal" style="margin-top: 20px">
-          <div style=" place-items: center center;width: 100px">帧率</div>
+          <div style="place-items: center center; width: 100px">帧率</div>
           <el-input v-model="frameSpeed" style="max-width: 200px" />
           <el-button @click="onSpeedChange" style="margin-left: 20px">确定</el-button>
         </el-container>
@@ -74,6 +94,7 @@
       </el-container>
     </el-dialog>
     <ResultDialog ref="ResultDialogRef" />
+    <PreviewImages ref="previewImagesRef" />
   </div>
 </template>
 
@@ -93,15 +114,18 @@ import {
   exportTraceMergeApi,
   getResApi,
   getTraceMergeApi,
+  hangupApi,
   importTemplateApi,
   importTraceMergeDataApi,
   listTraceMergeApi,
+  stopApi,
   updateTraceMergeApi
 } from '@/api/modules/demo/traceMerge'
 import File from '@/components/Upload/File.vue'
 import { getDictsApi } from '@/api/modules/system/dictData'
 import http from '@/api'
 import ResultDialog from '@/components/ResultDialog/ResultDialog.vue'
+import { getJsonParams, getOneAlgorithmConfigApi } from '@/api/modules/demo/algorithmConfig'
 
 const ResultDialogRef = ref<InstanceType<typeof ResultDialog> | null>(null)
 const showResult = async function (row) {
@@ -143,6 +167,8 @@ const onSpeedChange = () => {
     }
   }, 1000 / frameSpeed.value)
 }
+import PreviewImages from '@/views/demo/components/PreviewImages.vue'
+const previewImagesRef = ref()
 const display = function (row) {
   // console.log(row)
   getResApi({ taskId: row.id }).then(res => {
@@ -152,16 +178,17 @@ const display = function (row) {
     }
     let arr = row.resultPath.split('ObjectDetection_Web')
     let pathPrefix = arr[arr.length - 1]
-    resultData.value = []
+    resultData.value = ['']
     for (let i = 1; i < res.data[0]; i++) {
       let _str = '' + i
       while (_str.length < 3) {
         _str = '0' + _str
       }
-      resultData.value.push(pathPrefix + '/number' + _str + '.png')
+      resultData.value.push('/profile' + pathPrefix + '/number' + _str + '.png')
     }
     console.log('resultData', resultData.value)
-    displayDialogVisible.value = true
+    // displayDialogVisible.value = true
+    previewImagesRef.value?.handleOpenWithPicArray(resultData.value)
   })
 }
 
@@ -176,7 +203,41 @@ const execute = function (row) {
   })
 }
 
-const createTask = function () {
+const hangupTask = function (row) {
+  hangupApi({ taskId: row.id }).then(res => {
+    if (res.code == 200) {
+      ElMessage.success('暂停成功!')
+    } else {
+      ElMessage.error('暂停失败: ' + res.msg)
+    }
+  })
+}
+
+const stopTask = function (row) {
+  stopApi({ taskId: row.id }).then(res => {
+    if (res.code == 200) {
+      ElMessage.success('停止成功!')
+    } else {
+      ElMessage.error('停止失败: ' + res.msg)
+    }
+  })
+}
+const fileDescription = ref('')
+const jsonParams = ref([])
+const createTask = async function () {
+  const res = await getOneAlgorithmConfigApi({ algorithmName: '多源信息融合' })
+  // console.log(res)
+  jsonParams.value = JSON.parse(res.data.parameters)
+
+  let _res = await getDictsApi('zip_file_format_description')
+
+  _res.data.forEach(item => {
+    // 检查item对象是否包含dict和des属性
+    if (item.dictLabel === '多源信息融合') {
+      fileDescription.value = item.remark
+    }
+  })
+
   createTaskDialogVisible.value = true
   params.value = {
     preprocessPath: null,
@@ -186,13 +247,13 @@ const createTask = function () {
 
 const submitCreateTask = function () {
   if (params.value.preprocessPath == null || params.value.preprocessPath === '') {
-    ElMessage.error('请上传mat文件!')
+    ElMessage.error('请上传源数据文件!')
     return
   } else if (params.value.name == null || params.value.name === '') {
     ElMessage.error('请输入任务名称!')
     return
   }
-  addTraceMergeApi(params.value)
+  addTraceMergeApi({ parameters: JSON.stringify(getJsonParams(jsonParams.value)), ...params.value })
     .then(res => {
       console.log(res)
       if (res.code === 200) {

+ 201 - 27
src/views/demo/trackSequence/index.vue

@@ -9,10 +9,7 @@
     <ProTable ref="proTable" :columns="columns" row-key="id" :request-api="listTrackSequenceApi">
       <!-- 表格 header 按钮 -->
       <template #tableHeader="scope">
-        <el-button type="primary" v-auth="['demo:trackSequence:add']" icon="CirclePlus" @click="openDialog(1, '注视轨迹序列新增')">
-          新增(MASC)
-        </el-button>
-        <el-button type="primary" v-auth="['demo:trackSequence:add']" icon="CirclePlus" @click="addCATDialog()"> 新增(CAT) </el-button>
+        <el-button type="primary" v-auth="['demo:trackSequence:add']" icon="CirclePlus" @click="openDialog(1, '注视轨迹序列新增')"> 新增 </el-button>
         <!-- <el-button type="primary" v-auth="['demo:trackSequence:import']" icon="Upload" plain @click="batchAdd"> 导入 </el-button>
         <el-button type="primary" v-auth="['demo:trackSequence:export']" icon="Download" plain @click="downloadFile"> 导出 </el-button> -->
         <el-button
@@ -28,10 +25,11 @@
       </template>
       <!-- 表格操作 -->
       <template #operation="scope">
-        <el-button type="primary" link icon="View" v-if="scope.row.algorithmModelId != null" @click="openModelDialog(scope.row.id)">
+        <el-button type="primary" link icon="View" @click="openDialog(3, '详情', scope.row)">
           <!--@click="openStartDialog(scope.row)"  -->
           详情
         </el-button>
+        <el-button type="primary" link icon="EditPen" @click="openDialog(2, '编辑', scope.row)"> 编辑 </el-button>
         <el-button
           type="primary"
           link
@@ -116,8 +114,6 @@
         >
           模型
         </el-button>
-        <!-- <el-button type="primary" link icon="View" v-auth="['demo:toInfrared:query']" @click="openDialog(3, '查看', scope.row)"> 查看 </el-button> -->
-        <!-- <el-button type="primary" link icon="EditPen"v-auth="['demo:toInfrared:edit']" @click="openDialog(2, '编辑', scope.row)"> 编辑 </el-button> -->
         <el-button
           type="primary"
           link
@@ -134,7 +130,7 @@
     <ImportExcel ref="dialogRef" />
     <ViewLog ref="viewLogRef" :get-log-api="getLogTrackSequenceApi" />
     <PreviewCompareImages ref="previewImagesRef" />
-    <ShowStatisticResult ref="showStatisticResultRef" :api="getStatisticsResultToInfraredApi" />
+    <ShowStatisticResult ref="showStatisticResultRef" :api="getStatisticsResultTrackSequenceApi" />
     <ShowStatisticResult ref="showEvaluateResultRef" :api="previewEvaluateTrackSequenceApi" title="评估结果" />
     <el-dialog v-model="showModelDialogVisible" title="模型列表" width="1000">
       <el-scrollbar ref="scrollbarRef" id="scrollbarRef1" height="500px">
@@ -154,9 +150,12 @@
                 <el-link :href="model.url" type="primary" icon="Download" :underline="false" target="_blank" style="margin-right: 20px"
                   >下载
                 </el-link>
-                <el-button type="success" link @click="addModel(model.path, model.name)"
-                  ><el-icon> <Plus /> </el-icon>添加模型</el-button
-                >
+                <el-button type="success" link @click="addModel(model.path, model.name)">
+                  <el-icon>
+                    <Plus />
+                  </el-icon>
+                  添加模型
+                </el-button>
               </el-form-item>
             </el-form>
           </el-card>
@@ -193,11 +192,11 @@ import {
   showCATModelApi,
   previewPredictResultTrackSequenceModelApi,
   previewEvaluateTrackSequenceApi,
-  getStatisticsResultToInfraredApi
+  getStatisticsResultTrackSequenceApi
 } from '@/api/modules/demo/trackSequence'
 import { enumAlgorithmModelTrackApi } from '@/api/modules/demo/AlgorithmModelTrack'
 import { getAlgorithmModelTrackApi } from '@/api/modules/demo/AlgorithmModelTrack'
-import { enumAlgorithmConfigTrackApi } from '@/api/modules/demo/AlgorithmConfigTrack'
+import { enumAlgorithmConfigTrackApi, getAlgorithmConfigTrackApi } from '@/api/modules/demo/AlgorithmConfigTrack'
 
 import { listDataSeqApi } from '@/api/modules/demo/DataSeq'
 import statusEnums from '@/utils/status'
@@ -209,6 +208,17 @@ import { resetHeart } from '@/utils/websocket'
 import PreviewCompareImages from '@/views/demo/components/PreviewCompareImages.vue'
 
 import ShowStatisticResult from '@/views/demo/components/ShowStatisticResult.vue'
+import { getTargetDetectionApi } from '@/api/modules/demo/TargetDetection'
+
+import { getDictsApi } from '@/api/modules/system/dictData'
+const zipFileDescDict = ref<any>({})
+onMounted(async () => {
+  const res = await getDictsApi('zip_file_format_description')
+  for (let i = 0; i < res.data.length; i++) {
+    const item = res.data[i]
+    zipFileDescDict.value[item.dictValue] = item.remark
+  }
+})
 
 const showStatisticResultRef = ref()
 const showEvaluateResultRef = ref()
@@ -274,7 +284,7 @@ const setItemsOptions222 = async () => {
       prop: 'modelName',
       rules: [{ required: true, message: '模型名称不能为空', trigger: 'blur' }],
       compOptions: {
-        disabled: true,
+        disabled: false,
         placeholder: '请输入模型名称'
       }
     },
@@ -352,6 +362,7 @@ const setItemsOptionsAddCAT = () => {
       label: '上传数据集',
       prop: 'inputOssId',
       rules: [{ required: false, message: '数据集不能为空', trigger: 'blur' }],
+      tooltip: zipFileDescDict.value['track_sequence'],
       compOptions: {
         elTagName: 'file-upload',
         fileSize: 4096,
@@ -409,7 +420,7 @@ const addCATDialog = async () => {
 
 const showEvaluate = (row: any) => {
   const newItem = {
-    id: row.id
+    predictTaskId: row.id
   }
 
   const enumsAlgorithmConfigTrack__: Array<any> = []
@@ -439,6 +450,28 @@ const showEvaluate = (row: any) => {
         enum: enumsAlgorithmConfigTrack__
       }
     },
+    {
+      label: '选择Label文件',
+      prop: 'inputLabelOssId',
+      rules: [{ required: false, message: 'Label文件不能为空', trigger: 'blur' }],
+      compOptions: {
+        elTagName: 'select',
+        placeholder: '请选择或者上传Label文件',
+        enum: datasetList,
+        clearable: true
+      }
+    },
+    {
+      label: '上传Label文件',
+      prop: 'inputLabelOssId',
+      rules: [{ required: false, message: '请上传Label文件', trigger: 'blur' }],
+      compOptions: {
+        elTagName: 'file-upload',
+        fileSize: 4096,
+        fileType: ['txt', 'xlsx', 'xls'],
+        placeholder: '请上传数据集'
+      }
+    },
     {
       label: '备注',
       prop: 'remarks',
@@ -454,7 +487,7 @@ const showEvaluate = (row: any) => {
     isEdit: true,
     itemsOptions: itemsOptions,
     model: newItem,
-    api: addEvaluateTrackSequenceApi,
+    api: addTrackSequenceApi,
     getTableList: proTable.value?.getTableList
   }
   formDialogRef.value?.openDialog(params)
@@ -557,10 +590,17 @@ 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 getTrackSequenceApi(row?.id || null)
+    res = await getTrackSequenceApi(row.id || null)
+    const params = JSON.parse(res.data['algorithmParameters'])
+    if (params.otherParams) {
+      res.data = { ...res.data, ...params.otherParams }
+    }
   }
   // 重置表单
   setItemsOptions()
+  if (row?.id) {
+    itemsOptions = await updateItemsOptions(row.algorithmId)
+  }
   const params = {
     title,
     width: 580,
@@ -619,6 +659,14 @@ const columns = reactive<ColumnProps<any>[]>([
     label: '模型名称',
     width: 200
   },
+  {
+    prop: 'algorithmParameters',
+    label: '算法参数',
+    search: {
+      el: 'input'
+    },
+    width: 150
+  },
   // {
   //   prop: 'algorithmModelId',
   //   label: '模型',
@@ -663,6 +711,52 @@ const columns = reactive<ColumnProps<any>[]>([
   { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
 ])
 
+const remove_unnecessary_parameters = (itemsOptions: ProForm.ItemsOptions[]): ProForm.ItemsOptions[] => {
+  try {
+    const endIndex = itemsOptions.findIndex(option => option['label'] === '备注')
+    if (endIndex !== -1) {
+      itemsOptions = itemsOptions.slice(0, endIndex + 1)
+    }
+    return itemsOptions
+  } catch (error) {
+    console.error('移除不必要的参数时出错:', error)
+    // ElMessage.error('移除不必要的参数时出错,请检查!');
+    return itemsOptions // 返回原始选项,避免进一步的问题
+  }
+}
+
+const updateItemsOptions = async (algorithmId: any) => {
+  try {
+    const result = await getAlgorithmConfigTrackApi(algorithmId)
+    if (result.code === 200) {
+      // 处理结果
+      const parameters = JSON.parse(result.data['parameters'])
+      // console.log('parameters: ', parameters)
+
+      const itemsOptions_new = remove_unnecessary_parameters(itemsOptions)
+      for (const item of parameters) {
+        // 添加新的表单项选项
+        itemsOptions_new.push({
+          label: item['name'],
+          prop: item['agName'],
+          rules: [{ required: item['required'], message: item['agName'] + '不能为空', trigger: 'blur' }],
+          tooltip: item['prompt'],
+          compOptions: {
+            elTagName: 'input',
+            placeholder: item['defaultValue']
+            // value: item['defaultValue']
+          }
+        })
+      }
+      formDialogRef.value?.updateItemOptions(itemsOptions_new)
+      return itemsOptions_new
+    }
+  } catch (err) {
+    console.log(err)
+    ElMessage.error('获取算法配置失败,请检查!')
+  }
+}
+
 // 表单配置项
 let itemsOptions: ProForm.ItemsOptions[] = []
 const setItemsOptions = () => {
@@ -690,6 +784,7 @@ const setItemsOptions = () => {
       label: '上传数据集',
       prop: 'inputOssId',
       rules: [{ required: false, message: '数据集不能为空', trigger: 'blur' }],
+      tooltip: zipFileDescDict.value['track_sequence'],
       compOptions: {
         elTagName: 'file-upload',
         fileSize: 4096,
@@ -698,24 +793,97 @@ const setItemsOptions = () => {
       }
     },
     {
-      label: '选择模型',
+      label: '选择算法',
+      prop: 'algorithmId',
+      rules: [{ required: true, message: '算法不能为空', trigger: 'blur' }],
+      compOptions: {
+        elTagName: 'select',
+        placeholder: '请选择算法',
+        enum: enumsAlgorithmConfigTrack,
+        clearable: true,
+        onChange: async (value: any) => {
+          if (value != undefined && value != null && value != '') {
+            await updateItemsOptions(value)
+          }
+        }
+      }
+    },
+    {
+      label: '任务类型',
+      prop: 'type',
+      rules: [{ required: true, message: '任务类型不能为空', trigger: 'blur' }],
+      compOptions: {
+        disabled: true,
+        elTagName: 'select',
+        placeholder: '请选择任务类型',
+        enum: enumsAlgorithmType,
+        clearable: true,
+        value: ''
+      },
+      show: params => {
+        if (params.value.algorithmId != undefined) {
+          for (let i = 0; i < enumsAlgorithmConfigTrack.value.length; i++) {
+            if (enumsAlgorithmConfigTrack.value[i]['value'] === params.value.algorithmId) {
+              params.value.type = enumsAlgorithmConfigTrack.value[i]['type']
+              return true
+            }
+          }
+        }
+        return false
+      }
+    },
+    {
+      label: '视觉模型',
       prop: 'algorithmModelId',
-      rules: [{ required: true, message: '模型不能为空', trigger: 'blur' }],
+      rules: [{ required: false, message: '模型不能为空', trigger: 'blur' }],
+      show: params => {
+        if (params.value.type == AlgorithmType2['预测/推理']) {
+          return true
+        }
+        params.value.algorithmModelId = ''
+        return false
+      },
       compOptions: {
         elTagName: 'select',
         placeholder: '请选择模型',
-        enum: enumsAlgorithmModelTrack
+        enum: enumsAlgorithmModelTrack,
+        clearable: true
       }
     },
     {
-      label: '选择算法',
-      prop: 'algorithmId',
-      rules: [{ required: true, message: '请选择算法', trigger: 'blur' }],
+      label: '目标检测模型',
+      prop: 'algorithmModelTargetDetectionId',
+      rules: [{ required: true, message: '目标检测模型不能为空', trigger: 'blur' }],
+      show: params => {
+        if (params.value.type == AlgorithmType2['预测/推理']) {
+          return true
+        }
+        params.value.algorithmModelTargetDetectionId = ''
+        return false
+      },
       compOptions: {
-        disabled: false,
         elTagName: 'select',
-        placeholder: '请输入算法',
-        enum: enumsAlgorithmConfigTrack
+        placeholder: '请选择目标检测模型',
+        enum: enumsAlgorithmModelTrack_TD,
+        clearable: true
+      }
+    },
+    {
+      label: '上传标签',
+      prop: 'inputLabelOssId',
+      rules: [{ required: true, message: '标签不能为空', trigger: 'blur' }],
+      tooltip: zipFileDescDict.value['track_sequence_label'],
+      show: params => {
+        if (params.value.type == AlgorithmType2['测试']) {
+          return true
+        }
+        return false
+      },
+      compOptions: {
+        elTagName: 'file-upload',
+        fileSize: 4096,
+        fileType: ['txt', 'xlsx', 'xls'],
+        placeholder: '请上传标签'
       }
     },
     {
@@ -819,6 +987,7 @@ onMounted(async () => {
 })
 
 const enumsAlgorithmModelTrack = ref<any>([])
+const enumsAlgorithmModelTrack_TD = ref<any>([])
 
 const updateEnumsAlgorithmModelTrack = async () => {
   const result: any = await enumAlgorithmModelTrackApi()
@@ -829,11 +998,16 @@ const updateEnumsAlgorithmModelTrack = async () => {
     if (item.type !== AlgorithmType2['预测/推理']) {
       continue
     }
-    if (SubSystem[item['subsystem']] === '注释轨迹序列' || SubSystem[item['subsystem']] === '目标检测') {
+    if (SubSystem[item['subsystem']] === '注释轨迹序列') {
       item['label'] =
         item['value'] + '_' + item['label'] + '-' + SubSystem[item['subsystem']] + '-' + AlgorithmType[item['type']] + '-' + item['algorithmName']
       enumsAlgorithmModelTrack.value.push(item)
     }
+    if (SubSystem[item['subsystem']] === '目标检测') {
+      item['label'] =
+        item['value'] + '_' + item['label'] + '-' + SubSystem[item['subsystem']] + '-' + AlgorithmType[item['type']] + '-' + item['algorithmName']
+      enumsAlgorithmModelTrack_TD.value.push(item)
+    }
   }
 }
 

+ 8 - 0
src/views/demo/utils.ts

@@ -16,6 +16,14 @@ export const Status = {
   中断: '4'
 }
 
+export const Status__ = {
+  '0': '未开始',
+  '1': '运行中',
+  '2': '完成',
+  '3': '失败',
+  '4': '中断'
+}
+
 export const AlgorithmType = {
   '0': '训练',
   '1': '测试',

+ 122 - 74
src/views/demo/videoStable/index.vue

@@ -30,16 +30,24 @@
           link
           icon="View"
           @click="startVideoStable(scope.row)"
-          v-if="scope.row.status == '0' || scope.row.status == '3' || scope.row.status == '4'"
+          v-if="scope.row.status == '0' || scope.row.status == '3' || scope.row.status == '2'"
         >
           开始
         </el-button>
+
+        <el-button type="primary" link icon="View" @click="startVideoStable(scope.row)" v-if="scope.row.status == '4'"> 继续 </el-button>
+        <el-popconfirm title="确定暂停此任务吗?" @confirm="hangupVideoStable(scope.row)" v-if="scope.row.status == '1'">
+          <template #reference>
+            <el-button type="primary" link icon="View"> 暂停 </el-button>
+          </template>
+        </el-popconfirm>
         <el-popconfirm title="确定终止此任务吗?" @confirm="stopVideoStable(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="previewCompare(scope.row)" v-if="scope.row.status == '2'"> 预览 </el-button>
+        <el-button type="primary" link icon="View" @click="showTimeResult(scope.row)"> 指标 </el-button>
         <el-button
           type="primary"
           link
@@ -63,6 +71,7 @@
     <ViewLog ref="viewLogRef" :get-log-api="getLogVideoStableApi" />
     <ImportExcel ref="dialogRef" />
     <PreviewCompareImages ref="previewCompareImagesRef" />
+    <ResultDialog ref="ResultDialogRef" />
   </div>
 </template>
 
@@ -89,13 +98,17 @@ import {
   // getCompareImageApi,
   // getCompareImageCountApi,
   getImagesApi,
-  getLogVideoStableApi
+  getLogVideoStableApi,
+  hangupVideoStableApi
 } from '@/api/modules/demo/videoStable'
 
 import useWebSocketStore from '@/stores/modules/websocket'
 import { resetHeart } from '@/utils/websocket'
 import ViewLog from '@/views/demo/components/ViewLog.vue'
 import PreviewCompareImages from '@/views/demo/components/PreviewCompareImages.vue'
+import { getOneAlgorithmConfigApi, listAlgorithmConfigApi } from '@/api/modules/demo/algorithmConfig'
+import ResultDialog from '@/components/ResultDialog/ResultDialog.vue'
+import http from '@/api'
 
 const previewCompareImagesRef = ref()
 const previewCompare = async row => {
@@ -118,6 +131,15 @@ onMounted(() => {
   }
 })
 
+const ResultDialogRef = ref<InstanceType<typeof ResultDialog> | null>(null)
+const showTimeResult = async function (row) {
+  // let path = row.resultPath.split('ObjectDetection_Web')
+  // path = path[path.length - 1]
+  let p = row.outputPath.split('upload')
+  let result = await http.get('/profile/upload' + p[p.length - 1] + '/result.json')
+  ResultDialogRef.value.openDialog(result)
+}
+
 const startVideoStable = async (params: any) => {
   const res = await startVideoStableApi(params.id)
   if (res.code === 200) {
@@ -138,6 +160,16 @@ const stopVideoStable = async (params: any) => {
   proTable.value?.getTableList()
 }
 
+const hangupVideoStable = async (params: any) => {
+  const res = await hangupVideoStableApi(params.id)
+  if (res.code === 200) {
+    ElMessage.success('任务暂停成功')
+  } else {
+    ElMessage.error('任务暂停失败!')
+  }
+  proTable.value?.getTableList()
+}
+
 // ProTable 实例
 const proTable = ref<ProTableInstance>()
 
@@ -181,7 +213,7 @@ const openDialog = async (type: number, title: string, row?: any) => {
     res = await getVideoStableApi(row?.id || null)
   }
   // 重置表单
-  setItemsOptions()
+  await setItemsOptions()
   const params = {
     title,
     width: 580,
@@ -338,7 +370,7 @@ const columns = reactive<ColumnProps<any>[]>([
 ])
 // 表单配置项
 let itemsOptions: ProForm.ItemsOptions[] = []
-const setItemsOptions = () => {
+const setItemsOptions = async () => {
   itemsOptions = [
     {
       label: '任务名称',
@@ -359,76 +391,76 @@ const setItemsOptions = () => {
         placeholder: '请上传图片集压缩包'
       }
     },
-    {
-      label: '网格大小',
-      prop: 'block_size',
-      rules: [],
-      compOptions: {
-        type: 'input',
-        clearable: true,
-        placeholder: '默认50'
-      }
-    },
-    {
-      label: '扩散半径',
-      prop: 'radius',
-      rules: [],
-      compOptions: {
-        type: 'input',
-        clearable: true,
-        placeholder: '默认500'
-      }
-    },
-    {
-      label: '缓冲区大小',
-      prop: 'buffer_size',
-      rules: [],
-      compOptions: {
-        type: 'input',
-        clearable: true,
-        placeholder: '默认200'
-      }
-    },
-    {
-      label: '角点质量',
-      prop: 'cornerquality',
-      rules: [],
-      compOptions: {
-        type: 'input',
-        clearable: true,
-        placeholder: '默认0.2'
-      }
-    },
-    {
-      label: '角点最小距离',
-      prop: 'cornerminDistance',
-      rules: [],
-      compOptions: {
-        type: 'input',
-        clearable: true,
-        placeholder: '默认5'
-      }
-    },
-    {
-      label: '光流层级',
-      prop: 'lklevel',
-      rules: [],
-      compOptions: {
-        type: 'input',
-        clearable: true,
-        placeholder: '默认3'
-      }
-    },
-    {
-      label: '光流窗口大小',
-      prop: 'lkwinSiz',
-      rules: [],
-      compOptions: {
-        type: 'input',
-        clearable: true,
-        placeholder: '默认15'
-      }
-    },
+    // {
+    //   label: '网格大小',
+    //   prop: 'block_size',
+    //   rules: [],
+    //   compOptions: {
+    //     type: 'input',
+    //     clearable: true,
+    //     placeholder: '默认50'
+    //   }
+    // },
+    // {
+    //   label: '扩散半径',
+    //   prop: 'radius',
+    //   rules: [],
+    //   compOptions: {
+    //     type: 'input',
+    //     clearable: true,
+    //     placeholder: '默认500'
+    //   }
+    // },
+    // {
+    //   label: '缓冲区大小',
+    //   prop: 'buffer_size',
+    //   rules: [],
+    //   compOptions: {
+    //     type: 'input',
+    //     clearable: true,
+    //     placeholder: '默认200'
+    //   }
+    // },
+    // {
+    //   label: '角点质量',
+    //   prop: 'cornerquality',
+    //   rules: [],
+    //   compOptions: {
+    //     type: 'input',
+    //     clearable: true,
+    //     placeholder: '默认0.2'
+    //   }
+    // },
+    // {
+    //   label: '角点最小距离',
+    //   prop: 'cornerminDistance',
+    //   rules: [],
+    //   compOptions: {
+    //     type: 'input',
+    //     clearable: true,
+    //     placeholder: '默认5'
+    //   }
+    // },
+    // {
+    //   label: '光流层级',
+    //   prop: 'lklevel',
+    //   rules: [],
+    //   compOptions: {
+    //     type: 'input',
+    //     clearable: true,
+    //     placeholder: '默认3'
+    //   }
+    // },
+    // {
+    //   label: '光流窗口大小',
+    //   prop: 'lkwinSiz',
+    //   rules: [],
+    //   compOptions: {
+    //     type: 'input',
+    //     clearable: true,
+    //     placeholder: '默认15'
+    //   }
+    // },
     {
       label: '备注',
       prop: 'remarks',
@@ -444,6 +476,22 @@ const setItemsOptions = () => {
       }
     }
   ]
+
+  const res = await getOneAlgorithmConfigApi({ algorithmName: '电子稳相' })
+  const config = JSON.parse(res.data.parameters)
+  config.forEach(item => {
+    itemsOptions.push({
+      label: item.name,
+      prop: item.agName,
+      rules: [],
+      compOptions: {
+        type: 'input',
+        clearable: true,
+        placeholder: item.defaultValue
+      },
+      tooltip: item.prompt
+    })
+  })
 }
 </script>
 

+ 15 - 8
src/views/login/index.scss

@@ -1,8 +1,9 @@
 .login-container {
   height: 100%;
   min-height: 550px;
-  background-color: #eeeeee;
-  background-image: url('@/assets/images/login_bg.svg');
+
+  // background-color: #eeeeee;
+  background-image: url('@/assets/images/bg0.png');
   background-size: 100% 100%;
   background-size: cover;
   .login-box {
@@ -14,7 +15,9 @@
     width: 96.5%;
     height: 94%;
     padding: 0 50px;
-    background-color: rgb(255 255 255 / 80%);
+    background-color: transparent;
+
+    // background-color: rgb(255 255 255 / 80%);
     border-radius: 10px;
     .dark {
       position: absolute;
@@ -30,11 +33,14 @@
       }
     }
     .login-form {
-      width: 420px;
+      width: 400px;
       padding: 50px 40px 45px;
-      background-color: var(--el-bg-color);
+      background-color: transparent;
+
+      // background-color: var(--el-bg-color);
       border-radius: 10px;
-      box-shadow: rgb(0 0 0 / 10%) 0 2px 10px 2px;
+
+      // box-shadow: rgb(0 0 0 / 10%) 0 2px 10px 2px;
       .login-logo {
         display: flex;
         align-items: center;
@@ -42,13 +48,14 @@
         margin-bottom: 20px;
         .login-icon {
           width: 60px;
-          height: 52px;
+          height: 44px;
         }
         .logo-text {
           padding: 0 0 0 25px;
           margin: 0;
-          font-size: 42px;
+          font-size: 30px;
           font-weight: bold;
+          color: var(--el-text-color-primary) !important;
           color: #34495e;
           white-space: nowrap;
         }

+ 5 - 8
src/views/login/index.vue

@@ -1,24 +1,21 @@
 <template>
-  <div class="login-container flx-center">
+  <div class="login-container flx-center1">
     <div class="login-box">
-      <!-- <SwitchDark class="dark" /> -->
-      <div class="login-left">
-        <img class="login-left-img" src="@/assets/images/login_left.png" alt="login" />
-      </div>
       <div class="login-form">
         <div class="login-logo">
-          <img class="login-icon" src="@/assets/images/logo.svg" alt="" />
-          <h2 class="logo-text">算法任务系统</h2>
+          <img class="login-icon" src="@/assets/images/logo.png" alt="" />
+          <h2 class="logo-text">目标捕获技术设计支撑环境系统</h2>
         </div>
         <LoginForm />
       </div>
     </div>
+    <Footer style="height: 60px" />
   </div>
 </template>
 
 <script setup lang="ts" name="login">
 import LoginForm from './components/LoginForm.vue'
-// import SwitchDark from '@/components/SwitchDark/index.vue'
+import Footer from '@/layouts/components/Footer/index.vue'
 </script>
 
 <style scoped lang="scss">

+ 258 - 0
src/views/system/config/index.vue

@@ -0,0 +1,258 @@
+<template>
+  <div class="table-box">
+    <ProTable ref="proTable" :columns="columns" row-key="id" :request-api="listAlgorithmConfigApi">
+      <!-- 表格 header 按钮 -->
+      <template #tableHeader="scope">
+        <el-button type="primary" v-auth="['demo:algorithmConfig:add']" icon="CirclePlus" @click="openDialog(1, '通用算法配置新增')">
+          新增
+        </el-button>
+        <el-button type="primary" v-auth="['demo:algorithmConfig:import']" icon="Upload" plain @click="batchAdd"> 导入 </el-button>
+        <el-button type="primary" v-auth="['demo:algorithmConfig:export']" icon="Download" plain @click="downloadFile"> 导出 </el-button>
+        <el-button
+          type="danger"
+          v-auth="['demo:algorithmConfig: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:algorithmConfig:query']" @click="openDialog(3, '通用算法配置查看', scope.row)">
+          查看
+        </el-button>
+        <el-button type="primary" link icon="EditPen" v-auth="['demo:algorithmConfig:edit']" @click="openDialog(2, '通用算法配置编辑', scope.row)">
+          编辑
+        </el-button>
+        <el-button type="primary" link icon="Delete" v-auth="['demo:algorithmConfig:remove']" @click="deleteAlgorithmConfig(scope.row)">
+          删除
+        </el-button>
+      </template>
+    </ProTable>
+    <FormDialog ref="formDialogRef" />
+    <ImportExcel ref="dialogRef" />
+  </div>
+</template>
+
+<script setup lang="tsx" name="AlgorithmConfig">
+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 {
+  listAlgorithmConfigApi,
+  delAlgorithmConfigApi,
+  addAlgorithmConfigApi,
+  updateAlgorithmConfigApi,
+  importTemplateApi,
+  importAlgorithmConfigDataApi,
+  exportAlgorithmConfigApi,
+  getAlgorithmConfigApi
+} from '@/api/modules/demo/algorithmConfig'
+
+// ProTable 实例
+const proTable = ref<ProTableInstance>()
+
+// 删除通用算法配置信息
+const deleteAlgorithmConfig = async (params: any) => {
+  await useHandleData(delAlgorithmConfigApi, params.id, '删除【' + params.id + '】通用算法配置')
+  proTable.value?.getTableList()
+}
+
+// 批量删除通用算法配置信息
+const batchDelete = async (ids: string[]) => {
+  await useHandleData(delAlgorithmConfigApi, ids, '删除所选通用算法配置信息')
+  proTable.value?.clearSelection()
+  proTable.value?.getTableList()
+}
+
+// 导出通用算法配置列表
+const downloadFile = async () => {
+  ElMessageBox.confirm('确认导出通用算法配置数据?', '温馨提示', { type: 'warning' }).then(() =>
+    useDownload(exportAlgorithmConfigApi, '通用算法配置列表', proTable.value?.searchParam)
+  )
+}
+
+// 批量添加通用算法配置
+const dialogRef = ref<InstanceType<typeof ImportExcel> | null>(null)
+const batchAdd = () => {
+  const params = {
+    title: '通用算法配置',
+    tempApi: importTemplateApi,
+    importApi: importAlgorithmConfigDataApi,
+    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 getAlgorithmConfigApi(row?.id || null)
+  }
+  // 重置表单
+  setItemsOptions()
+  const params = {
+    title,
+    width: 580,
+    isEdit: type !== 3,
+    itemsOptions: itemsOptions,
+    model: type == 1 ? {} : res.data,
+    api: type == 1 ? addAlgorithmConfigApi : updateAlgorithmConfigApi,
+    getTableList: proTable.value?.getTableList
+  }
+  formDialogRef.value?.openDialog(params)
+}
+
+// 表格配置项
+const columns = reactive<ColumnProps<any>[]>([
+  { type: 'selection', fixed: 'left', width: 70 },
+  { prop: 'id', label: 'ID' },
+  {
+    prop: 'tool',
+    label: '工具',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'module',
+    label: '模块',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'algorithmName',
+    label: '算法名称',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'startApi',
+    label: '开始接口',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'pauseApi',
+    label: '暂停接口',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'terminateApi',
+    label: '终止接口',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'parameters',
+    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: 'tool',
+      rules: [{ required: true, message: '工具名称不能为空', trigger: 'blur' }],
+      compOptions: {
+        placeholder: '请输入工具名称'
+      }
+    },
+    {
+      label: '模块',
+      prop: 'module',
+      rules: [{ required: true, message: '模块不能为空', trigger: 'blur' }],
+      compOptions: {
+        placeholder: '请输入模块'
+      }
+    },
+    {
+      label: '算法名称',
+      prop: 'algorithmName',
+      rules: [{ required: true, message: '算法名称不能为空', trigger: 'blur' }],
+      compOptions: {
+        placeholder: '请输入算法名称'
+      }
+    },
+    {
+      label: '开始接口',
+      prop: 'startApi',
+      rules: [{ required: true, message: '开始接口不能为空', trigger: 'blur' }],
+      compOptions: {
+        placeholder: '请输入开始接口'
+      }
+    },
+    {
+      label: '暂停接口',
+      prop: 'pauseApi',
+      rules: [{ required: true, message: '暂停接口不能为空', trigger: 'blur' }],
+      compOptions: {
+        placeholder: '请输入暂停接口'
+      }
+    },
+    {
+      label: '终止接口',
+      prop: 'terminateApi',
+      rules: [{ required: true, message: '终止接口不能为空', trigger: 'blur' }],
+      compOptions: {
+        placeholder: '请输入终止接口'
+      }
+    },
+    {
+      label: '参数',
+      prop: 'parameters',
+      rules: [{ required: true, message: '参数不能为空', trigger: 'blur' }],
+      compOptions: {
+        type: 'textarea',
+        rows: 2,
+        placeholder: '请输入参数'
+      }
+    },
+    {
+      label: '备注',
+      prop: 'remarks',
+      rules: [{ required: false, message: '备注不能为空', trigger: 'blur' }],
+      compOptions: {
+        placeholder: '请输入备注'
+      }
+    }
+  ]
+}
+</script>

+ 13 - 13
src/views/taais/homePage/index.scss

@@ -19,21 +19,21 @@
 
 //   // color: black;
 // }
-:deep(.el-table) {
-  // --el-table-border-color: transparent;
-  --el-table-border-color: #bdbdbe7b;
+// :deep(.el-table) {
+//   // --el-table-border-color: transparent;
+//   --el-table-border-color: #bdbdbe7b;
 
-  // --el-table-border: none;
-  --el-table-text-color: #bdbdbe;
-  --el-table-header-text-color: #bdbdbe;
-  --el-table-row-hover-bg-color: transparent;
-  --el-table-current-row-bg-color: transparent;
-  --el-table-header-bg-color: transparent;
-  --el-table-bg-color: transparent;
-  --el-table-tr-bg-color: transparent;
+//   // --el-table-border: none;
+//   --el-table-text-color: #bdbdbe;
+//   --el-table-header-text-color: #bdbdbe;
+//   --el-table-row-hover-bg-color: transparent;
+//   --el-table-current-row-bg-color: transparent;
+//   --el-table-header-bg-color: transparent;
+//   --el-table-bg-color: transparent;
+//   --el-table-tr-bg-color: transparent;
 
-  // --el-table-expanded-cell-bg-color: transparent;
-}
+//   // --el-table-expanded-cell-bg-color: transparent;
+// }
 .bigBox,
 .createTask-bigBox {
   width: 100%;

+ 2 - 2
src/views/taais/homePage/index.vue

@@ -121,7 +121,7 @@ const createTaskNew = () => {
 }
 // 表格配置项
 const columns = reactive<ColumnProps<User.ResUserList>[]>([
-  { type: 'selection', fixed: 'left', width: 70 },
+  { type: 'selection', width: 70 },
   { prop: 'name', label: '任务名称' },
   // {
   //   prop: 'status',
@@ -144,7 +144,7 @@ const columns = reactive<ColumnProps<User.ResUserList>[]>([
     //   el: 'input'
     // }
   },
-  { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
+  { prop: 'operation', label: '操作', width: 230 }
 ])
 </script>
 <style scoped lang="scss">

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

@@ -110,7 +110,9 @@
           @update-data="updateBatchData"
           @update-model="updateModelData"
           @update-params="updateParamsList"
-          :show-select-batch-button="false"
+          :show-select-batch-button="true"
+          :use-data="true"
+          :data-list="selectedBatchDataList"
         />
       </el-container>
       <el-container style="height: 10px"></el-container>
@@ -125,6 +127,9 @@
       <span style="font-size: 16px; font-weight: bold; color: darkorange"> 训练超参 </span>
       <el-container v-for="(item, index) in superParameterFormData.trainParams" :key="index">
         <span class="span_class"> {{ item.name }}</span>
+        <el-tooltip effect="dark" :content="item?.prompt" placement="top">
+          <i :class="'iconfont icon-yiwen'"></i>
+        </el-tooltip>
         <el-input style="width: 300px" type="text" :placeholder="'请输入' + item.name" v-model="item.defaultValue"> </el-input>
       </el-container>
       <el-container style="height: 10px"></el-container>
@@ -132,6 +137,9 @@
       <span style="font-size: 16px; font-weight: bold; color: darkorange"> 验证超参 </span>
       <el-container v-for="(item, index) in superParameterFormData.verifyParams" :key="index">
         <span class="span_class"> {{ item.name }}</span>
+        <el-tooltip effect="dark" :content="item?.prompt" placement="top">
+          <i :class="'iconfont icon-yiwen'"></i>
+        </el-tooltip>
         <el-input style="width: 300px" type="text" :placeholder="'请输入' + item.name" v-model="item.defaultValue"> </el-input>
       </el-container>
       <el-container style="height: 10px"></el-container>
@@ -139,6 +147,9 @@
       <span style="font-size: 16px; font-weight: bold; color: darkorange"> 测试超参 </span>
       <el-container v-for="(item, index) in superParameterFormData.testParams" :key="index">
         <span class="span_class"> {{ item.name }}</span>
+        <el-tooltip effect="dark" :content="item?.prompt" placement="top">
+          <i :class="'iconfont icon-yiwen'"></i>
+        </el-tooltip>
         <el-input style="width: 300px" type="text" :placeholder="'请输入' + item.name" v-model="item.defaultValue"> </el-input>
       </el-container>
       <el-container style="height: 10px"></el-container>
@@ -187,7 +198,7 @@ import FormDialog from '@/components/FormDialog/index.vue'
 import { useRouter } from 'vue-router'
 import { listTaskConfigurationApi } from '@/api/modules/task/taskConfiguration'
 import { amplifyApi, batchListDataApi } from '@/api/modules/demo/data'
-import { listDataApi } from '@/api/modules/system/dictData'
+import { getDictsApi, listDataApi } from '@/api/modules/system/dictData'
 import { ElMessage } from 'element-plus'
 import AmplifyForm from '@/views/demo/data/AmplifyForm.vue'
 
@@ -202,11 +213,13 @@ const updateBatchData = data => {
 
 const updateModelData = data => {
   model.value = data
+  console.log('model', model.value)
 }
 
 // 监听 parameList 更新
 const updateParamsList = data => {
   parameList.value = data
+  console.log('params', parameList.value)
 }
 
 // 提交逻辑
@@ -219,8 +232,9 @@ const getTrainAugmentationParams = () => {
   })
 
   return {
-    batchNum,
+    batchNum: batchNum,
     taskName: model.value.taskName,
+    augmentationType: model.value.augmentationType,
     otherParams: parameList.value
   }
 }
@@ -276,7 +290,6 @@ const valid = data => {
 }
 
 const submit = () => {
-  console.log('submit data, formdata is: ', formData)
   const params = {
     taskName: formData.taskName,
     taskType: formData.taskType,
@@ -287,6 +300,7 @@ const submit = () => {
     hasTrainAugmentation: formData.expandData,
     trainAugmentationParams: getTrainAugmentationParams()
   }
+  console.log('submit data', params)
   let result = valid(params)
   // console.log(result)
   if (result.code !== 200) {
@@ -537,7 +551,8 @@ const onAlgorithmModelSelect = index => {
 const formDialogRef = ref<InstanceType<typeof FormDialog> | null>(null)
 
 let UPDATE_INDEX = ref({ id: null, idx: null })
-const showAddModelDialog = (item, index) => {
+const fileDescription = ref('')
+const showAddModelDialog = async (item, index) => {
   let _id = null
   try {
     _id = item.id
@@ -553,6 +568,14 @@ const showAddModelDialog = (item, index) => {
     id: _id,
     idx: index
   }
+  let _res = await getDictsApi('zip_file_format_description')
+
+  _res.data.forEach(item => {
+    // 检查item对象是否包含dict和des属性
+    if (item.dictLabel === '多目标检测导入模型') {
+      fileDescription.value = item.remark
+    }
+  })
   const params = {
     title: '算法模型配置',
     width: 580,
@@ -568,6 +591,7 @@ const showAddModelDialog = (item, index) => {
       },
       {
         label: '模型',
+        tooltip: fileDescription,
         prop: 'modelAddress',
         rules: [], //{ required: true, message: '模型不能为空', trigger: 'blur' }
         compOptions: {

+ 13 - 9
src/views/task/amplify/index.vue

@@ -494,11 +494,13 @@ onMounted(() => {
       })
     }
   })
+  if (subTaskId) {
+    getSubtaskApi(subTaskId).then(res => {
+      taskType.value = res.data.type
+      taskStatus.value = res.data.status
+    })
+  }
 
-  getSubtaskApi(subTaskId).then(res => {
-    taskType.value = res.data.type
-    taskStatus.value = res.data.status
-  })
   refreshList()
   timer.value = setInterval(() => {
     refreshList()
@@ -588,7 +590,9 @@ const viewLog = row => {
   }
   const paths = row.outputImagePath.split('\n')
   for (let path of paths) {
-    const url = `/api/profile/task/log/bizType/` + row.id + '/log.log'
+    let p = row.remarks === 'PERSISTENCE' ? row.outputImagePath.split('amplify') : row.remarks.split('amplify')
+    console.log(p)
+    const url = '/api/profile/amplify' + p[p.length - 1] + (row.remarks === 'PERSISTENCE' ? '/log.log' : '')
     logShow(url)
     dialogVisible.value = true
     timer2.value = setInterval(() => {
@@ -715,7 +719,7 @@ const columns = reactive<ColumnProps<any>[]>([
   },
   {
     prop: 'inputImagePath',
-    label: '预处理数据路径'
+    label: '剩余任务数'
   },
   {
     prop: 'outputImagePath',
@@ -736,7 +740,7 @@ const columns = reactive<ColumnProps<any>[]>([
   },
   {
     prop: 'costSecond',
-    label: '耗时(ms)'
+    label: '耗时'
   },
   {
     prop: 'log',
@@ -806,10 +810,10 @@ const setItemsOptions = () => {
       }
     },
     {
-      label: '预处理数据路径',
+      label: '剩余任务数',
       prop: 'inputImagePath',
       compOptions: {
-        placeholder: '请输入预处理数据路径'
+        placeholder: '剩余任务数'
       }
     },
     {

+ 60 - 5
src/views/task/bizProcess/index.vue

@@ -47,11 +47,29 @@
         <!--          查看详情-->
         <!--        </el-button>-->
 
-        <el-button v-if="scope.row.name.indexOf('训练') === -1" type="primary" link icon="Refresh" @click="reRunTask(scope.row)">
-          执行任务
+        <el-button
+          v-if="scope.row.name.indexOf('训练') === -1 && (scope.row.status === '0' || scope.row.status === '3')"
+          type="primary"
+          link
+          icon="VideoPlay"
+          @click="reRunTask(scope.row)"
+        >
+          开始任务
         </el-button>
-        <el-button v-else type="primary" link icon="Refresh" @click="startTask(scope.row)"> 开始任务 </el-button>
-
+        <el-button
+          v-if="scope.row.name.indexOf('训练') !== -1 && (scope.row.status === '0' || scope.row.status === '3')"
+          type="primary"
+          link
+          icon="VideoPlay"
+          @click="startTask(scope.row)"
+        >
+          开始任务
+        </el-button>
+        <el-button v-if="scope.row.status === '0'" type="primary" link icon="Refresh" @click="taskExecute('continue', scope.row)">
+          继续任务
+        </el-button>
+        <el-button v-if="scope.row.status === '1'" type="primary" link icon="Refresh" @click="taskExecute('pause', scope.row)"> 暂停任务 </el-button>
+        <el-button v-if="scope.row.status === '1'" type="primary" link icon="Refresh" @click="taskExecute('stop', scope.row)"> 停止任务 </el-button>
         <el-button v-if="!scope.row.name.includes('测试')" type="primary" link icon="finished" @click="showResult(scope.row)"> 结果图 </el-button>
 
         <el-button v-if="!scope.row.name.includes('训练')" type="primary" link icon="search" @click="showTimeResult(scope.row)"> 查看指标 </el-button>
@@ -60,7 +78,9 @@
           查看日志
         </el-button>
 
-        <el-button type="primary" link icon="Refresh" @click="exportData(scope.row)"> 导出结果 </el-button>
+        <el-button type="primary" link icon="FolderOpened" @click="openDir(scope.row, true)"> 预处理文件夹 </el-button>
+        <el-button type="primary" link icon="FolderOpened" @click="openDir(scope.row, false)"> 结果文件夹 </el-button>
+        <el-button type="primary" link icon="SoldOut" @click="exportData(scope.row)"> 导出结果 </el-button>
       </template>
     </ProTable>
     <FormDialog ref="formDialogRef" />
@@ -312,6 +332,23 @@ const startTask = row => {
     }
   })
 }
+
+const taskExecute = (type, row) => {
+  http
+    .post<any>(
+      '/identification/identificationSubtaskDetails/' + (type === 'continue' ? 'continueTask' : type === 'pause' ? 'pauseTask' : 'stopTask'),
+      { bizId: row.id },
+      { loading: true }
+    )
+    .then(res => {
+      if (res.code !== 200) {
+        ElMessage.error(res.msg)
+      } else {
+        ElMessage.success('操作成功')
+      }
+    })
+}
+
 const typeDefs = ref(reactive([]))
 
 const exportData = row => {
@@ -319,10 +356,26 @@ const exportData = row => {
     console.log(res)
     if (res.code === 200) {
       window.open(res.msg, '_blank')
+      // http.get<any>('/identification/identificationSubtaskDetails/openDir', { directory: row.resultPath + "/weights" }, { loading: true }).then(res => {
+      //   console.log(res)
+      // })
     }
   })
 }
 
+const openDir = (row, isPre) => {
+  console.log(row)
+  http
+    .get<any>(
+      '/identification/identificationSubtaskDetails/openDir',
+      { directory: isPre ? row.preprocessPath : row.resultPath, type: '2' },
+      { loading: true }
+    )
+    .then(res => {
+      console.log(res)
+    })
+}
+
 let imgDataList = ref(reactive([]))
 let titleMsg = ref('')
 let valDialogVisible = ref(false)
@@ -412,10 +465,12 @@ const loadVerifyResult = async (name, filepath) => {
   }
 }
 
+import { xywh2fourNodes } from '../../demo/data/reformat'
 const setDetail = obj => {
   http.get<any>(obj.labelUrl).then(res => {
     obj.jsonData = []
     // console.log('result', res)
+    res = xywh2fourNodes(res)
     let arr = res.replace('\r', '').split('\n')
     // console.log(arr)
     for (let i = 0; i < arr.length; i++) {

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 406 - 561
yarn.lock


Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels