浏览代码

Merge branch 'master' of www/taais-web into develop

allen 10 月之前
父节点
当前提交
455c6389f8
共有 52 个文件被更改,包括 5088 次插入1459 次删除
  1. 1 1
      .env
  2. 2 1
      .env.development
  3. 1 1
      index.html
  4. 222 302
      package-lock.json
  5. 4 2
      package.json
  6. 0 0
      public/logo.svg
  7. 1 1
      src/api/interface/index.ts
  8. 1 1
      src/api/interface/login.ts
  9. 181 0
      src/api/interface/task/bizProcess.ts
  10. 171 0
      src/api/interface/task/dataProcess.ts
  11. 151 0
      src/api/interface/task/dataSet.ts
  12. 33 9
      src/api/interface/task/subtask.ts
  13. 4 5
      src/api/modules/demo/data.ts
  14. 36 0
      src/api/modules/taais/task.ts
  15. 94 0
      src/api/modules/task/bizProcess.ts
  16. 70 0
      src/api/modules/task/dataProcess.ts
  17. 70 0
      src/api/modules/task/dataSet.ts
  18. 1 1
      src/api/modules/task/subtask.ts
  19. 8 0
      src/api/modules/task/task.ts
  20. 0 1
      src/assets/images/logo.svg
  21. 6 1
      src/components/FormDialog/index.vue
  22. 1 1
      src/components/ImportPicDataset/index.vue
  23. 10 3
      src/components/ProForm/index.vue
  24. 0 1
      src/components/ProTable/index.vue
  25. 0 1
      src/components/Upload/File.vue
  26. 0 1
      src/components/Upload/FileS3.vue
  27. 2 2
      src/components/Upload/Img.vue
  28. 8 8
      src/layouts/components/Header/ToolBarRight.vue
  29. 19 4
      src/routers/modules/routerData.json
  30. 1 1
      src/stores/modules/auth.ts
  31. 2 2
      src/stores/modules/global.ts
  32. 3 0
      src/typings/ProForm.d.ts
  33. 18 0
      src/typings/canvas.d.ts
  34. 106 0
      src/utils/fabric.ts
  35. 7 11
      src/views/ag/config/index.vue
  36. 27 3
      src/views/ag/model/index.vue
  37. 90 0
      src/views/demo/components/img-detect.vue
  38. 645 0
      src/views/demo/components/img-maker.vue
  39. 65 6
      src/views/demo/data/index.vue
  40. 3 3
      src/views/login/index.vue
  41. 0 1
      src/views/system/user/index.vue
  42. 1107 351
      src/views/taais/homePage/createTask.vue
  43. 44 25
      src/views/taais/homePage/index.scss
  44. 26 38
      src/views/taais/homePage/index.vue
  45. 1 1
      src/views/taais/homePage/inferResult.vue
  46. 2 2
      src/views/taais/homePage/logPage.vue
  47. 576 0
      src/views/task/bizProcess/index.vue
  48. 300 0
      src/views/task/dataProcess/index.vue
  49. 276 0
      src/views/task/dataSet/index.vue
  50. 100 47
      src/views/task/subtask/index.vue
  51. 35 35
      src/views/task/task/index.vue
  52. 557 586
      yarn.lock

+ 1 - 1
.env

@@ -1,5 +1,5 @@
 # title
-VITE_GLOB_APP_TITLE = 目标精确捕获系统
+VITE_GLOB_APP_TITLE = 算法任务系统
 
 # 本地运行端口号
 VITE_PORT = 8848

+ 2 - 1
.env.development

@@ -25,7 +25,8 @@ VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3C
 VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
 
 # 开发环境跨域代理,支持配置多个
-VITE_PROXY = [["/api","http://localhost:9090"]]
+# VITE_PROXY = [["/api","http://localhost:9090"]]
+VITE_PROXY = [["/api","http://192.168.101.34/prod-api"]]
 # VITE_PROXY = [["/api","https://mock.mengxuegu.com/mock/629d727e6163854a32e8307e"]]
 # VITE_PROXY = [["/api","https://www.fastmock.site/mock/f81e8333c1a9276214bcdbc170d9e0a0"]]
 # VITE_PROXY = [["/api-easymock","https://mock.mengxuegu.com"],["/api-fastmock","https://www.fastmock.site"]]

+ 1 - 1
index.html

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

文件差异内容过多而无法显示
+ 222 - 302
package-lock.json


+ 4 - 2
package.json

@@ -39,7 +39,8 @@
     "driver.js": "^1.3.1",
     "echarts": "^5.4.3",
     "echarts-liquidfill": "^3.1.0",
-    "element-plus": "^2.4.3",
+    "element-plus": "2.6.0",
+    "fabric": "^5.3.0",
     "file-saver": "^2.0.5",
     "image-conversion": "^2.1.1",
     "js-cookie": "^3.0.5",
@@ -54,9 +55,10 @@
     "qs": "^6.11.2",
     "screenfull": "^6.0.2",
     "sortablejs": "^1.15.1",
-    "vue": "^3.3.11",
+    "vue": "3.3.13",
     "vue-cropper": "^1.1.2",
     "vue-i18n": "^9.6.4",
+    "vue-konva": "^3.0.2",
     "vue-router": "^4.2.5",
     "vue-types": "^5.1.1",
     "vuedraggable": "^4.1.0"

文件差异内容过多而无法显示
+ 0 - 0
public/logo.svg


+ 1 - 1
src/api/interface/index.ts

@@ -51,7 +51,7 @@ export namespace Login {
     uuid: string
     clientId: string
     grantType: string
-    tenantId: string
+    tenantId: string | number
   }
   export interface ResLogin {
     access_token: string

+ 1 - 1
src/api/interface/login.ts

@@ -15,7 +15,7 @@ export type RegisterForm = {
  * 登录请求
  */
 export interface LoginData {
-  tenantId?: number
+  tenantId?: number | string
   username?: string
   password?: string
   rememberMe?: boolean

+ 181 - 0
src/api/interface/task/bizProcess.ts

@@ -0,0 +1,181 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface BizProcessVO extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id: string | number
+
+  /**
+   * 子任务id
+   */
+  subTaskId: string | number
+
+  /**
+   * 任务名称
+   */
+  name: string
+
+  /**
+   * 任务类型
+   */
+  type: string
+
+  /**
+   * 任务状态
+   */
+  status: string
+
+  /**
+   * 算法
+   */
+  algorithmId: string | number
+
+  /**
+   * 模型
+   */
+  modelId: string | number
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters: string
+
+  /**
+   * 预处理数据路径
+   */
+  preprocessPath: string
+
+  /**
+   * 结果数据路径
+   */
+  resultPath: string
+
+  /**
+   * 序号
+   */
+  index: number
+
+  /**
+   * 开始时间
+   */
+  startTime: string
+
+  /**
+   * 结束时间
+   */
+  endTime: string
+
+  /**
+   * 耗时
+   */
+  costSecond: number
+
+  /**
+   * 日志
+   */
+  log: string
+}
+
+export interface BizProcessForm {
+  /**
+   * 主键ID
+   */
+  id?: string | number
+
+  /**
+   * 子任务id
+   */
+  subTaskId?: string | number
+
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务类型
+   */
+  type?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 算法
+   */
+  algorithmId?: string | number
+
+  /**
+   * 模型
+   */
+  modelId?: string | number
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters?: string
+
+  /**
+   * 预处理数据路径
+   */
+  preprocessPath?: string
+
+  /**
+   * 结果数据路径
+   */
+  resultPath?: string
+
+  /**
+   * 序号
+   */
+  index?: number
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
+  /**
+   * 耗时
+   */
+  costSecond?: number
+
+  /**
+   * 日志
+   */
+  log?: string
+}
+
+export interface BizProcessQuery extends PageQuery {
+  /**
+   * 子任务id
+   */
+  subTaskId?: string | number
+
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务类型
+   */
+  type?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+}

+ 171 - 0
src/api/interface/task/dataProcess.ts

@@ -0,0 +1,171 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface DataProcessVO extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id: string | number
+
+  /**
+   * 子任务id
+   */
+  subTaskId: string | number
+
+  /**
+   * 任务名称
+   */
+  name: string
+
+  /**
+   * 任务类型
+   */
+  type: string
+
+  /**
+   * 任务状态
+   */
+  status: string
+
+  /**
+   * 算法
+   */
+  algorithmId: string | number
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters: string
+
+  /**
+   * 预处理数据路径
+   */
+  preprocessPath: string
+
+  /**
+   * 结果数据路径
+   */
+  resultPath: string
+
+  /**
+   * 开始时间
+   */
+  startTime: string
+
+  /**
+   * 序号
+   */
+  index: number
+
+  /**
+   * 结束时间
+   */
+  endTime: string
+
+  /**
+   * 耗时
+   */
+  costSecond: number
+
+  /**
+   * 日志
+   */
+  log: string
+}
+
+export interface DataProcessForm {
+  /**
+   * 主键ID
+   */
+  id?: string | number
+
+  /**
+   * 子任务id
+   */
+  subTaskId?: string | number
+
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务类型
+   */
+  type?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 算法
+   */
+  algorithmId?: string | number
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters?: string
+
+  /**
+   * 预处理数据路径
+   */
+  preprocessPath?: string
+
+  /**
+   * 结果数据路径
+   */
+  resultPath?: string
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 序号
+   */
+  index?: number
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
+  /**
+   * 耗时
+   */
+  costSecond?: number
+
+  /**
+   * 日志
+   */
+  log?: string
+}
+
+export interface DataProcessQuery extends PageQuery {
+  /**
+   * 子任务id
+   */
+  subTaskId?: string | number
+
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务类型
+   */
+  type?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+}

+ 151 - 0
src/api/interface/task/dataSet.ts

@@ -0,0 +1,151 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface DataSetVO extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id: string | number
+
+  /**
+   * 子任务id
+   */
+  subTaskId: string | number
+
+  /**
+   * 任务名称
+   */
+  name: string
+
+  /**
+   * 任务类型
+   */
+  type: string
+
+  /**
+   * 任务状态
+   */
+  status: string
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters: string
+
+  /**
+   * 结果数据路径
+   */
+  resultPath: string
+
+  /**
+   * 开始时间
+   */
+  startTime: string
+
+  /**
+   * 序号
+   */
+  index: number
+
+  /**
+   * 结束时间
+   */
+  endTime: string
+
+  /**
+   * 耗时
+   */
+  costSecond: number
+
+  /**
+   * 日志
+   */
+  log: string
+}
+
+export interface DataSetForm {
+  /**
+   * 主键ID
+   */
+  id?: string | number
+
+  /**
+   * 子任务id
+   */
+  subTaskId?: string | number
+
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务类型
+   */
+  type?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters?: string
+
+  /**
+   * 结果数据路径
+   */
+  resultPath?: string
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 序号
+   */
+  index?: number
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
+  /**
+   * 耗时
+   */
+  costSecond?: number
+
+  /**
+   * 日志
+   */
+  log?: string
+}
+
+export interface DataSetQuery extends PageQuery {
+  /**
+   * 子任务id
+   */
+  subTaskId?: string | number
+
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务类型
+   */
+  type?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+}

+ 33 - 9
src/api/interface/task/subtask.ts

@@ -1,10 +1,5 @@
 import { PageQuery, BaseEntity } from '@/api/interface/index'
 export interface SubtaskVO extends BaseEntity {
-  /**
-   * 主键ID
-   */
-  id: string | number
-
   /**
    * 任务名称
    */
@@ -15,6 +10,11 @@ export interface SubtaskVO extends BaseEntity {
    */
   status: string
 
+  /**
+   * 任务类型
+   */
+  type: string
+
   /**
    * 调用算法时所用的参数
    */
@@ -38,9 +38,9 @@ export interface SubtaskVO extends BaseEntity {
 
 export interface SubtaskForm {
   /**
-   * 主键ID
+   * 任务ID
    */
-  id?: string | number
+  taskId?: string | number
 
   /**
    * 任务名称
@@ -52,6 +52,11 @@ export interface SubtaskForm {
    */
   status?: string
 
+  /**
+   * 任务类型
+   */
+  type?: string
+
   /**
    * 调用算法时所用的参数
    */
@@ -78,12 +83,16 @@ export interface SubtaskForm {
   log?: string
 
   /**
-   * 是否包含详情
+   * 序号
    */
-  hasDetails?: number
+  index?: number
 }
 
 export interface SubtaskQuery extends PageQuery {
+  /**
+   * 任务名称
+   */
+  taskId?: string
   /**
    * 任务名称
    */
@@ -94,6 +103,21 @@ export interface SubtaskQuery extends PageQuery {
    */
   status?: string
 
+  /**
+   * 任务类型
+   */
+  type?: string
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
   /**
    * 日期范围参数
    */

+ 4 - 5
src/api/modules/demo/data.ts

@@ -1,12 +1,11 @@
 import http from '@/api'
-
 /**
  * @name 查询数据管理列表
  * @param query 参数
  * @returns 返回列表
  */
 export const listDataApi = (query: any) => {
-  return http.get<any>('/demo/data/list', query, { loading: true })
+  return http.get<any[]>('/demo/data/list', query, { loading: true })
 }
 
 /**
@@ -14,7 +13,7 @@ export const listDataApi = (query: any) => {
  * @param id id
  * @returns returns
  */
-export const getDataApi = (id: any) => {
+export const getDataApi = (id: string | number) => {
   return http.get<any>(`/demo/data/${id}`)
 }
 
@@ -41,7 +40,7 @@ export const updateDataApi = (data: any) => {
  * @param id id
  * @returns returns
  */
-export const delDataApi = (id: any) => {
+export const delDataApi = (id: string | number | Array<string | number>) => {
   return http.delete<any>(`/demo/data/${id}`)
 }
 
@@ -58,7 +57,7 @@ export const importTemplateApi = () => {
  * @returns returns
  */
 export const importDataDataApi = (data: any) => {
-  return http.post('/common/zip/upload', data)
+  return http.post('/demo/data/zip/upload', data)
 }
 
 /**

+ 36 - 0
src/api/modules/taais/task.ts

@@ -1,3 +1,4 @@
+import http from '@/api'
 import taskDataList from '@/assets/mock/taskData.json'
 import tableData from '@/assets/mock/tableData.json'
 
@@ -21,3 +22,38 @@ export const getTransferImgList1 = () => {
 export const getTransferImgList2 = () => {
   return tableData.transferImgList2
 }
+// /task/task/create
+/**
+ * @name 得到图像数据
+ * @param type type
+ * @returns returns
+ */
+export const getImageApi = (type: any) => {
+  return http.post<any>(`/task/task/getImage`, type)
+}
+/**
+ * @name 创建算法任务
+ * @param data data
+ * @returns returns
+ */
+export const createTaskApi = (data: any) => {
+  return http.post<any>(`/task/task/create`, data)
+}
+/**
+ * @name 算法查询
+ * @param data data
+ * @returns returns
+ */
+export const getAlgorithmApi = (type: any, subsystem: any) => {
+  return http.post<any>(`/task/task/getAlgorithm/${type}/${subsystem}`)
+  // return http.post<any>(`/task/task/getModel`, data)
+}
+/**
+ * @name 模型查询
+ * @param data data
+ * @returns returns
+ */
+export const getModelApi = (data: any) => {
+  return http.post<any>(`/task/task/getModel/${data}`)
+  // return http.post<any>(`/task/task/getModel`, data)
+}

+ 94 - 0
src/api/modules/task/bizProcess.ts

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

+ 70 - 0
src/api/modules/task/dataProcess.ts

@@ -0,0 +1,70 @@
+import http from '@/api'
+import { DataProcessVO, DataProcessForm, DataProcessQuery } from '@/api/interface/task/dataProcess'
+/**
+ * @name 查询算法数据处理列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listDataProcessApi = (query: DataProcessQuery) => {
+  return http.get<DataProcessVO[]>('/task/dataProcess/list', query, { loading: true })
+}
+
+/**
+ * @name 查询算法数据处理详细
+ * @param id id
+ * @returns returns
+ */
+export const getDataProcessApi = (id: string | number) => {
+  return http.get<DataProcessVO>(`/task/dataProcess/${id}`)
+}
+
+/**
+ * @name 新增算法数据处理
+ * @param data data
+ * @returns returns
+ */
+export const addDataProcessApi = (data: DataProcessForm) => {
+  return http.post<any>('/task/dataProcess', data, { loading: false })
+}
+
+/**
+ * @name 修改算法数据处理
+ * @param data data
+ * @returns returns
+ */
+export const updateDataProcessApi = (data: DataProcessForm) => {
+  return http.put<any>('/task/dataProcess', data, { loading: false })
+}
+
+/**
+ * @name 删除算法数据处理
+ * @param id id
+ * @returns returns
+ */
+export const delDataProcessApi = (id: string | number | Array<string | number>) => {
+  return http.delete<any>(`/task/dataProcess/${id}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/task/dataProcess/importTemplate', {})
+}
+
+/**
+ * @name 导入数据
+ * @returns returns
+ */
+export const importDataProcessDataApi = (data: any) => {
+  return http.post('/task/dataProcess/importData', data)
+}
+
+/**
+ * @name 导出数据
+ * @returns returns
+ */
+export const exportDataProcessApi = (data: any) => {
+  return http.downloadPost('/task/dataProcess/export', data)
+}

+ 70 - 0
src/api/modules/task/dataSet.ts

@@ -0,0 +1,70 @@
+import http from '@/api'
+import { DataSetVO, DataSetForm, DataSetQuery } from '@/api/interface/task/dataSet'
+/**
+ * @name 查询算法数据集合列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listDataSetApi = (query: DataSetQuery) => {
+  return http.get<DataSetVO[]>('/task/dataSet/list', query, { loading: true })
+}
+
+/**
+ * @name 查询算法数据集合详细
+ * @param id id
+ * @returns returns
+ */
+export const getDataSetApi = (id: string | number) => {
+  return http.get<DataSetVO>(`/task/dataSet/${id}`)
+}
+
+/**
+ * @name 新增算法数据集合
+ * @param data data
+ * @returns returns
+ */
+export const addDataSetApi = (data: DataSetForm) => {
+  return http.post<any>('/task/dataSet', data, { loading: false })
+}
+
+/**
+ * @name 修改算法数据集合
+ * @param data data
+ * @returns returns
+ */
+export const updateDataSetApi = (data: DataSetForm) => {
+  return http.put<any>('/task/dataSet', data, { loading: false })
+}
+
+/**
+ * @name 删除算法数据集合
+ * @param id id
+ * @returns returns
+ */
+export const delDataSetApi = (id: string | number | Array<string | number>) => {
+  return http.delete<any>(`/task/dataSet/${id}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/task/dataSet/importTemplate', {})
+}
+
+/**
+ * @name 导入数据
+ * @returns returns
+ */
+export const importDataSetDataApi = (data: any) => {
+  return http.post('/task/dataSet/importData', data)
+}
+
+/**
+ * @name 导出数据
+ * @returns returns
+ */
+export const exportDataSetApi = (data: any) => {
+  return http.downloadPost('/task/dataSet/export', data)
+}

+ 1 - 1
src/api/modules/task/subtask.ts

@@ -6,7 +6,7 @@ import { SubtaskVO, SubtaskForm, SubtaskQuery } from '@/api/interface/task/subta
  * @returns 返回列表
  */
 export const listSubtaskApi = (query: SubtaskQuery) => {
-  return http.get<SubtaskVO[]>('/task/subtask/list', query, { loading: true })
+  return http.get<SubtaskVO[]>('/task/subtask/list', query, { loading: false })
 }
 
 /**

+ 8 - 0
src/api/modules/task/task.ts

@@ -9,6 +9,14 @@ export const listTaskApi = (query: TaskQuery) => {
   return http.get<TaskVO[]>('/task/task/list', query, { loading: true })
 }
 
+/**
+ * @name 查询所有算法
+ * @returns 返回列表
+ */
+export const getAlgorithmOptionApi = () => {
+  return http.get<TaskVO[]>('/task/task/getAlgorithmOption')
+}
+
 /**
  * @name 查询算法任务详细
  * @param id id

文件差异内容过多而无法显示
+ 0 - 1
src/assets/images/logo.svg


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

@@ -8,7 +8,11 @@
     :top="parameter.top"
     draggable
   >
-    <ProFrom ref="proFormRef" :items-options="parameter.itemsOptions" :form-options="_options" :model="parameter.model" />
+    <ProFrom ref="proFormRef" :items-options="parameter.itemsOptions" :form-options="_options" :model="parameter.model">
+      <template #modelAddress="{}">
+        <FileUpload :file-size="4096" :file-type="['pt']" />
+      </template>
+    </ProFrom>
     <template #footer>
       <span class="dialog-footer">
         <el-button type="primary" v-if="parameter.isEdit" :loading="butLoading" @click="handleSubmit">确认</el-button>
@@ -22,6 +26,7 @@
 import { ref, ComputedRef, computed } from 'vue'
 import ProFrom from '@/components/ProForm/index.vue'
 import { ElMessage } from 'element-plus'
+import FileUpload from '@/components/Upload/File.vue'
 
 export interface FormParameterProps {
   title: string // 标题

+ 1 - 1
src/components/ImportPicDataset/index.vue

@@ -108,7 +108,7 @@ const parameter = ref<ParameterProps>({
   width: 500,
   top: '20vh',
   multiple: false,
-  fileSize: 5,
+  fileSize: 4096,
   fileType: ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
   ZipFileType: ['application/zip', 'application/x-zip-compressed', 'application/x-rar-compressed']
 })

+ 10 - 3
src/components/ProForm/index.vue

@@ -25,7 +25,7 @@
               <SelectIcon v-model:icon-value="formModel[item.prop]" />
             </template>
             <template v-else-if="item.compOptions.elTagName === 'file-upload'">
-              <FileUpload v-model:model-value="formModel[item.prop]" />
+              <FileUpload v-model:model-value="formModel[item.prop]" v-bind="$attrs" />
             </template>
             <template v-else-if="item.compOptions.elTagName === 'img-upload'">
               <uploadImg v-model:image-url="formModel[item.prop]" />
@@ -46,8 +46,8 @@
       </template>
     </el-row>
     <el-form-item v-if="_formOptions.hasFooter">
-      <slot name="operation" :model="formModel" :pro-form-ref="proFormRef">
-        <el-button type="primary" @click="onSubmit(proFormRef)">{{ _formOptions.submitButtonText }}</el-button>
+      <slot name="operation" :form-model="formModel" :model="formModel" :pro-form-ref="proFormRef">
+        <el-button type="primary" v-if="_formOptions.showSubmitButton" @click="onSubmit(proFormRef)">{{ _formOptions.submitButtonText }}</el-button>
         <el-button v-if="_formOptions.showResetButton" type="info" @click="resetForm(proFormRef)">
           {{ _formOptions.resetButtonText }}
         </el-button>
@@ -146,6 +146,13 @@ props.itemsOptions.forEach(async item => {
   await setEnumMap(item)
 })
 const emits = defineEmits<EmitEvent>()
+// 监听itemsOptions变化
+watch(props, () => {
+  // 处理表单项需要的参数
+  props.itemsOptions.forEach(async item => {
+    await setEnumMap(item)
+  })
+})
 // 根据items初始化model, 如果items有传值就用传递的model数据模型,否则就给上面声明的formModel设置相应的(key,value) [item.prop], item.value是表单的默认值(选填)
 watch(
   () => props.model,

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

@@ -138,7 +138,6 @@ const radio = ref('')
 
 // 表格多选 Hooks
 const { selectionChange, selectedList, selectedListIds, isSelected } = useSelection(props.rowKey)
-
 // 表格操作 Hooks
 const { tableData, pageable, searchParam, searchInitParam, getTableList, search, reset, handleSizeChange, handleCurrentChange } = useTable(
   props.requestApi,

+ 0 - 1
src/components/Upload/File.vue

@@ -175,7 +175,6 @@ const uploadSuccess = (response: any | undefined, uploadFile: UploadFile) => {
 
 // 上传结束处理
 const uploadedSuccessfully = () => {
-  debugger
   if (number.value > 0 && uploadList.value.length === number.value) {
     _fileList.value = _fileList.value.filter(f => f.url !== undefined).concat(uploadList.value)
     uploadList.value = []

+ 0 - 1
src/components/Upload/FileS3.vue

@@ -175,7 +175,6 @@ const uploadSuccess = (response: any | undefined, uploadFile: UploadFile) => {
 
 // 上传结束处理
 const uploadedSuccessfully = () => {
-  debugger
   if (number.value > 0 && uploadList.value.length === number.value) {
     _fileList.value = _fileList.value.filter(f => f.url !== undefined).concat(uploadList.value)
     uploadList.value = []

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

@@ -15,7 +15,7 @@
       :accept="fileType.join(',')"
     >
       <template v-if="imageUrl">
-        <img :src="imageUrl" class="upload-image" />
+        <img :src="'/api' + imageUrl" class="upload-image" />
         <div class="upload-handle" @click.stop>
           <div v-if="!self_disabled" class="handle-icon" @click="editImg">
             <el-icon><Edit /></el-icon>
@@ -43,7 +43,7 @@
     <div class="el-upload__tip">
       <slot name="tip"></slot>
     </div>
-    <el-image-viewer v-if="imgViewVisible" :url-list="[imageUrl]" @close="imgViewVisible = false" />
+    <el-image-viewer v-if="imgViewVisible" :url-list="['/api' + imageUrl]" @close="imgViewVisible = false" />
   </div>
 </template>
 

+ 8 - 8
src/layouts/components/Header/ToolBarRight.vue

@@ -1,11 +1,11 @@
 <template>
   <div class="tool-bar-ri">
     <div class="header-icon">
-      <SwitchDark />
-      <AssemblySize id="assemblySize" />
+      <!-- <SwitchDark /> -->
+      <!-- <AssemblySize id="assemblySize" /> -->
       <!-- <Language id="language" /> -->
-      <SearchMenu id="searchMenu" />
-      <ThemeSetting id="themeSetting" />
+      <!-- <SearchMenu id="searchMenu" /> -->
+      <!-- <ThemeSetting id="themeSetting" /> -->
       <!-- <Message id="message" /> -->
       <Fullscreen id="fullscreen" />
     </div>
@@ -17,14 +17,14 @@
 <script setup lang="ts">
 // import { computed } from 'vue'
 // import { useUserStore } from '@/stores/modules/user'
-import AssemblySize from './components/AssemblySize.vue'
+// import AssemblySize from './components/AssemblySize.vue'
 // import Language from './components/Language.vue'
-import SearchMenu from './components/SearchMenu.vue'
-import ThemeSetting from './components/ThemeSetting.vue'
+// import SearchMenu from './components/SearchMenu.vue'
+// import ThemeSetting from './components/ThemeSetting.vue'
 // import Message from './components/Message.vue'
 import Fullscreen from './components/Fullscreen.vue'
 import Avatar from './components/Avatar.vue'
-import SwitchDark from '@/components/SwitchDark/index.vue'
+// import SwitchDark from '@/components/SwitchDark/index.vue'
 
 // const userStore = useUserStore()
 // const username = computed(() => userStore.name || 'KM')

+ 19 - 4
src/routers/modules/routerData.json

@@ -25,8 +25,8 @@
         "title": "创建任务",
         "link": "",
         "full": false,
-        "affix": true,
-        "noCache": true,
+        "affix": false,
+        "noCache": false,
         "activeMenu": "/index"
       }
     },
@@ -40,7 +40,7 @@
         "title": "日志",
         "link": "",
         "full": false,
-        "affix": true,
+        "affix": false,
         "noCache": true,
         "activeMenu": "/index"
       }
@@ -55,7 +55,22 @@
         "title": "结果",
         "link": "",
         "full": false,
-        "affix": true,
+        "affix": false,
+        "noCache": true,
+        "activeMenu": "/index"
+      }
+    },
+    {
+      "path": "/inferResult",
+      "name": "inferResult",
+      "component": "taais/homePage/inferResult",
+      "hidden": true,
+      "meta": {
+        "icon": "HomeFilled",
+        "title": "结果",
+        "link": "",
+        "full": false,
+        "affix": false,
         "noCache": true,
         "activeMenu": "/index"
       }

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

@@ -29,7 +29,7 @@ export const useAuthStore = defineStore('admin-auth', {
     // Get AuthMenuList
     async getAuthMenuList() {
       const { data } = await getRoutersApi()
-      this.authMenuList = [...staticRouterList.data, ...data]
+      this.authMenuList = [...staticRouterList.data, ...data] as any[]
     },
     // Set RouteName
     async setRouteName(name: string) {

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

@@ -7,7 +7,7 @@ export const useGlobalStore = defineStore('admin-global', {
   // 修改默认值之后,需清除 localStorage 数据
   state: (): GlobalState => ({
     // 布局模式 (纵向:vertical | 经典:classic | 横向:transverse | 分栏:columns)
-    layout: 'vertical',
+    layout: 'transverse',
     // element 组件大小
     assemblySize: 'default',
     // 当前系统语言
@@ -39,7 +39,7 @@ export const useGlobalStore = defineStore('admin-global', {
     // 标签页图标
     tabsIcon: true,
     // 页脚
-    footer: true
+    footer: false
   }),
   getters: {},
   actions: {

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

@@ -37,6 +37,8 @@ declare namespace ProForm {
     | 'time-select'
     | 'transfer' // label不显示 使用插槽吧
     | 'icon' // 图标
+    | 'tree'
+    | File.FileUploadType
   interface FormOptions {
     inline?: boolean
     labelWidth?: string | number
@@ -44,6 +46,7 @@ declare namespace ProForm {
     disabled?: boolean // 不可编辑
     hasFooter?: boolean // 是否显示底部操作按钮
     labelSuffix?: ': ' | string
+    showSubmitButton?: boolean
     showResetButton?: boolean // 是否展示重置按钮
     showCancelButton?: boolean // 是否展示取消按钮
     submitButtonText?: string

+ 18 - 0
src/typings/canvas.d.ts

@@ -0,0 +1,18 @@
+interface canvasPoint {
+  x: number
+  y: number
+  radius?: number
+  fill?: string
+  stroke?: string
+  strokeWidth?: number
+  left?: number
+  top?: number
+  selectable?: boolean
+  hasBorders?: boolean
+  hasControls?: boolean
+  evented?: boolean
+  originX?: string
+  originY?: string
+  id?: number
+  objectCaching?: boolean
+}

+ 106 - 0
src/utils/fabric.ts

@@ -0,0 +1,106 @@
+// 坐标点排序
+export const sortPoints = (aCoord: any) => {
+  let points = JSON.parse(JSON.stringify(aCoord))
+  // (tl tr) (bl,br)
+  const poiT: canvasPoint = linesIntersection(points[0] || points.tl, points[1] || points.tr, points[2] || points.br, points[3] || points.bl)
+  // (tl br) (tr,bl)
+  const poiB: canvasPoint = linesIntersection(points[0] || points.tl, points[3] || points.bl, points[2] || points.br, points[1] || points.tr)
+  if (poiT?.x != -1) {
+    // 第二个和第三个坐标互换
+    changePoint(points[1] || points.tr, points[2] || points.br)
+  } else if (poiB?.x != -1) {
+    // 第一个和第四个坐标互换
+    changePoint(points[0] || points.tl, points[3] || points.bl)
+    // 第二个和第三个坐标互换
+    changePoint(points[1] || points.tr, points[2] || points.br)
+    // 第一个和第二个坐标互换
+    changePoint(points[0] || points.tl, points[1] || points.tr)
+  }
+  return points
+}
+// 坐标点更换
+const changePoint = (poi1, poi2) => {
+  let temp = { x: poi1.x, y: poi1.y }
+  poi1.x = poi2.x
+  poi1.y = poi2.y
+
+  poi2.x = temp.x
+  poi2.y = temp.y
+}
+// 获取线段交点
+// 算法参考:https://www.jb51.net/article/90104.htm
+function linesIntersection(tl, tr, br, bl) {
+  let tn1 = tr.y - tl.y,
+    ty1 = tl.x - tr.x
+  let tn2 = br.y - bl.y,
+    ty2 = bl.x - br.x
+  let denominator = tn1 * ty2 - ty1 * tn2
+  if (denominator == 0) {
+    return { x: -1, y: -1 }
+  }
+  let distC_N2 = tn2 * bl.x + ty2 * bl.y
+  let distA_N2 = tn2 * tl.x + ty2 * tl.y - distC_N2
+  let distB_N2 = tn2 * tr.x + ty2 * tr.y - distC_N2
+
+  if (distA_N2 * distB_N2 >= 0) {
+    return { x: -1, y: -1 }
+  }
+  let distA_N1 = tn1 * tl.x + ty1 * tl.y
+  let distC_N1 = tn1 * bl.x + ty1 * bl.y - distA_N1
+  let distD_N1 = tn1 * br.x + ty1 * br.y - distA_N1
+  if (distC_N1 * distD_N1 >= 0) {
+    return { x: -1, y: -1 }
+  }
+  //计算交点坐标
+  let fraction = distA_N2 / denominator
+  let dx = fraction * ty1,
+    dy = -fraction * tn1
+  return { x: tl.x + dx, y: tl.y + dy }
+}
+
+export const useDrawArea = (
+  params = {
+    src: '',
+    width: 1920,
+    height: 1080,
+    area: ''
+  }
+) => {
+  const { src, width, height, area } = params
+  return new Promise((resolve, reject) => {
+    if (src && src != '' && area && area != '') {
+      let cvs = document.createElement('canvas')
+      let ctx: CanvasRenderingContext2D | null = cvs.getContext('2d')
+      let img = new Image()
+      img.setAttribute('crossOrigin', 'anonymous')
+      img.src = src
+      let points = area.split(',').map(item => {
+        return item.split(';').map(arss => Number(arss))
+      })
+      img.onload = () => {
+        cvs.width = width
+        cvs.height = height
+        if (ctx) {
+          ctx?.drawImage(img, 0, 0, width, height)
+          ctx.strokeStyle = '#ff0000'
+          ctx.lineWidth = 2
+          points.forEach(ar => {
+            ctx?.beginPath()
+            ctx?.moveTo(ar[0], ar[1])
+            ctx?.lineTo(ar[2], ar[3])
+            if (ar.length > 4) {
+              ctx?.lineTo(ar[4], ar[5])
+              ctx?.lineTo(ar[6], ar[7])
+            }
+            ctx?.closePath()
+            ctx?.stroke()
+          })
+        }
+        let url: string = cvs.toDataURL('image/png') || ''
+        resolve(url)
+      }
+    } else {
+      reject('')
+    }
+  })
+}

+ 7 - 11
src/views/ag/config/index.vue

@@ -156,10 +156,6 @@ const setItemsOptions = () => {
       label: '类型',
       prop: 'type',
       rules: [{ required: true, message: '类型不能为空', trigger: 'change' }],
-      options: {
-        labelKey: 'dictLabel',
-        valueKey: 'dictValue'
-      },
       compOptions: {
         elTagName: 'radio-group',
         labelKey: 'dictLabel',
@@ -168,13 +164,13 @@ const setItemsOptions = () => {
         placeholder: '请选择类型'
       }
     },
-    {
-      label: '父id',
-      prop: 'parentId',
-      compOptions: {
-        placeholder: '请输入父id'
-      }
-    },
+    // {
+    //   label: '父id',
+    //   prop: 'parentId',
+    //   compOptions: {
+    //     placeholder: '请输入父id'
+    //   }
+    // },
     {
       label: '分系统',
       prop: 'subsystem',

+ 27 - 3
src/views/ag/model/index.vue

@@ -34,7 +34,7 @@
 </template>
 
 <script setup lang="tsx" name="Model">
-import { ref, reactive } from 'vue'
+import { ref, reactive, onMounted } from 'vue'
 import { useHandleData } from '@/hooks/useHandleData'
 import { useDownload } from '@/hooks/useDownload'
 import { ElMessageBox } from 'element-plus'
@@ -52,9 +52,11 @@ import {
   exportModelApi,
   getModelApi
 } from '@/api/modules/ag/model'
+import { getAlgorithmOptionApi } from '@/api/modules/task/task'
 
 // ProTable 实例
 const proTable = ref<ProTableInstance>()
+let allAgloData = ref([] as any[])
 
 // 删除算法模型配置信息
 const deleteModel = async (params: any) => {
@@ -154,7 +156,11 @@ const setItemsOptions = () => {
       prop: 'algorithmId',
       rules: [{ required: true, message: '算法不能为空', trigger: 'blur' }],
       compOptions: {
-        placeholder: '请输入算法'
+        elTagName: 'select',
+        labelKey: 'name',
+        valueKey: 'id',
+        enum: allAgloData.value,
+        placeholder: '请选择算法'
       }
     },
     {
@@ -165,12 +171,25 @@ const setItemsOptions = () => {
         placeholder: '请输入模型名称'
       }
     },
+    // {
+    //   label: '模型',
+    //   prop: 'modelAddress',
+    //   rules: [{ required: true, message: '模型不能为空', trigger: 'blur' }],
+    //   compOptions: {
+    //     elTagName: 'file-upload',
+    //     accept: '.pt',
+    //     fileSize: 4096,
+    //     fileType: ['pt']
+    //     // props: { fileSize: 4096, fileType: ['pt'] }
+    //     // props: { accept: '.pt' }
+    //   }
+    // },
     {
       label: '模型',
       prop: 'modelAddress',
       rules: [{ required: true, message: '模型不能为空', trigger: 'blur' }],
       compOptions: {
-        placeholder: '请输入模型'
+        elTagName: 'slot'
       }
     },
     {
@@ -196,4 +215,9 @@ const setItemsOptions = () => {
     }
   ]
 }
+onMounted(() => {
+  getAlgorithmOptionApi().then(res => {
+    allAgloData.value = res.data
+  })
+})
 </script>

+ 90 - 0
src/views/demo/components/img-detect.vue

@@ -0,0 +1,90 @@
+<template>
+  <el-dialog class="modal-canvas" v-model="visible" title="标注" width="980px" height="700px">
+    <ImgMaker ref="imgMaker" v-if="visible" :src="cover" :area="area" :width="width" :height="height"></ImgMaker>
+    <div style=" margin-top: 10px;text-align: center">
+      <!-- <el-space> -->
+      <el-button type="primary" @click="onClearLast">撤销最后一次的操作</el-button>
+      <el-button type="primary" @click="onClearAll">清空所有</el-button>
+      <el-button type="primary" @click="onCancel">取消</el-button>
+      <el-button type="primary" @click="onSubmit">保存</el-button>
+      <!-- </a-space> -->
+    </div>
+  </el-dialog>
+</template>
+<script lang="ts" setup>
+import { reactive, ref, toRefs, defineProps, watchEffect } from 'vue'
+import ImgMaker from './img-maker.vue'
+const props = defineProps({
+  area: {
+    type: String,
+    default: ''
+  },
+  img: {
+    type: String,
+    default: ''
+  },
+  width: {
+    type: Number,
+    default: 1920
+  },
+  height: {
+    type: Number,
+    default: 1080
+  }
+})
+const emit = defineEmits(['success'])
+const imgMaker = ref()
+const state = reactive({
+  visible: false,
+  cover: ''
+})
+const { visible, cover } = toRefs(state)
+watchEffect(() => {
+  state.cover = props.img
+})
+
+const onClearAll = () => {
+  imgMaker.value.clearAll()
+}
+const onClearLast = () => {
+  imgMaker.value.clearObjLast()
+}
+const onCancel = () => {
+  onClearAll()
+  state.visible = false
+  imgMaker.value.drawType = null
+}
+const onSubmit = () => {
+  let points = imgMaker.value.getData()
+  // console.log('points', points)
+
+  let datas = []
+  if (points.length > 0) {
+    datas = points.map(point => {
+      if (point.br) {
+        let w = point.tr.x - point.tl.x
+        let h = point.bl.y - point.tl.y
+
+        const algoData = `${point.tl.x / 1920};${point.tl.y / 1080};${w / 1920};${h / 1080}`
+        // return `${point.tl.x};${point.tl.y};${point.tr.x};${point.tr.y};${point.br.x};${point.br.y};${point.bl.x};${point.bl.y}`
+        return algoData
+      } else {
+        let coors = ''
+        Object.keys(point).forEach(item => {
+          coors += `${point[item].x};${point[item].y};`
+        })
+        coors = coors.slice(0, -1)
+        return coors
+      }
+      // return `${point.tl.x};${point.tl.y};${point.tr.x};${point.tr.y}`
+    })
+  }
+  // console.log('datas', datas)
+  // 归一化
+
+  emit('success', datas)
+  onClearAll()
+  state.visible = false
+}
+defineExpose({ visible, cover })
+</script>

+ 645 - 0
src/views/demo/components/img-maker.vue

@@ -0,0 +1,645 @@
+<template>
+  <div>
+    <div style="margin-bottom: 10px">
+      <el-button plain type="primary" class="shape-border" @click="drawTypeChange('rectangle')">矩形</el-button>
+      <!-- <el-button plain type="primary" class="shape-border" @click="drawPolygon('polygon')">多边形</el-button> -->
+    </div>
+    <canvas id="canvas" :width="cWidth" :height="cHeight"></canvas>
+  </div>
+</template>
+<script lang="ts" setup>
+import { fabric } from 'fabric'
+import { reactive, watch, onMounted } from 'vue'
+// import { sortPoints } from '@/utils/fabric'
+
+const props = defineProps({
+  src: {
+    type: String,
+    default: ''
+  },
+  area: {
+    type: String,
+    default: ''
+  },
+  width: {
+    type: Number,
+    default: 1920
+  },
+  height: {
+    type: Number,
+    default: 1080
+  },
+  cWidth: {
+    type: Number,
+    default: 960
+  },
+  cHeight: {
+    type: Number,
+    default: 540
+  }
+})
+const state = reactive({
+  loading: true,
+  radio: 0.5,
+  realRadioX: 0.5,
+  realRadioY: 0.5,
+  imgPoint: { x: 0, y: 0 },
+  realPoint: { x: 0, y: 0 },
+  canvas: {} as any,
+  mouseFrom: { x: 0, y: 0 } as canvasPoint,
+  mouseTo: { x: 0, y: 0 } as canvasPoint,
+  // drawType: 'rectangle' as string, //当前绘制图像的种类
+  drawType: null as any, //当前绘制图像的种类
+  drawWidth: 1, //笔触宽度
+  color: '#E34F51', //画笔颜色
+  drawingObject: null as any, //当前绘制对象
+  moveCount: 1, //绘制移动计数器
+  doDrawing: false as boolean, // 绘制状态
+  rectPath: '' as string, //矩形绘制路径
+  //polygon 相关参数
+  polygonMode: false as boolean,
+  pointArray: [] as canvasPoint[],
+  lineArray: [] as canvasPoint[],
+  activeShape: false as any,
+  activeLine: '' as any,
+  line: {} as canvasPoint
+})
+watch(
+  () => state.drawType,
+  value => {
+    state.canvas.selection = !value
+  }
+)
+watch(
+  () => props.width,
+  value => {
+    state.canvas.setWidth(value)
+  }
+)
+watch(
+  () => props.height,
+  value => {
+    state.canvas.setHeight(value)
+  }
+)
+
+const loadInit = () => {
+  if (props.src == '') {
+    return
+  }
+  state.loading = true
+  state.canvas = new fabric.Canvas('canvas', {})
+  state.canvas.selectionColor = 'rgba(0,0,0,0.05)'
+  state.canvas.on('mouse:down', mousedown)
+  state.canvas.on('mouse:move', mousemove)
+  state.canvas.on('mouse:up', mouseup)
+  let imgElement = new Image()
+  imgElement.src = props.src
+  imgElement.onload = () => {
+    // 区域大小/图片原始大小 缩放比例
+    state.radio =
+      props.cWidth / imgElement.width > props.cHeight / imgElement.height ? props.cHeight / imgElement.height : props.cWidth / imgElement.width
+    // console.log('state.radio', state.radio)
+
+    // 屏幕分辨率/图片原始大小
+    state.realRadioX = props.width / imgElement.width
+    state.realRadioY = props.height / imgElement.height
+
+    state.imgPoint.x = Math.floor(imgElement.width / 2)
+    state.imgPoint.y = Math.floor(imgElement.height / 2)
+
+    state.realPoint.x = Math.floor(props.width / 2)
+    state.realPoint.y = Math.floor(props.height / 2)
+    let imgInstance = new fabric.Image(imgElement, {
+      selectable: false,
+      width: imgElement.width,
+      height: imgElement.height,
+      scaleX: state.radio,
+      scaleY: state.radio
+    })
+    state.canvas.add(imgInstance)
+    drawImage()
+    state.canvas.renderAll()
+    state.loading = false
+  }
+}
+const drawImage = () => {
+  if (props.area === '') {
+    clearAll()
+    return
+  }
+  let points = props.area.split(',').map(item => {
+    let areas = item.split(';')
+    let data = areas.map((ars, index) => {
+      let arp = 0
+      let ar = Number(ars)
+      if (index % 2 == 0) {
+        let dx = Math.abs(state.realPoint.x > ar ? state.realPoint.x - ar : state.realPoint.x + ar) / state.realRadioX
+        let rdx = Math.abs(state.imgPoint.x - dx)
+        arp = rdx
+      } else {
+        let dy = Math.abs(state.realPoint.y > ar ? state.realPoint.y - ar : state.realPoint.y + ar) / state.realRadioY
+        let rdy = Math.abs(state.imgPoint.y - dy)
+        arp = rdy
+      }
+      return Number(arp) * state.radio
+    })
+    return data
+  })
+  points.forEach(point => {
+    drawImageObj(point)
+  })
+}
+const drawImageObj = data => {
+  let path = 'M '
+  // debugger
+  let points = [] as any
+  let len = data.length / 2
+  for (let i = 0; i < len; i++) {
+    let idx = i * 2
+    points.push({ x: data[idx], y: data[idx + 1] })
+    path += `${data[idx]} ${data[idx + 1]} L `
+  }
+  let canvasObject = null as any
+  if (points[0]?.y === points[1]?.y && points[2]?.y === points[3]?.y && points[0]?.x === points[3]?.x && points[1]?.x - points[2]?.x) {
+    path = path.replace(/L\s$/g, 'z')
+    canvasObject = new fabric.Path(path, {
+      left: data[0],
+      top: data[1],
+      stroke: state.color,
+      selectable: false,
+      strokeWidth: state.drawWidth,
+      fill: 'rgba(255, 255, 255, 0)',
+      hasControls: false
+    })
+  } else {
+    canvasObject = new fabric.Polygon(points, {
+      stroke: state.color,
+      strokeWidth: state.drawWidth,
+      fill: 'rgba(255, 255, 255, 0)',
+      opacity: 1,
+      hasBorders: false,
+      hasControls: false,
+      evented: false
+    })
+  }
+  canvasObject['points'] = points
+  state.canvas.add(canvasObject)
+}
+const drawTypeChange = e => {
+  state.drawType = e
+  state.canvas.skipTargetFind = !!e
+  if (e == 'pen') {
+    // isDrawingMode为true 才可以自由绘画
+    state.canvas.isDrawingMode = true
+  } else {
+    state.canvas.isDrawingMode = false
+  }
+}
+// 鼠标按下时触发
+const mousedown = e => {
+  // 记录鼠标按下时的坐标
+  let xy = e.pointer || transformMouse(e.e.offsetX, e.e.offsetY)
+
+  state.mouseFrom.x = xy.x
+  state.mouseFrom.y = xy.y
+  state.doDrawing = true
+  // 绘制多边形
+  if (state.drawType == 'polygon') {
+    state.canvas.skipTargetFind = false
+    try {
+      // 此段为判断是否闭合多边形,点击红点时闭合多边形
+      if (state.pointArray.length > 1) {
+        // e.target.id == this.pointArray[0].id 表示点击了初始红点
+        if (e.target && e.target.id == state.pointArray[0].id) {
+          generatePolygon()
+        }
+      }
+      //未点击红点则继续作画
+      if (state.polygonMode) {
+        addPoint(e)
+      }
+    } catch (error) {
+      console.log(error)
+    }
+  }
+}
+// 鼠标松开执行
+const mouseup = e => {
+  let xy = e.pointer || transformMouse(e.e.offsetX, e.e.offsetY)
+  state.mouseTo.x = xy.x
+  state.mouseTo.y = xy.y
+  state.drawingObject = null
+  state.moveCount = 1
+  if (state.drawType != 'polygon' && state.drawType != 'line') {
+    state.doDrawing = false
+  }
+  // 设置只允许绘制一个
+  // let canvasObj = state.canvas.getObjects();
+  // if(canvasObj.length >2){
+  //   state.canvas.remove(canvasObj[1])
+  // }
+}
+//鼠标移动过程中已经完成了绘制
+const mousemove = e => {
+  if (state.moveCount % 2 && !state.doDrawing) {
+    //减少绘制频率
+    return
+  }
+  state.moveCount++
+  let xy = e.pointer || transformMouse(e.e.offsetX, e.e.offsetY)
+  if (xy.y >= 0 && xy.x <= props.cWidth && xy.y >= 0 && xy.y <= props.cHeight) {
+    state.mouseTo.x = xy.x
+    state.mouseTo.y = xy.y
+    // 矩形
+    if (state.drawType == 'rectangle') {
+      if (state.mouseFrom.x < state.mouseTo.x && state.mouseFrom.y < state.mouseTo.y) {
+        drawing()
+      } else {
+        // clearAll();
+      }
+    }
+    if (state.drawType == 'polygon') {
+      if (state.activeLine && state.activeLine.class == 'line') {
+        let pointer = state.canvas.getPointer(e.e)
+        state.activeLine.set({ x2: pointer.x, y2: pointer.y })
+
+        let points = state.activeShape.get('points')
+        points[state.pointArray.length] = {
+          x: pointer.x,
+          y: pointer.y,
+          zIndex: 1
+        }
+        state.activeShape.set({
+          points: points
+        })
+        state.canvas.renderAll()
+      }
+      state.canvas.renderAll()
+    }
+  } else {
+    // clearAll();
+  }
+}
+// 绘制矩形
+const drawing = () => {
+  if (state.drawingObject) {
+    state.canvas.remove(state.drawingObject)
+  }
+  let canvasObject = null
+  let left = state.mouseFrom.x,
+    top = state.mouseFrom.y,
+    mouseFrom = state.mouseFrom,
+    mouseTo = state.mouseTo
+  let path =
+    'M ' +
+    mouseFrom.x +
+    ' ' +
+    mouseFrom.y +
+    ' L ' +
+    mouseTo.x +
+    ' ' +
+    mouseFrom.y +
+    ' L ' +
+    mouseTo.x +
+    ' ' +
+    mouseTo.y +
+    ' L ' +
+    mouseFrom.x +
+    ' ' +
+    mouseTo.y +
+    ' L ' +
+    mouseFrom.x +
+    ' ' +
+    mouseFrom.y +
+    ' z'
+  state.rectPath = path
+  canvasObject = new fabric.Path(path, {
+    left: left,
+    top: top,
+    stroke: state.color,
+    selectable: false,
+    strokeWidth: state.drawWidth,
+    fill: 'rgba(255, 255, 255, 0)',
+    hasControls: false
+  })
+  if (canvasObject) {
+    state.canvas.add(canvasObject)
+    state.drawingObject = canvasObject
+  }
+}
+// 绘制多边形开始,绘制多边形和其他图形不一样,需要单独处理
+// const drawPolygon = type => {
+//   state.drawType = type
+//   state.polygonMode = true
+//   //这里画的多边形,由顶点与线组成
+//   state.pointArray = [] // 顶点集合
+//   state.lineArray = [] //线集合
+//   state.canvas.isDrawingMode = false
+// }
+const addPoint = e => {
+  let random = Math.floor(Math.random() * 10000)
+  let id = new Date().getTime() + random
+  let circle = new fabric.Circle({
+    radius: 5,
+    fill: '#ffffff',
+    stroke: '#333333',
+    strokeWidth: 0.5,
+    left: (e.pointer.x || e.e.layerX) / state.canvas.getZoom(),
+    top: (e.pointer.y || e.e.layerY) / state.canvas.getZoom(),
+    selectable: false,
+    hasBorders: false,
+    hasControls: false,
+    originX: 'center',
+    originY: 'center',
+    id: id,
+    objectCaching: false
+  })
+  if (state.pointArray.length == 0) {
+    circle.set({
+      fill: '#00FFFF'
+    })
+  }
+  let points = [
+    (e.pointer.x || e.e.layerX) / state.canvas.getZoom(),
+    (e.pointer.y || e.e.layerY) / state.canvas.getZoom(),
+    (e.pointer.x || e.e.layerX) / state.canvas.getZoom(),
+    (e.pointer.y || e.e.layerY) / state.canvas.getZoom()
+  ]
+
+  state.line = new fabric.Line(points, {
+    strokeWidth: 2,
+    fill: '#999999',
+    stroke: '#999999',
+    class: 'line',
+    originX: 'center',
+    originY: 'center',
+    selectable: false,
+    hasBorders: false,
+    hasControls: false,
+    evented: false,
+
+    objectCaching: false
+  })
+  if (state.activeShape) {
+    let pos = state.canvas.getPointer(e.e)
+    let points = state.activeShape.get('points')
+    points.push({
+      x: pos.x,
+      y: pos.y
+    })
+    let polygon = new fabric.Polygon(points, {
+      stroke: '#333333',
+      strokeWidth: 1,
+      fill: '#cccccc',
+      opacity: 0.3,
+      selectable: false,
+      hasBorders: false,
+      hasControls: false,
+      evented: false,
+      objectCaching: false
+    })
+    state.canvas.remove(state.activeShape)
+    state.canvas.add(polygon)
+    state.activeShape = polygon
+    state.canvas.renderAll()
+  } else {
+    let polyPoint = [
+      {
+        x: (e.pointer.x || e.e.layerX) / state.canvas.getZoom(),
+        y: (e.pointer.y || e.e.layerY) / state.canvas.getZoom()
+      }
+    ]
+    let polygon = new fabric.Polygon(polyPoint, {
+      stroke: '#333333',
+      strokeWidth: 1,
+      fill: '#cccccc',
+      opacity: 0.3,
+      selectable: false,
+      hasBorders: false,
+      hasControls: false,
+      evented: false,
+      objectCaching: false
+    })
+    state.activeShape = polygon
+    state.canvas.add(polygon)
+  }
+  state.activeLine = state.line
+
+  state.pointArray.push(circle)
+  state.lineArray.push(state.line)
+  state.canvas.add(state.line)
+  state.canvas.add(circle)
+}
+// 绘制不规则
+const generatePolygon = () => {
+  // let points = clearPolygonLines()
+  // let polygon = new fabric.Polygon(sortPoints(points), {
+  //   stroke: state.color,
+  //   strokeWidth: state.drawWidth,
+  //   fill: 'rgba(255, 255, 255, 0)',
+  //   opacity: 1,
+  //   hasBorders: false,
+  //   hasControls: false,
+  //   evented: false
+  // })
+  // state.canvas.add(polygon)
+  let points = [{}]
+  console.log('state.pointArray', state.pointArray)
+
+  state.pointArray.map(point => {
+    points.push({
+      x: point.left,
+      y: point.top
+    })
+    state.canvas.remove(point)
+  })
+  state.lineArray.map(line => {
+    state.canvas.remove(line)
+  })
+  state.canvas.remove(state.activeShape).remove(state.activeLine)
+  let polygon = new fabric.Polygon(points, {
+    stroke: state.color,
+    strokeWidth: state.drawWidth,
+    fill: 'rgba(255, 255, 255, 0)',
+    opacity: 1,
+    hasBorders: true,
+    hasControls: false
+  })
+  state.canvas.add(polygon)
+  resetPolygon()
+}
+// 坐标转换
+const transformMouse = (mouseX, mouseY) => {
+  return { x: mouseX / 1, y: mouseY / 1 }
+}
+// 重置不规则四边形
+const resetPolygon = () => {
+  state.activeLine = null
+  state.activeShape = null
+  state.polygonMode = false
+  state.doDrawing = false
+  state.drawType = null
+}
+// 清除绘制四边形的四个坐标点
+const clearPolygonLines = () => {
+  let points = [{}]
+  state.pointArray.forEach(point => {
+    points.push({
+      x: point.left,
+      y: point.top
+    })
+    state.canvas.remove(point)
+  })
+  state.lineArray.forEach(line => {
+    state.canvas.remove(line)
+  })
+  state.canvas.remove(state.activeShape).remove(state.activeLine)
+  return points
+}
+// 撤销最后一次的操作
+const clearObjLast = () => {
+  let canvasObjs = state.canvas.getObjects()
+  let len = canvasObjs.length
+  if (len > 1) {
+    state.canvas.remove(canvasObjs[len - 1])
+  }
+}
+// 全部清除
+const clearAll = () => {
+  state.canvas.getObjects().forEach((element, index) => {
+    if (index > 0) {
+      state.canvas.remove(element)
+    }
+  })
+  clearPolygonLines()
+  resetPolygon()
+  state.drawType = 'rectangle'
+}
+const getPoint = pi => {
+  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
+  let dy = Math.abs(state.imgPoint.y > poi.y ? state.imgPoint.y - poi.y : state.imgPoint.y + poi.y) * state.realRadioY
+  let rdx = Math.abs(state.realPoint.x - dx)
+  let rdy = Math.abs(state.realPoint.y - dy)
+  let minX = Math.min(Math.floor(rdx), props.width)
+  let minY = Math.min(Math.floor(rdy), props.height)
+  return { x: minX, y: minY }
+}
+// 生成真实分辨率图片的坐标点
+const getData = () => {
+  let datas = [] as any
+  let marks = ['tl', 'tr', 'br', 'bl']
+  // if (state.lineArray.length > 0 && state.lineArray.length < 4) {
+  //   clearPolygonLines()
+  // }
+  state.canvas.getObjects().forEach((item, index) => {
+    if (index > 0) {
+      let aCoords = item.aCoords
+      let point = {}
+      if (item.points) {
+        item.points.forEach((item, idx) => {
+          // if (aCoords[marks[idx]]) {
+          //   aCoords[marks[idx]].x = item.x
+          //   aCoords[marks[idx]].y = item.y
+          // }
+          // if (idx > 0) {
+          point[idx] = getRealPoint({
+            x: item?.x,
+            y: item?.y
+          })
+          // }
+        })
+      } else {
+        marks.forEach(mark => {
+          let poi = {
+            x: getPoint(aCoords[mark].x),
+            y: getPoint(aCoords[mark].y)
+          }
+          point[mark] = getRealPoint(poi)
+        })
+      }
+
+      if (item.points && item.points.length === 2) {
+        delete point['br']
+        delete point['bl']
+      }
+      datas.push(point)
+    }
+  })
+  return datas
+}
+// 获取归一化数据比例
+const normalization = () => {
+  return {
+    realRadioX: state.realRadioX,
+    realRadioY: state.realRadioY
+  }
+}
+defineExpose({ drawType: state.drawType, clearObjLast, clearAll, getData, normalization })
+onMounted(() => {
+  loadInit()
+})
+</script>
+
+<style lang="scss" scoped>
+canvas {
+  border: 1px dashed black;
+}
+.loading-box {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  width: 960px;
+  height: 540px;
+  font-size: 14px;
+  color: #ea5413;
+}
+.draw-btn-group {
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+  width: 960px;
+  margin-top: 10px;
+  .active {
+    .draw-rect {
+      background: #ff00ff;
+      border-color: #ff00ff;
+    }
+  }
+  .shape-box {
+    width: 120px;
+    text-align: left;
+  }
+  .shape-border {
+    display: block;
+    width: 80px;
+    height: 30px;
+    margin-right: 30px;
+    font-size: 12px;
+    text-align: center;
+  }
+  .shape-border-ti {
+    transform: skewX(-45deg);
+  }
+  .draw-icon {
+    display: inline-block;
+    width: 80px;
+    height: 30px;
+  }
+  .draw-rect {
+    width: 80px;
+    border-color: #333333;
+    border-style: solid;
+    border-width: 1px;
+  }
+  .draw-line {
+    position: relative;
+    top: -14px;
+    border-bottom: 2px solid #00ffff;
+  }
+}
+</style>

+ 65 - 6
src/views/demo/data/index.vue

@@ -1,6 +1,9 @@
 <template>
   <div class="table-box">
     <ProTable ref="proTable" :columns="columns" row-key="id" :request-api="listDataApi" :init-param="initParam">
+      <template #yuan="scope">
+        <el-image style="width: 100px" :src="'/api' + scope.row.url" @click="markImg(scope.row)" />
+      </template>
       <!-- 表格 header 按钮 -->
       <template #tableHeader="scope">
         <el-button type="primary" v-auth="['demo:data:add']" :icon="CirclePlus" @click="openDialog(1, '数据新增')"> 新增 </el-button>
@@ -19,6 +22,7 @@
       </template>
       <!-- 表格操作 -->
       <template #operation="scope">
+        <!-- <el-button type="primary" link :icon="EditPen" v-auth="['demo:data:edit']" @click="openDialog(2, '数据标注', scope.row)"> 标注 </el-button> -->
         <el-button type="primary" link :icon="EditPen" v-auth="['demo:data:edit']" @click="openDialog(2, '数据编辑', scope.row)"> 编辑 </el-button>
         <el-button type="primary" link :icon="View" v-auth="['demo:data:query']" @click="openDialog(3, '数据查看', scope.row)"> 查看 </el-button>
         <el-button type="primary" link :icon="Delete" v-auth="['demo:data:remove']" @click="deleteData(scope.row)"> 删除 </el-button>
@@ -27,22 +31,23 @@
 
     <FormDialog ref="formDialogRef" />
     <ImportPicDataset ref="dialogRef" />
+    <ImgDetect ref="imgDetect" :img="cover" :area="area" :width="width" :height="height" @success="handleImgSuccess"></ImgDetect>
   </div>
 </template>
 
 <script setup lang="tsx" name="Data">
-import { ref, reactive } from 'vue'
+import { ref, reactive, toRefs } from 'vue'
 import { useHandleData } from '@/hooks/useHandleData'
 import { useDownload } from '@/hooks/useDownload'
-import { ElMessageBox } from 'element-plus'
+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 ImportPicDataset from '@/components/ImportPicDataset/index.vue'
-// import uploadImgs from '@/components/Upload/Imgs.vue'
-// import uploadImg from '@/components/Upload/Img.vue'
 import { ProTableInstance, ColumnProps } from '@/components/ProTable/interface'
 import { Delete, EditPen, Download, Upload, View, CirclePlus } from '@element-plus/icons-vue'
+// import { fabric } from 'fabric'
+import { useDrawArea } from '@/utils/fabric'
+import ImgDetect from '../components/img-detect.vue'
 import {
   listDataApi,
   delDataApi,
@@ -53,9 +58,20 @@ import {
   exportDataApi,
   getDataApi
 } from '@/api/modules/demo/data'
+const imgDetect = ref()
+const state = reactive({
+  area: '' as string,
+  width: 1920 as number,
+  height: 1080 as number,
+  cover: ''
+})
+const { area, width, height, cover } = toRefs(state)
 
 // ProTable 实例
 const proTable = ref<ProTableInstance>()
+// const getImageUrl = name => {
+//   return new URL(name, import.meta.url).href
+// }
 
 const initParam = reactive({ type: 1 })
 // 删除数据管理信息
@@ -64,6 +80,49 @@ const deleteData = async (params: any) => {
   proTable.value?.getTableList()
 }
 
+// 标注图片
+const markImg = data => {
+  state.cover = '/api' + data.url
+  // area 代表后端的传来的标注数据
+  const area = []
+  if (state.cover != '') {
+    if (area.length != 0) {
+      handleImgSuccess(area)
+    }
+    imgDetect.value.visible = true
+  } else {
+    ElMessage.warning('缺失图像,暂时不能进行区域添加!')
+  }
+}
+const getList = () => {
+  useDrawArea({
+    src: state.cover,
+    width: state.width,
+    height: state.height,
+    area: state.area
+  })
+    .then(url => {
+      state.cover = url as string
+    })
+    .catch(error => {
+      console.log(error)
+    })
+}
+const handleImgSuccess = data => {
+  data.forEach(item => {
+    const area = item.split(';')
+    // try=tly blx=tlx brx=trx bry=bly
+    const tlx = Math.round(Number(area[0]) * 1920)
+    const tly = Math.round(Number(area[1]) * 1080)
+    const trx = tlx + Math.round(Number(area[2]) * 1920)
+    const bly = tly + Math.round(Number(area[3]) * 1080)
+    state.area += `${tlx};${tly};${trx};${tly};${trx};${bly};${tlx};${bly},`
+  })
+  // console.log('state.area', state.area)
+  state.area.slice(0, -1)
+  getList()
+}
+
 // 批量删除数据管理信息
 const batchDelete = async (ids: string[]) => {
   await useHandleData(delDataApi, ids, '删除所选数据信息')
@@ -114,7 +173,7 @@ const openDialog = async (type: number, title: string, row?: any) => {
 // 表格配置项
 const columns = reactive<ColumnProps<any>[]>([
   { type: 'selection', fixed: 'left', width: 70 },
-
+  { prop: 'yuan', label: '原图', width: 200 },
   {
     prop: 'name',
     label: '名称',

+ 3 - 3
src/views/login/index.vue

@@ -1,14 +1,14 @@
 <template>
   <div class="login-container flx-center">
     <div class="login-box">
-      <SwitchDark class="dark" />
+      <!-- <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">KM-Admin</h2>
+          <h2 class="logo-text">算法任务系统</h2>
         </div>
         <LoginForm />
       </div>
@@ -18,7 +18,7 @@
 
 <script setup lang="ts" name="login">
 import LoginForm from './components/LoginForm.vue'
-import SwitchDark from '@/components/SwitchDark/index.vue'
+// import SwitchDark from '@/components/SwitchDark/index.vue'
 </script>
 
 <style scoped lang="scss">

+ 0 - 1
src/views/system/user/index.vue

@@ -153,7 +153,6 @@ const roleOptions = ref<any[]>([])
 // 打开弹框的功能
 const openDialog = async (type: number, title: string, row?: any) => {
   let res = await getUserApi(row?.userId || null)
-  debugger
   postOptions.value = res.data.posts
   roleOptions.value = res.data.roles
   // 表单项配置

+ 1107 - 351
src/views/taais/homePage/createTask.vue

@@ -1,125 +1,342 @@
 <template>
   <div class="createTask-bigBox">
-    <dv-border-box1 ref="borderRef" style="width: 1000px; height: 650px; margin: 0 auto">
+    <dv-border-box1 ref="borderRef" style="width: 80%; height: calc(100% - 20px); margin: 0 auto">
       <div class="createTask-container">
-        <h3 class="title">{{ title }}</h3>
-        <h4 class="title2" v-if="pageIndex === 4">训练算法</h4>
-        <div v-for="(item, index) in formItems" :key="index">
-          <ProForm :items-options="item.items" :form-options="_options" :model="item.model" class="proform">
-            <template #transfer1="{ formModel }">
-              <el-transfer filterable v-model="formModel.transfer1" :data="transferImg1">
-                <template #default="{ option }">
-                  <el-image
-                    style="width: 50px; height: 50px"
-                    :preview-src-list="[getImageUrl(option.label)]"
-                    :src="getImageUrl(option.label)"
-                  ></el-image>
-                </template>
-              </el-transfer>
+        <h3 class="title" style="margin-top: 0">{{ title }}</h3>
+        <!-- <h4 class="title2" v-if="pageIndex === 4">训练算法</h4> -->
+        <div v-for="(item, index) in formItems" :key="index" class="createTask-main">
+          <ProForm ref="proFormRef" :items-options="item.items" :form-options="_options" :model="item.model" class="proform">
+            <template #selectTask>
+              <el-tree
+                style="max-width: 600px"
+                ref="selectTaskTreeRef"
+                :default-checked-keys="formItem.selectTask"
+                :default-expanded-keys="formItem.selectTask"
+                :props="defaultProps"
+                :check-on-click-node="true"
+                :data="data1"
+                node-key="id"
+                show-checkbox
+                @check="
+                  (click, checked) => {
+                    changeTree(click, checked)
+                  }
+                "
+              />
             </template>
-            <template #transfer2="{ formModel }">
-              <el-transfer filterable v-model="formModel.transfer2" :data="transferImg2">
-                <template #default="{ option }">
-                  <el-image
-                    style="width: 50px; height: 50px"
-                    :preview-src-list="[getImageUrl(option.label)]"
-                    :src="getImageUrl(option.label)"
-                  ></el-image>
-                </template>
-              </el-transfer>
+            <template #proTable="{}">
+              <el-tabs
+                tab-position="left"
+                v-model="activeName"
+                style="min-height: 450px"
+                class="demo-tabs"
+                :before-leave="beforeTabLeave"
+                @tab-click="handleClick"
+              >
+                <el-tab-pane label="数据一" name="one">
+                  <div class="table-box">
+                    <ProTable
+                      ref="proTable"
+                      row-key="id"
+                      :columns="dataColumns"
+                      :request-api="listDataApi"
+                      :tool-button="false"
+                      :init-param="initParam1"
+                      height="45vh"
+                    >
+                    </ProTable>
+                  </div>
+                </el-tab-pane>
+                <el-tab-pane label="数据二" name="two" :disabled="tabTwo">
+                  <div class="table-box">
+                    <ProTable
+                      ref="proTable"
+                      row-key="id"
+                      :columns="dataColumns"
+                      :request-api="listDataApi"
+                      :init-param="initParam2"
+                      :tool-button="false"
+                      height="45vh"
+                    >
+                    </ProTable>
+                  </div>
+                </el-tab-pane>
+                <el-tab-pane label="数据三" name="three" :disabled="tabThree">
+                  <div class="table-box">
+                    <ProTable
+                      ref="proTable"
+                      row-key="id"
+                      :columns="dataColumns"
+                      :request-api="listDataApi"
+                      :init-param="initParam3"
+                      :tool-button="false"
+                      height="45vh"
+                    >
+                    </ProTable>
+                  </div>
+                </el-tab-pane>
+                <el-tab-pane label="数据四" name="four" :disabled="tabFour">
+                  <div class="table-box">
+                    <ProTable
+                      ref="proTable"
+                      row-key="id"
+                      :columns="dataColumns"
+                      :request-api="listDataApi"
+                      :init-param="initParam4"
+                      :tool-button="false"
+                      height="45vh"
+                    >
+                    </ProTable>
+                  </div>
+                </el-tab-pane>
+              </el-tabs>
             </template>
-            <template #username1="{ formModel }">
-              <el-input v-model="formModel.username1" />
+            <template #operation="{}">
+              <div class="footBtn">
+                <el-button class="btn back" v-if="pageIndex === 1" @click="onReturn()"> 返回 </el-button>
+                <el-button class="btn back" v-else @click="onBack()"> 上一步 </el-button>
+                <el-button
+                  class="btn add"
+                  type="primary"
+                  v-if="(pageIndex === 2 || pageIndex === 6 || pageIndex === 10) && model.taskType === '1'"
+                  style="margin-left: -15px"
+                  @click="addNewData()"
+                >
+                  增加新一组数据
+                </el-button>
+                <el-button
+                  class="btn add"
+                  style="margin-left: -15px"
+                  v-if="(pageIndex === 5 || pageIndex === 9 || pageIndex === 13) && model.taskType === '2'"
+                  @click="onAdd(pageIndex)"
+                >
+                  增加算法
+                </el-button>
+                <el-button class="btn next" type="success" @click="nextBtnText === '提交' ? onSubmit() : onNext()">
+                  {{ nextBtnText }}
+                </el-button>
+              </div>
             </template>
           </ProForm>
         </div>
       </div>
-      <el-button class="btn back" v-if="pageIndex === 1" @click="onReturn()"> 返回 </el-button>
-      <el-button class="btn back" v-else @click="onBack()"> 上一步 </el-button>
-      <el-button class="btn add" style="margin-left: -15px" v-if="pageIndex === 4 || pageIndex === 7" @click="onAdd()"> 增加 </el-button>
-      <el-button class="btn next" type="success" @click="onNext()"> {{ nextBtnText }} </el-button>
     </dv-border-box1>
   </div>
 </template>
 <script setup lang="tsx" name="createTask">
-import { ref, ComputedRef, computed, watch } from 'vue'
+import { ref, ComputedRef, computed, watch, reactive } from 'vue'
 import ProForm from '@/components/ProForm/index.vue'
 import { useRouter } from 'vue-router'
-import { getTransferImgList1, getTransferImgList2 } from '@/api/modules/taais/task'
+import { getModelApi, getAlgorithmApi, createTaskApi } from '@/api/modules/taais/task'
+import ProTable from '@/components/ProTable/index.vue'
+import { ColumnProps, ProTableInstance } from '@/components/ProTable/interface'
+import { listDataApi } from '@/api/modules/demo/data'
+import { ElMessage, ElTree } from 'element-plus'
+import { getDictsApi } from '@/api/modules/system/dictData'
+import type { TabsPaneContext } from 'element-plus'
+// :request-api="getImageApi(1)" getImageApi,, Select, TabsPaneContext
+const activeName = ref('one')
+let tabTwo = ref(true)
+let tabThree = ref(true)
+let tabFour = ref(true)
+let initParam1 = reactive({ type: 1 })
+let initParam2 = reactive({ type: 2 })
+let initParam3 = reactive({ type: 3 })
+let initParam4 = reactive({ type: 4 })
+const proTable = ref<ProTableInstance>()
 let model = ref({
-  enhanceModel: '',
-  pretreatmentModel: ''
+  taskType: '2'
 })
-const router = useRouter()
-let pageIndex = ref<number>(1)
-let title = ref('目标精准捕获任务选择')
-let nextBtnText = ref('下一步')
-const transferImg1 = getTransferImgList1()
-const transferImg2 = getTransferImgList2()
-const enumData = [
-  {
-    label: 'rtdetr',
-    value: '1'
+
+let formItem = reactive({
+  taskName: '',
+  selectTask: [2, 5] as any,
+  trainDataSelect: [] as any[],
+  trainDataEnhancement: {
+    algorithmId: null,
+    params: []
   },
-  {
-    label: 'yolov5',
-    value: '2'
+  trainDataExpansion: {
+    algorithmId: null,
+    modelId: null,
+    params: []
   },
-  {
-    label: 'yolov8',
-    value: '3'
-  }
-]
-const enumDataModel = [
-  {
-    label: 'rtdetrModel',
-    value: '1'
+  train: [{}],
+  testDataSelect: [] as any[],
+  testDataEnhancement: {
+    algorithmId: null,
+    modelId: null,
+    params: []
   },
-  {
-    label: 'yolov5Model',
-    value: '2'
+  testDataExpansion: {
+    algorithmId: null,
+    modelId: null,
+    params: []
   },
-  {
-    label: 'yolov8Model',
-    value: '3'
-  }
-]
+  test: [{}],
+  reasoningDataSelect: [] as any[],
+  reasoningDataEnhancement: {
+    algorithmId: null,
+    modelId: null,
+    params: []
+  },
+  reasoningDataExpansion: {
+    algorithmId: null,
+    modelId: null,
+    params: []
+  },
+  reasoning: [{}]
+})
+let prevTreeData = ref([3])
+const router = useRouter()
+let subSystem, selectTrainAgloId, selectTestAgloId, selectReasoningAgloId
+const trainActiveTab = ref()
+const testActiveTab = ref()
+const reasoningActiveTab = ref()
+let pageIndex = ref<number>(1)
+const selectTaskTreeRef = ref<InstanceType<typeof ElTree>>()
+
+let title = ref('算法任务选择')
+let nextBtnText = ref('下一步')
 const data1 = [
   {
+    id: 98,
     label: '训练',
+    disabled: true,
     children: [
       {
+        id: 2,
         label: '训练数据选择',
         children: []
       },
       {
-        label: '训练数据预处理',
+        id: 3,
+        label: '训练数据增广',
         children: []
       },
       {
+        id: 5,
         label: '训练',
         children: []
       }
     ]
   },
   {
-    label: '推理',
+    id: 99,
+    label: '验证',
+    disabled: true,
     children: [
       {
-        label: '推理数据选择',
+        id: 6,
+        label: '验证数据选择',
         children: []
       },
       {
-        label: '推理数据预处理',
+        id: 9,
+        label: '验证',
+        children: []
+      }
+    ]
+  },
+  {
+    id: 100,
+    label: '测试',
+    disabled: true,
+    children: [
+      {
+        id: 10,
+        label: '测试数据选择',
         children: []
       },
       {
-        label: '推理',
+        id: 13,
+        label: '测试',
         children: []
       }
     ]
   }
 ]
+const taskTypeData = [
+  {
+    label: '单数据多算法',
+    value: '2'
+  },
+  {
+    label: '多数据单算法',
+    value: '1'
+  }
+]
+const dataColumns = reactive<ColumnProps<any>[]>([
+  { type: 'selection', fixed: 'left', width: 70 },
+  {
+    prop: 'name',
+    label: '名称',
+    width: 120
+  },
+  {
+    prop: 'dataType',
+    label: '数据类型',
+    width: 120
+  },
+  {
+    prop: 'fileType',
+    label: '文件类型',
+    width: 120
+  },
+  {
+    prop: 'batchNum',
+    label: '批次号',
+    search: {
+      el: 'input',
+      defaultValue: ''
+    },
+    width: 120
+  },
+  {
+    prop: 'objectType',
+    label: '目标类型',
+    search: {
+      el: 'input',
+      defaultValue: ''
+    },
+    width: 120
+  },
+  {
+    prop: 'objectSubtype',
+    label: '目标子类型',
+    search: {
+      el: 'input',
+      defaultValue: ''
+    },
+    width: 120
+  },
+
+  {
+    prop: 'scene',
+    label: '场景',
+    width: 120
+  },
+  {
+    prop: 'dataSource',
+    label: '数据源',
+    width: 120
+  },
+  {
+    prop: 'gatherTime',
+    label: '采集时间',
+    width: 120
+  },
+  {
+    prop: 'gatherSpot',
+    label: '采集地点',
+    width: 120
+  },
+  {
+    prop: 'increment',
+    label: '扩增方式',
+    width: 120
+  }
+])
 const defaultProps = {
   children: 'children',
   label: 'label'
@@ -134,492 +351,1031 @@ const _options: ComputedRef<ProForm.FormOptions> = computed(() => {
   return Object.assign(form)
 })
 
-let items: ProForm.ItemsOptions[] = [
+let items = reactive<ProForm.ItemsOptions[]>([
+  // 1
   {
-    // formItemOptions: {
     label: '任务名称',
     prop: 'taskName',
     span: 12,
+    rules: [{ required: true, message: '请输入任务名称' }],
     show: () => {
       return pageIndex.value === 1 ? true : false
     },
-    // },
     compOptions: {
       elTagName: 'input',
       clearable: true,
-      placeholder: '请输入任务名称'
+      placeholder: '请输入任务名称',
+      onChange: val => {
+        formItem.taskName = val
+      }
     }
   },
   {
-    // formItemOptions: {
     label: '任务选择',
-    prop: 'treeName',
+    prop: 'selectTask',
     show: () => {
       return pageIndex.value === 1 ? true : false
     },
-    // },
     compOptions: {
-      elTagName: 'tree',
-      enum: data1,
-      props: defaultProps,
-      style: 'max-width: 600px',
-      defaultExpandAll: true,
-      showCheckbox: true
+      elTagName: 'slot'
     }
   },
   {
-    // formItemOptions: {
-    label: '选择训练数据',
-    prop: 'transfer1',
+    label: '任务类型',
+    prop: 'taskType',
     show: () => {
-      return pageIndex.value === 2 ? true : false
+      return pageIndex.value === 1 ? true : false
     },
-    // },
     compOptions: {
-      elTagName: 'slot',
-      filterable: true
+      elTagName: 'radio-group',
+      enum: taskTypeData
     }
   },
   {
-    // formItemOptions: {
-    label: '增强算法',
-    prop: 'enhanceAlgo',
-    span: 14,
+    label: '选择子系统',
+    prop: 'subConfig',
+    span: 12,
+    rules: [{ required: true, message: '请选择子系统' }],
     show: () => {
-      return pageIndex.value === 3 ? true : false
+      return pageIndex.value === 1 ? true : false
     },
-    // },
     compOptions: {
       elTagName: 'select',
-      enum: enumData,
+      labelKey: 'dictLabel',
+      valueKey: 'dictValue',
+      enum: () => getDictsApi('biz_sub_config'),
       onChange: val => {
-        model.value.enhanceModel = val
+        subSystem = val
       }
     }
   },
+  // 2  6  10
   {
-    // formItemOptions: {
-    label: '增强模型',
-    prop: 'enhanceModel',
-    span: 14,
+    label: '',
+    hideLabelSuffix: true,
+    labelWidth: '0px',
+    prop: 'proTable',
     show: () => {
-      return pageIndex.value === 3 ? true : false
+      return pageIndex.value === 2 || pageIndex.value === 6 || pageIndex.value === 10 ? true : false
     },
-    // },
     compOptions: {
-      elTagName: 'select',
-      enum: enumDataModel
+      elTagName: 'slot'
     }
   },
+  // 3
   {
-    // formItemOptions: {
-    label: '参数1',
-    prop: 'threeParameter1',
+    label: '选择增广算法',
+    prop: 'trainEnhanceAlgo',
     span: 14,
+    rules: [{ required: true, message: '选择增广算法' }],
     show: () => {
       return pageIndex.value === 3 ? true : false
     },
-    // },
     compOptions: {
-      elTagName: 'input',
-      clearable: true,
-      placeholder: '请输入...'
-    }
-  },
-  {
-    // formItemOptions: {
-    label: '参数2',
-    prop: 'threeParameter2',
-    span: 14,
-    show: () => {
-      return pageIndex.value === 3 ? true : false
-    },
-    // },
-    compOptions: {
-      elTagName: 'input',
-      clearable: true,
-      placeholder: '请输入...'
+      elTagName: 'select',
+      labelKey: 'algorithmName',
+      valueKey: 'id',
+      enum: null,
+      onChange: val => {
+        formItem.trainDataEnhancement.algorithmId = val
+        // agloChange('trainEnhanceModel', val)
+        // getAgloParams(4, 'trainDataEnhancement', 3, val)
+        getAlgorithmApi(4, subSystem).then(res => {
+          res.data.forEach(item => {
+            if (item.id === val) {
+              const params = eval('(' + item.parameterConfig + ')')
+              formItem['trainDataEnhancement'].params = params
+              addForm(params, 3, 'trainDataEnhancement')
+            }
+          })
+        })
+      }
     }
   },
+  // {
+  //   label: '选择增广模型',
+  //   prop: 'trainEnhanceModel',
+  //   span: 14,
+  //   rules: [{ required: true, message: '选择增广模型' }],
+  //   show: () => {
+  //     return pageIndex.value === 3 ? true : false
+  //   },
+  //   compOptions: {
+  //     elTagName: 'select',
+  //     labelKey: 'modelName',
+  //     valueKey: 'id',
+  //     enum: null,
+  //     onChange: val => {
+  //       getAgloParams(4, 'trainDataEnhancement', 3, val)
+  //     }
+  //   }
+  // },
+  // 4
   {
-    // formItemOptions: {
-    label: '参数3',
-    prop: 'threeParameter3',
+    label: '选择扩充算法',
+    prop: 'trainExpansionAlgo',
     span: 14,
+    rules: [{ required: true, message: '选择扩充算法' }],
     show: () => {
-      return pageIndex.value === 3 ? true : false
+      return pageIndex.value === 4 ? true : false
     },
-    // },
     compOptions: {
-      elTagName: 'input',
-      clearable: true,
-      placeholder: '请输入...'
+      elTagName: 'select',
+      labelKey: 'algorithmName',
+      valueKey: 'id',
+      enum: null,
+      onChange: val => {
+        formItem.trainDataExpansion.algorithmId = val
+        agloChange('trainExpansionModel', val, false)
+      }
     }
   },
   {
-    // formItemOptions: {
-    label: '参数4',
-    prop: 'threeParameter4',
+    label: '选择扩充模型',
+    prop: 'trainExpansionModel',
     span: 14,
+    rules: [{ required: true, message: '选择扩充模型' }],
     show: () => {
-      return pageIndex.value === 3 ? true : false
+      return pageIndex.value === 4 ? true : false
     },
-    // },
     compOptions: {
-      elTagName: 'input',
-      clearable: true,
-      placeholder: '请输入...'
+      elTagName: 'select',
+      labelKey: 'modelName',
+      valueKey: 'id',
+      enum: null,
+      onChange: val => {
+        getAgloParams(5, 'trainDataExpansion', 4, val)
+      }
     }
   },
+  // 5
   {
-    // formItemOptions: {
-    label: '训练算法',
+    label: '选择训练算法',
     prop: 'trainAlgo',
     span: 14,
+    rules: [{ required: true, message: '请选择训练算法' }],
     show: () => {
-      return pageIndex.value === 4 ? true : false
+      return pageIndex.value === 5 ? true : false
     },
-    // },
     compOptions: {
       elTagName: 'select',
-      enum: enumData
+      labelKey: 'algorithmName',
+      valueKey: 'id',
+      enum: null,
+      onChange: val => {
+        selectTrainAgloId = val
+        formItem.train[0]['algorithmId'] = val
+        agloChange('trainModel', val, false)
+      }
     }
   },
   {
-    // formItemOptions: {
-    label: '预训练模型权重文件路径',
-    prop: 'fourParameter1',
-    labelWidth: 180,
+    label: '选择训练模型',
+    prop: 'trainModel',
     span: 14,
+    rules: [{ required: true, message: '请选择训练模型' }],
     show: () => {
-      return pageIndex.value === 4 ? true : false
+      return pageIndex.value === 5 ? true : false
     },
-    // },
     compOptions: {
-      elTagName: 'input',
-      clearable: true,
-      placeholder: '请输入...'
+      elTagName: 'select',
+      labelKey: 'modelName',
+      valueKey: 'id',
+      // enum: () => getModelApi(1),
+      enum: null,
+      onChange: val => {
+        getAlgorithmApi(1, subSystem).then(res => {
+          res.data.forEach(item => {
+            if (item.id === selectTrainAgloId) {
+              const params = eval('(' + item.parameterConfig + ')')
+              formItem.train[0]['modelId'] = val
+              formItem.train[0]['params'] = params
+              // (参数信息,第几页,数组名称)
+              addForm(params, 5, 'train[0]')
+            }
+          })
+        })
+      }
     }
   },
+  // 7
   {
-    // formItemOptions: {
-    label: '模型结构配置文件路径',
-    prop: 'fourParameter2',
-    labelWidth: 180,
+    label: '选择增强算法',
+    prop: 'testEnhanceAlgo',
     span: 14,
+    rules: [{ required: true, message: '选择增强算法' }],
     show: () => {
-      return pageIndex.value === 4 ? true : false
+      return pageIndex.value === 7 ? true : false
     },
-    // },
     compOptions: {
-      elTagName: 'input',
-      clearable: true,
-      placeholder: '请输入...'
+      elTagName: 'select',
+      labelKey: 'algorithmName',
+      valueKey: 'id',
+      enum: null,
+      onChange: val => {
+        formItem.testDataEnhancement['algorithmId'] = val
+        agloChange('testEnhanceModel', val, false)
+      }
     }
   },
   {
-    // formItemOptions: {
-    label: '训练轮数',
-    prop: 'fourParameter3',
-    labelWidth: 180,
+    label: '选择增强模型',
+    prop: 'testEnhanceModel',
     span: 14,
+    rules: [{ required: true, message: '选择增强模型' }],
     show: () => {
-      return pageIndex.value === 4 ? true : false
+      return pageIndex.value === 7 ? true : false
     },
-    // },
     compOptions: {
-      elTagName: 'input',
-      clearable: true,
-      placeholder: '请输入...'
+      elTagName: 'select',
+      labelKey: 'modelName',
+      valueKey: 'id',
+      enum: null,
+      onChange: val => {
+        if (val === 1) {
+          return
+        } else {
+          getAgloParams(4, 'testDataEnhancement', 7, val)
+        }
+      }
     }
   },
+  // 8
   {
-    // formItemOptions: {
-    label: '余弦学习率调度器',
-    prop: 'fourParameter4',
-    labelWidth: 180,
+    label: '选择扩充算法',
+    prop: 'testExpansionAlgo',
     span: 14,
+    rules: [{ required: true, message: '选择扩充算法' }],
     show: () => {
-      return pageIndex.value === 4 ? true : false
-    },
-    // },
-    compOptions: {
-      elTagName: 'input',
-      clearable: true,
-      placeholder: '请输入...'
-    }
-  },
-  {
-    // formItemOptions: {
-    label: '选择推理数据',
-    prop: 'transfer2',
-    show: () => {
-      return pageIndex.value === 5 ? true : false
+      return pageIndex.value === 8 ? true : false
     },
-    // },
     compOptions: {
-      elTagName: 'slot',
-      filterable: true
+      elTagName: 'select',
+      labelKey: 'algorithmName',
+      valueKey: 'id',
+      enum: null,
+      onChange: val => {
+        formItem.testDataExpansion['algorithmId'] = val
+        agloChange('testExpansionModel', val, false)
+      }
     }
   },
   {
-    // formItemOptions: {
-    label: '预处理算法',
-    prop: 'pretreatmentAlgo',
+    label: '选择扩充模型',
+    prop: 'testExpansionModel',
     span: 14,
+    rules: [{ required: true, message: '选择扩充模型' }],
     show: () => {
-      return pageIndex.value === 6 ? true : false
+      return pageIndex.value === 8 ? true : false
     },
-    // },
     compOptions: {
       elTagName: 'select',
-      enum: enumData,
+      labelKey: 'modelName',
+      valueKey: 'id',
+      enum: null,
       onChange: val => {
-        model.value.pretreatmentModel = val
+        if (val === 1) {
+          return
+        } else {
+          getAgloParams(5, 'testDataExpansion', 8, val)
+        }
       }
     }
   },
+  // 9
   {
-    // formItemOptions: {
-    label: '预处理模型',
-    prop: 'pretreatmentModel',
+    label: '选择验证算法',
+    prop: 'testAlgo',
     span: 14,
+    rules: [{ required: true, message: '请选择验证算法' }],
     show: () => {
-      return pageIndex.value === 6 ? true : false
+      return pageIndex.value === 9 ? true : false
     },
-    // },
     compOptions: {
       elTagName: 'select',
-      enum: enumDataModel
-    }
-  },
-  {
-    // formItemOptions: {
-    label: '参数1',
-    prop: 'sixParameter1',
-    span: 12,
-    show: () => {
-      return pageIndex.value === 6 ? true : false
-    },
-    // },
-    compOptions: {
-      elTagName: 'input',
-      clearable: true,
-      placeholder: '请输入...'
-    }
-  },
-  {
-    // formItemOptions: {
-    label: '参数2',
-    prop: 'sixParameter2',
-    span: 12,
-    show: () => {
-      return pageIndex.value === 6 ? true : false
-    },
-    // },
-    compOptions: {
-      elTagName: 'input',
-      clearable: true,
-      placeholder: '请输入...'
+      labelKey: 'algorithmName',
+      valueKey: 'id',
+      enum: null,
+      onChange: val => {
+        selectTestAgloId = val
+        formItem.test[0]['algorithmId'] = val
+        agloChange('testModel', val, true)
+      }
     }
   },
   {
-    // formItemOptions: {
-    label: '参数3',
-    prop: 'sixParameter3',
-    span: 12,
+    label: '选择验证模型',
+    prop: 'testModel',
+    span: 14,
+    rules: [{ required: true, message: '请选择验证模型' }],
     show: () => {
-      return pageIndex.value === 6 ? true : false
+      return pageIndex.value === 9 ? true : false
     },
-    // },
     compOptions: {
-      elTagName: 'input',
-      clearable: true,
-      placeholder: '请输入...'
+      elTagName: 'select',
+      labelKey: 'modelName',
+      valueKey: 'id',
+      enum: null,
+      onChange: val => {
+        // getAgloParams(1, 'test[0]', 9, val, 0)
+        getAlgorithmApi(2, subSystem).then(res => {
+          res.data.forEach(item => {
+            if (item.id === selectTestAgloId) {
+              const params = eval('(' + item.parameterConfig + ')')
+              formItem.test[0]['modelId'] = val
+              formItem.test[0]['params'] = params
+              // (参数信息,第几页,数组名称)
+              addForm(params, 9, 'test[0]')
+            }
+          })
+        })
+      }
     }
   },
+  // 11
   {
-    // formItemOptions: {
-    label: '参数4',
-    prop: 'sixParameter4',
-    span: 12,
+    label: '选择增强算法',
+    prop: 'reasoningEnhanceAlgo',
+    span: 14,
+    rules: [{ required: true, message: '选择增强算法' }],
     show: () => {
-      return pageIndex.value === 6 ? true : false
+      return pageIndex.value === 11 ? true : false
     },
-    // },
     compOptions: {
-      elTagName: 'input',
-      clearable: true,
-      placeholder: '请输入...'
+      elTagName: 'select',
+      labelKey: 'algorithmName',
+      valueKey: 'id',
+      enum: null,
+      onChange: val => {
+        formItem.reasoningDataEnhancement['algorithmId'] = val
+        agloChange('reasoningEnhanceModel', val, false)
+      }
     }
   },
   {
-    // formItemOptions: {
-    label: '推理算法',
-    prop: 'inferAlgo',
+    label: '选择增强模型',
+    prop: 'reasoningEnhanceModel',
     span: 14,
+    rules: [{ required: true, message: '选择增强模型' }],
     show: () => {
-      return pageIndex.value === 7 ? true : false
+      return pageIndex.value === 11 ? true : false
     },
-    // },
     compOptions: {
       elTagName: 'select',
-      enum: enumData
+      labelKey: 'modelName',
+      valueKey: 'id',
+      enum: null,
+      onChange: val => {
+        if (val === 1) {
+          return
+        } else {
+          getAgloParams(4, 'reasoningDataEnhancement', 11, val)
+        }
+      }
     }
   },
+  // 12
   {
-    // formItemOptions: {
-    label: '目标置信度阈值',
-    prop: 'sevenParameter1',
-    labelWidth: 180,
+    label: '选择扩充算法',
+    prop: 'reasoningExpansionAlgo',
     span: 14,
+    rules: [{ required: true, message: '选择扩充算法' }],
     show: () => {
-      return pageIndex.value === 7 ? true : false
+      return pageIndex.value === 12 ? true : false
     },
-    // },
     compOptions: {
-      elTagName: 'input',
-      clearable: true,
-      placeholder: '请输入...'
+      elTagName: 'select',
+      labelKey: 'algorithmName',
+      valueKey: 'id',
+      enum: null,
+      onChange: val => {
+        formItem.reasoningDataExpansion['algorithmId'] = val
+        agloChange('reasoningExpansionModel', val, false)
+      }
     }
   },
   {
-    // formItemOptions: {
-    label: '非极大值抑制的IoU阈值',
-    prop: 'sevenParameter2',
-    labelWidth: 180,
+    label: '选择扩充模型',
+    prop: 'reasoningExpansionModel',
+    rules: [{ required: true, message: '选择扩充模型' }],
     span: 14,
     show: () => {
-      return pageIndex.value === 7 ? true : false
+      return pageIndex.value === 12 ? true : false
     },
-    // },
     compOptions: {
-      elTagName: 'input',
-      clearable: true,
-      placeholder: '请输入...'
+      elTagName: 'select',
+      labelKey: 'modelName',
+      valueKey: 'id',
+      enum: null,
+      onChange: val => {
+        if (val === 1) {
+          return
+        } else {
+          getAgloParams(5, 'reasoningDataExpansion', 12, val)
+        }
+      }
     }
   },
+  // 13
   {
-    // formItemOptions: {
-    label: '测试图片最大检测器数',
-    prop: 'sevenParameter3',
-    labelWidth: 180,
+    label: '选择测试算法',
+    prop: 'reasoningAlgo',
     span: 14,
+    rules: [{ required: true, message: '请选择测试算法' }],
     show: () => {
-      return pageIndex.value === 7 ? true : false
+      return pageIndex.value === 13 ? true : false
     },
-    // },
     compOptions: {
-      elTagName: 'input',
-      clearable: true,
-      placeholder: '请输入...'
+      elTagName: 'select',
+      labelKey: 'algorithmName',
+      valueKey: 'id',
+      enum: null,
+      onChange: val => {
+        selectReasoningAgloId = val
+        formItem.reasoning[0]['algorithmId'] = val
+        agloChange('reasoningModel', val, true)
+      }
     }
   },
   {
-    // formItemOptions: {
-    label: '使用半精度推理(FP16)',
-    prop: 'sevenParameter4',
-    labelWidth: 180,
+    label: '选择测试模型',
+    prop: 'reasoningModel',
     span: 14,
+    rules: [{ required: true, message: '请选择测试模型' }],
     show: () => {
-      return pageIndex.value === 7 ? true : false
+      return pageIndex.value === 13 ? true : false
     },
-    // },
     compOptions: {
-      elTagName: 'input',
-      clearable: true,
-      placeholder: '请输入...'
+      elTagName: 'select',
+      labelKey: 'modelName',
+      valueKey: 'id',
+      enum: null,
+      onChange: val => {
+        getAlgorithmApi(3, subSystem).then(res => {
+          res.data.forEach(item => {
+            if (item.id === selectReasoningAgloId) {
+              const params = eval('(' + item.parameterConfig + ')')
+              formItem.reasoning[0]['modelId'] = val
+              formItem.reasoning[0]['params'] = params
+              // (参数信息,第几页,数组名称)
+              addForm(params, 13, 'reasoning[0]')
+            }
+          })
+        })
+      }
     }
   }
-]
-let formItemsTemp4 = ref([
-  {
-    items,
-    model: model.value
-  }
-])
-let formItemsTemp7 = ref([
-  {
-    items,
-    model: model.value
-  }
 ])
+// let formItemsTemp2 = ref([
+//   {
+//     items,
+//     model: model.value
+//   }
+// ])
+// let formItemsTemp7 = ref([
+//   {
+//     items,
+//     model: model.value
+//   }
+// ])
 let formItems = ref([
   {
     items,
     model: model.value
   }
 ])
+let addTrainAgloIndex = 1
+let addTestAgloIndex = 1
+let addReasoningAgloIndex = 1
+const proFormRef = ref<InstanceType<typeof ProForm> | null>(null)
 // 增加训练算法
-const onAdd = () => {
-  const data = {
-    enhanceModel: '',
-    pretreatmentModel: ''
+const onAdd = pageNum => {
+  let arrayName, agloIndex, type, name
+  switch (pageNum) {
+    case 5:
+      arrayName = 'train'
+      agloIndex = addTrainAgloIndex
+      type = 1
+      name = '训练'
+      break
+    case 9:
+      arrayName = 'test'
+      agloIndex = addTestAgloIndex
+      type = 2
+      name = '验证'
+      break
+    case 13:
+      arrayName = 'reasoning'
+      agloIndex = addReasoningAgloIndex
+      type = 3
+      name = '测试'
+      break
+    default:
+      break
   }
-  formItems.value.push({
-    items,
-    model: data
+  const formEl = proFormRef.value![0].proFormRef
+  if (!formEl) return
+  formEl.validate(valid => {
+    if (valid) {
+      if (agloIndex >= 4) {
+        ElMessage.warning('最多选择四种算法,已选择了四种')
+        return
+      }
+      getAlgorithmApi(type, subSystem).then(res1 => {
+        formItems.value[0].items.push({
+          label: `选择${name}算法`,
+          prop: `${arrayName}Aglo${agloIndex}`,
+          span: 14,
+          rules: [{ required: true, message: `请选择${name}算法` }],
+          show: () => {
+            return pageIndex.value === pageNum ? true : false
+          },
+          compOptions: {
+            elTagName: 'select',
+            labelKey: 'algorithmName',
+            valueKey: 'id',
+            enum: res1.data,
+            onChange: agloId => {
+              formItem[`${arrayName}`].push({})
+              if (!formItem[`${arrayName}`][`${agloIndex}`]['algorithmId']) {
+                formItem[`${arrayName}`][`${agloIndex}`]['algorithmId'] = agloId
+                getModelApi(agloId).then(res2 => {
+                  if (type === 2 || type === 3) {
+                    res2.data.unshift({
+                      algorithmId: null,
+                      id: 1,
+                      modelAddress: null,
+                      modelName: '基于训练生成的模型'
+                    })
+                  }
+                  formItems.value[0].items.push({
+                    label: `选择${name}模型`,
+                    prop: `${arrayName}Model${agloIndex}`,
+                    span: 14,
+                    rules: [{ required: true, message: `请选择${name}模型` }],
+                    show: () => {
+                      return pageIndex.value === pageNum ? true : false
+                    },
+                    compOptions: {
+                      elTagName: 'select',
+                      labelKey: 'modelName',
+                      valueKey: 'id',
+                      enum: res2.data,
+                      onChange: modelId => {
+                        res1.data.forEach(agloItem => {
+                          if (agloItem.id === agloId) {
+                            const params = eval('(' + agloItem.parameterConfig + ')')
+                            formItem[`${arrayName}`][`${agloIndex}`]['modelId'] = modelId
+                            formItem[`${arrayName}`][`${agloIndex}`]['params'] = params
+                            addForm(params, pageNum, `${arrayName}[${agloIndex}]`)
+                          }
+                        })
+                      }
+                    }
+                  })
+                })
+              } else {
+                formItem[`${arrayName}`].splice(-1, 1)
+                formItem[`${arrayName}`][`${agloIndex}`]['algorithmId'] = agloId
+                const column = formItems.value[0].items.find(column => column.prop === `${arrayName}Model${agloIndex}`)
+                if (column) {
+                  getModelApi(agloId).then(newRes => {
+                    column.compOptions.enum = newRes.data
+                  })
+                }
+              }
+            }
+          }
+        })
+      })
+      if (pageNum === 5) addTrainAgloIndex++
+      if (pageNum === 9) addTestAgloIndex++
+      if (pageNum === 13) addReasoningAgloIndex++
+    }
   })
 }
-const getImageUrl = name => {
-  return new URL(`../../../assets/taaisImg/${name}`, import.meta.url).href
+// 增加新数据
+const addNewData = () => {
+  switch (activeName.value) {
+    case 'one':
+      const table0Ref = proTable.value![0]
+      if (table0Ref.tableData.length === 0) {
+        ElMessage.warning('请正确选择该组数据')
+      } else {
+        tabTwo.value = false
+        activeName.value = 'two'
+      }
+      break
+    case 'two':
+      const table1Ref = proTable.value![1]
+      if (table1Ref.tableData.length === 0) {
+        ElMessage.warning('请正确选择该组数据')
+      } else {
+        tabThree.value = false
+        activeName.value = 'three'
+      }
+      break
+    case 'three':
+      const table2Ref = proTable.value![2]
+      if (table2Ref.tableData.length === 0) {
+        ElMessage.warning('请正确选择该组数据')
+      } else {
+        tabFour.value = false
+        activeName.value = 'four'
+      }
+      break
+    default:
+      break
+  }
+}
+// 增加表单事件
+const addForm = (params, index, arrayName) => {
+  params.forEach(item => {
+    let i = formItems.value[0].items.length
+    formItems.value[0].items.push({
+      label: item.name,
+      prop: `task${i}`,
+      span: 12,
+      rules: [
+        { required: item.required, message: `${item.name}不能为空` },
+        { pattern: new RegExp(`${item.validate}`), message: item.prompt }
+      ],
+      show: () => {
+        return pageIndex.value === index ? true : false
+      },
+      compOptions: {
+        elTagName: 'input',
+        clearable: true,
+        placeholder: item.prompt,
+        onChange: val1 => {
+          let label = item.name
+          if (arrayName.includes(']')) {
+            // 截取数组和下标
+            let array = arrayName.slice(0, -3)
+            let index = arrayName.slice(-2, -1)
+            const item = formItem[`${array}`][`${index}`]['params'].find(item => item.name === label)
+            if (item) {
+              item.value = val1
+            }
+          } else {
+            const item1 = formItem[`${arrayName}`]['params'].find(item => item.name === label)
+            if (item1) {
+              item1.value = val1
+            }
+          }
+        }
+      }
+    })
+    formItems.value[0].model[`task${i}`] = item.defaultValue
+  })
+}
+const agloChange = (propName, agloId, flag) => {
+  const Column = formItems.value[0].items.find(column => column.prop === propName)
+  if (Column) {
+    getModelApi(agloId).then(res => {
+      Column.compOptions.enum = res.data as any[]
+      if (flag) {
+        Column.compOptions.enum.unshift({
+          algorithmId: null,
+          id: 1,
+          modelAddress: null,
+          modelName: '基于训练生成的模型'
+        })
+      }
+    })
+  }
+}
+const getAlgo = (propName, type) => {
+  const column = formItems.value[0].items.find(column => column.prop === propName)
+  if (column) {
+    getAlgorithmApi(type, subSystem).then(res => {
+      column.compOptions.enum = res.data as any[]
+    })
+  }
+}
+// 算法类型:1-5、算法类型名称:如训练数据增强、页码、模型Id、模型的参数下标
+const getAgloParams = (agloType, agloTypeName, page, modelId) => {
+  const algoId = formItem[agloTypeName].algorithmId
+  getAlgorithmApi(agloType, subSystem).then(res => {
+    res.data.forEach(item => {
+      if (item.id === algoId) {
+        const params = eval('(' + item.parameterConfig + ')')
+        formItem[agloTypeName].modelId = modelId
+        formItem[agloTypeName].params = params
+        // (参数信息,第几页,数组名称)
+        addForm(params, page, agloTypeName)
+      }
+    })
+  })
 }
+// 返回按钮
 const onReturn = () => {
   router.push(`/index`)
 }
 let flag = ref<number>(0) //跳转到日志页面的flag,0为训练日志、1为推理日志
+// 下一步
 const onNext = () => {
-  if (pageIndex.value === 7) {
-    router.push({ path: `/logPage/${flag.value}`, query: { type: 1 } })
+  const formEl = proFormRef.value![0].proFormRef
+  if (!formEl) return
+  formEl.validate(valid => {
+    if (valid) {
+      if (formItem.selectTask.length === 0 && pageIndex.value === 1) {
+        ElMessage.warning('请选择任务')
+        return
+      }
+      if (pageIndex.value === 2 || pageIndex.value === 6 || pageIndex.value === 10) {
+        let dataName, flag
+        if (pageIndex.value === 2) dataName = 'trainDataSelect'
+        else if (pageIndex.value === 6) dataName = 'testDataSelect'
+        else if (pageIndex.value === 10) dataName = 'reasoningDataSelect'
+        switch (activeName.value) {
+          case 'one':
+            flag = 0
+            break
+          case 'two':
+            flag = 1
+            break
+          case 'three':
+            flag = 2
+            break
+          case 'false':
+            flag = 3
+            break
+          default:
+            break
+        }
+        formItem[dataName] = []
+        for (let i = 0; i <= flag; i++) {
+          if (proTable.value![i].tableData.length === 0) {
+            ElMessage.warning('数据存在空集,请正确选择数据')
+            return
+          }
+          let obj = proTable.value![i].searchParam
+          for (let key in obj) {
+            if (obj.hasOwnProperty(key) && obj[key] === '') {
+              delete obj[key]
+            }
+          }
+          formItem[dataName].push({
+            conditionSelected: true,
+            condition: proTable.value![i].searchParam
+          })
+        }
+        activeName.value = 'one'
+        tabTwo.value = true
+        tabThree.value = true
+        tabFour.value = true
+      }
+      if (pageIndex.value === formItem.selectTask[formItem.selectTask.length - 2]) {
+        nextBtnText.value = '提交'
+      }
+      if (pageIndex.value === formItem.selectTask[formItem.selectTask.length - 1]) {
+        console.log('flag.value', flag.value)
+        return
+        // router.push({ path: `/logPage/${flag.value}`, query: { type: 1 } })
+      }
+
+      pageIndex.value = formItem.selectTask[formItem.selectTask.findIndex(page => page === pageIndex.value) + 1]
+    }
+  })
+}
+// 上一步
+const onBack = () => {
+  nextBtnText.value = '下一步'
+  if (pageIndex.value === formItem.selectTask[0]) {
+    pageIndex.value = 1
+    return
+  }
+  pageIndex.value = formItem.selectTask[formItem.selectTask.findIndex(page => page === pageIndex.value) - 1]
+}
+const changeTree = (newVal, allVal) => {
+  const newId = newVal.id
+  const dependencyMap = new Map([
+    [
+      [3, 4, 2, 5],
+      [2, 5]
+    ], // 如果包含3或4,则添加2和5
+    [
+      [7, 8, 6, 9],
+      [6, 9]
+    ],
+    [
+      [11, 12, 10, 13],
+      [10, 13]
+    ]
+  ])
+  const updateCheckedKeys = keysSet => {
+    prevTreeData.value = Array.from(keysSet)
+    selectTaskTreeRef.value![0].setCheckedKeys(Array.from(keysSet), false)
+  }
+
+  if (!allVal.checkedKeys.includes(newId)) {
+    if (newId === 2 || newId === 5) {
+      const data = delNumber(2, 5, allVal.checkedKeys)
+      updateCheckedKeys(new Set(data))
+    } else if (newId === 6 || newId === 9) {
+      const data = delNumber(6, 9, allVal.checkedKeys)
+      updateCheckedKeys(new Set(data))
+    } else if (newId === 10 || newId === 13) {
+      const data = delNumber(10, 13, allVal.checkedKeys)
+      updateCheckedKeys(new Set(data))
+    }
   } else {
-    pageIndex.value++
+    for (const [keysToCheck, keysToAdd] of dependencyMap.entries()) {
+      if (keysToCheck.includes(newId)) {
+        const keysSet = new Set([...allVal.checkedKeys, ...keysToAdd])
+        updateCheckedKeys(keysSet)
+        break
+      }
+    }
   }
+
+  formItem.selectTask = selectTaskTreeRef.value![0].getCheckedKeys().filter(item => item < 90)
 }
-const onBack = () => {
-  if (pageIndex.value === 1) return
-  pageIndex.value--
+// 树组件去除节点函数
+const delNumber = (start, end, dataList) => {
+  return dataList.filter(number => !(number >= start && number <= end)).sort((a, b) => a - b)
 }
-watch(
-  () => pageIndex.value,
-  (value, oldValue) => {
-    if (oldValue === 4) formItemsTemp4.value = formItems.value
-    if (oldValue === 7) formItemsTemp7.value = formItems.value
-    if (value === 4) formItems.value = formItemsTemp4.value
-    if (value === 7) formItems.value = formItemsTemp7.value
-    else {
-      formItems.value = [
-        {
-          items,
-          model: model.value
+const onSubmit = () => {
+  findParams(formItem)
+  createTaskApi(formItem).then(res => {
+    console.log('createTask', res)
+    // const taskId=res
+    router.push({ path: `/task/subtask/`, query: { id: res.data } })
+  })
+}
+const findParams = obj => {
+  for (const key in obj) {
+    if (obj[key] !== null && typeof obj[key] === 'object') {
+      // 如果值是数组,则遍历数组中的每个元素
+      if (Array.isArray(obj[key])) {
+        obj[key].forEach(item => {
+          if (item.params) {
+            item.params.forEach(paramItem => {
+              if (!paramItem.value) {
+                paramItem.value = paramItem.defaultValue
+              }
+            })
+            item.params = JSON.stringify(item.params)
+          }
+          if (item.condition) {
+            item.condition = JSON.stringify(item.condition)
+          }
+        })
+      } else {
+        // 如果值是对象
+        if (obj[key]['params']) {
+          obj[key]['params'].forEach(paramItem => {
+            if (!paramItem.value) {
+              paramItem.value = paramItem.defaultValue
+            }
+          })
+          obj[key]['params'] = JSON.stringify(obj[key]['params'])
         }
-      ]
+        if (obj[key]['condition']) {
+          obj[key]['condition'] = JSON.stringify(obj[key]['condition'])
+        }
+      }
     }
-    0
+  }
+}
+const beforeTabLeave = (activeName, oldActiveName) => {
+  let dataSelect1
+  if (pageIndex.value === 2) {
+    dataSelect1 = 'trainDataSelect'
+  } else if (pageIndex.value === 6) {
+    dataSelect1 = 'testDataSelect'
+  } else if (pageIndex.value === 10) {
+    dataSelect1 = 'reasoningDataSelect'
+  }
 
+  switch (oldActiveName) {
+    case 'one':
+      Object.assign(initParam1, formItem[dataSelect1]?.[0]?.condition)
+      break
+    case 'two':
+      Object.assign(initParam2, formItem[dataSelect1]?.[1]?.condition)
+      break
+    case 'three':
+      Object.assign(initParam3, formItem[dataSelect1]?.[2]?.condition)
+      break
+    case 'four':
+      Object.assign(initParam4, formItem[dataSelect1]?.[3]?.condition)
+      break
+    default:
+      break
+  }
+}
+const handleClick = (tab: TabsPaneContext) => {
+  let dataSelect
+  if (pageIndex.value === 2) {
+    dataSelect = 'trainDataSelect'
+    trainActiveTab.value = tab
+  } else if (pageIndex.value === 6) {
+    dataSelect = 'testDataSelect'
+    testActiveTab.value = tab
+  } else if (pageIndex.value === 10) {
+    dataSelect = 'reasoningDataSelect'
+    reasoningActiveTab.value = tab
+  }
+  const tabName = tab.paneName
+  switch (tabName) {
+    case 'one':
+      const data1 = formItem[dataSelect]?.[0]?.condition
+      console.log('data1', data1)
+      updateDefaultValue(data1?.objectType, data1?.objectSubtype, data1?.batchNum)
+      break
+    case 'two':
+      const data2 = formItem[dataSelect]?.[1]?.condition
+      console.log('data2', data2)
+      updateDefaultValue(data2?.objectType, data2?.objectSubtype, data2?.batchNum)
+      break
+    case 'three':
+      const data3 = formItem[dataSelect]?.[2]?.condition
+      console.log('data3', data3)
+      updateDefaultValue(data3?.objectType, data3?.objectSubtype, data3?.batchNum)
+      break
+    case 'four':
+      const data4 = formItem[dataSelect]?.[3]?.condition
+      updateDefaultValue(data4?.objectType, data4?.objectSubtype, data4?.batchNum)
+      break
+    default:
+      break
+  }
+}
+const updateDefaultValue = (objectType, objectSubtype, batchNum) => {
+  dataColumns.map(column => {
+    if (column.prop === 'objectType') {
+      column.search!.defaultValue = objectType
+    } else if (column.prop === 'objectSubtype') {
+      column.search!.defaultValue = objectSubtype
+    } else if (column.prop === 'batchNum') {
+      column.search!.defaultValue = batchNum
+    }
+  })
+}
+watch(
+  () => pageIndex.value,
+  value => {
     switch (value) {
       case 1:
-        title.value = '任务创建:目标精准捕获任务选择'
+        title.value = '任务创建:算法任务选择'
         nextBtnText.value = '下一步'
         break
       case 2:
-        title.value = '任务创建:训练数据选择'
+        title.value = '训练数据选择'
+        if (trainActiveTab.value) {
+          handleClick(trainActiveTab.value)
+        }
         break
       case 3:
-        title.value = '任务创建:训练数据预处理'
+        title.value = '训练数据增广'
+        getAlgo('trainEnhanceAlgo', 4)
         break
       case 4:
-        title.value = '任务创建:训练参数设置'
+        title.value = '训练数据扩充'
+        getAlgo('trainExpansionAlgo', 5)
         break
       case 5:
-        title.value = '任务创建:推理数据选择'
+        title.value = '训练算法选择'
+        getAlgo('trainAlgo', 1)
         break
       case 6:
-        title.value = '任务创建:推理数据预处理'
-        nextBtnText.value = '下一步'
+        title.value = '验证数据选择'
+        if (testActiveTab.value) {
+          handleClick(testActiveTab.value)
+        }
         break
       case 7:
-        title.value = '任务创建:推理参数设置'
-        nextBtnText.value = '提交'
+        title.value = '测试数据增强'
+        getAlgo('testEnhanceAlgo', 4)
+        break
+      case 8:
+        title.value = '测试数据扩充'
+        getAlgo('testExpansionAlgo', 5)
+        break
+      case 9:
+        title.value = '验证算法选择'
+        getAlgo('testAlgo', 2)
+        break
+      case 10:
+        title.value = '测试数据选择'
+        if (reasoningActiveTab.value) {
+          handleClick(reasoningActiveTab.value)
+        }
+        break
+      case 11:
+        title.value = '推理数据增强'
+        getAlgo('reasoningEnhanceAlgo', 4)
+        break
+      case 12:
+        title.value = '推理数据扩充'
+        getAlgo('reasoningExpansionAlgo', 5)
+        nextBtnText.value = '下一步'
+        break
+      case 13:
+        title.value = '测试算法选择'
+        getAlgo('reasoningAlgo', 3)
         break
       default:
         break

+ 44 - 25
src/views/taais/homePage/index.scss

@@ -6,15 +6,19 @@
     padding: 60px 65px 60px 85px;
   }
 }
-:deep(.card) {
-  width: 100%;
-  height: 100%;
-  background-image: url('../../../assets/taaisImg/53bg.png');
-  background-repeat: no-repeat;
-  background-size: 100% 100%;
-
-  // color: black;
+:deep(::-webkit-scrollbar) {
+  display: none;
 }
+
+// :deep(.card) {
+//   width: 100%;
+//   height: 100%;
+//   background-image: url('../../../assets/taaisImg/53bg.png');
+//   background-repeat: no-repeat;
+//   background-size: 100% 100%;
+
+//   // color: black;
+// }
 :deep(.el-table) {
   // --el-table-border-color: transparent;
   --el-table-border-color: #bdbdbe7b;
@@ -49,10 +53,11 @@
   .title2 {
     text-align: center;
   }
-  .btn {
-    position: absolute;
-    bottom: 20px;
-  }
+
+  // .btn {
+  //   position: absolute;
+  //   bottom: 20px;
+  // }
   .back {
     left: 100px;
   }
@@ -64,38 +69,53 @@
   }
 }
 %box-basic {
-  width: 70%;
-  height: 700px;
+  width: 90%;
   padding: 20px;
   margin: 0 auto;
 }
 .createTask-container {
   position: relative;
-  width: 70%;
-  height: 520px;
+  width: 90%;
+  height: 85%;
   padding: 20px;
   margin: 0 auto;
-  margin-top: 100px;
+  margin-top: 1%;
   overflow: hidden;
-  overflow-y: scroll;
+  .footBtn {
+    position: fixed;
+    bottom: 4%;
+    left: 10%;
+    display: flex;
+    justify-content: space-evenly;
+    width: 86%;
+  }
+  .createTask-main {
+    height: 100%;
+    overflow: hidden;
+    overflow-y: scroll;
+  }
 }
 .logPage-container {
   @extend %box-basic;
 
   position: relative;
   width: 90%;
-  margin-top: 50px;
   .btn {
-    margin-top: 10px;
-    margin-left: 100px;
+    margin-top: 20px;
+
+    // margin-left: 100px;
+  }
+  .prev {
+    position: absolute;
+    left: 150px;
   }
   .next {
     position: absolute;
-    right: 120px;
+    right: 150px;
   }
   .log {
     width: 90%;
-    height: 550px; /* 根据需要调整 */
+    height: 65vh; /* 根据需要调整 */
     padding: 10px;
 
     // padding-bottom: 80px;
@@ -119,11 +139,10 @@
 
   width: 90%;
   padding: 3px 20px;
-  margin-top: 50px;
   .table {
     position: relative;
     width: 100%;
-    height: 600px;
+    height: 70vh;
     margin-top: -15px;
     .btn {
       margin-top: 10px;

+ 26 - 38
src/views/taais/homePage/index.vue

@@ -2,27 +2,31 @@
   <div class="home-container">
     <dv-border-box1 ref="borderRef" style="width: 100%; height: 100%; margin: 0 auto">
       <div class="table-box">
-        <ProTable
+        <ProTable ref="proTable" :columns="columns" row-key="id" :request-api="listTaskApi" :tool-button="false">
+          <template #tableHeader="">
+            <el-button type="primary" v-auth="['system:user:add']" :icon="CirclePlus" @click="createTask()"> 创建任务 </el-button>
+          </template>
+          <!-- 表格操作 -->
+          <template #operation="scope">
+            <el-button type="primary" link icon="View" v-auth="['task:task:query']" @click="viewDetails(scope.row)"> 查看详情 </el-button>
+            <el-button type="primary" link :icon="View" @click="openDialog(3, '任务查看', scope.row)">查看</el-button>
+          </template>
+        </ProTable>
+        <!-- <ProTable
           ref="proTable"
-          row-key="userId"
-          :data="taskDataList.data"
-          :indent="20"
+          row-key="id"
           :columns="columns"
-          :data-callback="dataCallback"
+          :request-api="listTaskApi"
           :request-auto="false"
-          :init-param="initParam"
           :tool-button="false"
-          :search-col="{ xs: 1, sm: 1, md: 2, lg: 3, xl: 3 }"
         >
-          <!-- 表格 header 按钮 -->
           <template #tableHeader="">
             <el-button type="primary" v-auth="['system:user:add']" :icon="CirclePlus" @click="createTask()"> 创建任务 </el-button>
           </template>
-          <!-- 表格操作 -->
           <template #operation="scope">
             <el-button type="primary" link :icon="View" @click="openDialog(3, '任务查看', scope.row)">查看</el-button>
           </template>
-        </ProTable>
+        </ProTable> -->
       </div>
     </dv-border-box1>
   </div>
@@ -37,8 +41,10 @@ import { CirclePlus, View } from '@element-plus/icons-vue'
 import { useRouter } from 'vue-router'
 import { ColumnProps, ProTableInstance } from '@/components/ProTable/interface'
 import { addUserApi, updateUserApi, deptTreeSelectApi } from '@/api/modules/system/user'
-import { getTaskApi } from '@/api/modules/taais/task'
-import taskDataList from '@/assets/mock/taskData.json'
+// import { getTaskApi } from '@/api/modules/taais/task'
+import { listTaskApi, getTaskApi } from '@/api/modules/task/task'
+import { getDictsApi } from '@/api/modules/system/dictData'
+// import taskDataList from '@/assets/mock/taskData.json'
 // import { getDictsApi } from '@/api/modules/system/dictData'
 onMounted(() => {
   getTreeFilter()
@@ -57,18 +63,15 @@ const getTreeFilter = async () => {
   treeFilterData.value = data
   initParam.deptId = treeFilterData.value[0].id
 }
-const dataCallback = (data: any) => {
-  return data
+// 查看详情
+const viewDetails = row => {
+  router.push({ path: `/task/subtask/`, query: { id: row.id } })
 }
 // 批量添加用户
 const formDialogRef = ref<InstanceType<typeof FormDialog> | null>(null)
 // 打开弹框的功能
 const openDialog = async (type: number, title: string, row?: any) => {
   let res = getTaskApi(row?.taskId || null)
-  console.log('res', res)
-
-  // postOptions.value = res.data.posts
-  // roleOptions.value = res.data.roles
   // 表单项配置
   const fieldList: Form.FieldItem[] = [
     {
@@ -96,31 +99,16 @@ const router = useRouter()
 const createTask = () => {
   router.push(`/createTask`)
 }
-// 跳转详情页
-// const toDetail = (row: { tableId: any }) => {
-//   router.push(`/tool/tool-edit/index/${row.tableId}`)
-// }
-// const getTaskApi
 // 表格配置项
 const columns = reactive<ColumnProps<User.ResUserList>[]>([
   // { type: 'selection', fixed: 'left', width: 70 },
-  { prop: 'taskName', label: '任务名称' },
+  { prop: 'name', label: '任务名称' },
   {
     prop: 'status',
-    label: '用户状态'
-    // enum: () => getDictsApi('sys_normal_disable'),
-    // fieldNames: { label: 'dictLabel', value: 'dictValue' },
-    // render: scope => {
-    //   return (
-    //     <el-switch
-    //       model-value={scope.row.status}
-    //       active-text={scope.row.status === '1' ? '禁用' : '启用'}
-    //       active-value={'0'}
-    //       inactive-value={'1'}
-    //       onClick={() => changeStatus(scope.row)}
-    //     />
-    //   )
-    // }
+    label: '任务状态',
+    tag: true,
+    enum: () => getDictsApi('biz_task_status'),
+    fieldNames: { label: 'dictLabel', value: 'dictValue' }
   },
   { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
 ])

+ 1 - 1
src/views/taais/homePage/inferResult.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="bigBox">
-    <dv-border-box1 ref="borderRef" style="width: 1200px; height: 730px; margin: 0 auto">
+    <dv-border-box1 ref="borderRef" style="width: 80%; height: 100%; margin: 0 auto">
       <div class="trainResult-container">
         <h4>推理结果</h4>
         <div class="table">

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

@@ -1,6 +1,6 @@
 <template>
   <div class="bigBox">
-    <dv-border-box1 ref="borderRef" style="width: 1200px; height: 700px; margin: 0 auto">
+    <dv-border-box1 ref="borderRef" style="width: 80%; height: 100%; margin: 0 auto">
       <div class="logPage-container">
         <el-divider content-position="left">
           <span style="font-size: 18px; font-weight: 700">{{ title }}</span>
@@ -8,7 +8,7 @@
         <div class="log">
           <div class="p" v-for="(item, index) in logInfo" :key="index">{{ item }}</div>
         </div>
-        <el-button class="btn" @click="goTrainResult()"> 上一步 </el-button>
+        <el-button class="btn prev" @click="goTrainResult()"> 上一步 </el-button>
         <el-button type="primary" v-if="over" class="btn next" @click="onResult()"> 查看结果 </el-button>
       </div>
     </dv-border-box1>

+ 576 - 0
src/views/task/bizProcess/index.vue

@@ -0,0 +1,576 @@
+<template>
+  <div class="table-box">
+    <ProTable ref="proTable" :columns="columns" row-key="id" :data="bizProcessList">
+      <!-- 表格 header 按钮 -->
+      <template #tableHeader="scope">
+        <!-- <el-button type="primary" v-auth="['task:bizProcess:add']" icon="CirclePlus" @click="openDialog(1, '算法业务处理新增')"> 新增 </el-button>
+        <el-button type="primary" v-auth="['task:bizProcess:import']" icon="Upload" plain @click="batchAdd"> 导入 </el-button> -->
+        <el-button type="primary" v-auth="['task:bizProcess:export']" icon="Download" plain @click="downloadFile"> 导出 </el-button>
+        <el-button
+          type="danger"
+          v-auth="['task:bizProcess:remove']"
+          icon="Delete"
+          plain
+          :disabled="!scope.isSelected"
+          @click="batchDelete(scope.selectedListIds)"
+        >
+          批量删除
+        </el-button>
+        <el-button type="primary" v-auth="['task:bizProcess:add']" icon="View" @click="contrastResults()"> 对比结果 </el-button>
+      </template>
+      <!-- 表格操作 -->
+      <template #operation="scope">
+        <el-button type="primary" link icon="View" v-auth="['task:bizProcess:query']" @click="openDialog(3, '算法业务处理查看', scope.row)">
+          查看
+        </el-button>
+        <el-button type="primary" link icon="EditPen" v-auth="['task:bizProcess:edit']" @click="openDialog(2, '算法业务处理编辑', scope.row)">
+          编辑
+        </el-button>
+        <el-button type="primary" link icon="Delete" v-auth="['task:bizProcess:remove']" @click="deleteBizProcess(scope.row)"> 删除 </el-button>
+        <el-button type="primary" link icon="View" v-auth="['task:bizProcess:query']" @click="viewLog(scope.row)"> 查看日志 </el-button>
+      </template>
+    </ProTable>
+    <FormDialog ref="formDialogRef" />
+    <ImportExcel ref="dialogRef" />
+    <el-dialog v-model="dialogVisible" title="日志" width="70%">
+      <div class="log" ref="logRef">
+        <div class="p" v-for="(item, index) in logInfo" :key="index">{{ item }}</div>
+      </div>
+    </el-dialog>
+    <el-dialog v-model="resultVisible" title="对比结果" width="70%">
+      <div v-if="!resultsFlag" class="resultShow">
+        <el-row class="headerRow">
+          <el-col class="col" :span="spanNum" v-for="(agloName, index) in resultsData['agNameList']" :key="index">
+            <span>{{ agloName }}</span>
+          </el-col>
+        </el-row>
+        <el-row class="row">
+          <el-col class="col" :span="spanNum" v-for="(RCurveUrl, index) in resultsData['rcureList']" :key="index">
+            <div v-if="index === 0" :span="4" class="oneCol">{{ RCurveUrl }}</div>
+            <ImagePreview
+              class="img"
+              v-else
+              :width="100"
+              :height="100"
+              :src="'/api/profile' + RCurveUrl"
+              :preview-src-list="['/api/profile' + RCurveUrl]"
+            />
+          </el-col>
+        </el-row>
+        <el-row class="row">
+          <el-col class="col" :span="spanNum" v-for="(PCurveUrl, index) in resultsData['pcureList']" :key="index">
+            <div v-if="index === 0" class="oneCol">{{ PCurveUrl }}</div>
+            <ImagePreview
+              class="img"
+              v-else
+              :width="100"
+              :height="100"
+              :src="'/api/profile' + PCurveUrl"
+              :preview-src-list="['/api/profile' + PCurveUrl]"
+            />
+          </el-col>
+        </el-row>
+        <el-row class="row">
+          <el-col class="col" :span="spanNum" v-for="(F1CurveUrl, index) in resultsData['f1cureList']" :key="index">
+            <div v-if="index === 0" class="oneCol">{{ F1CurveUrl }}</div>
+            <ImagePreview
+              class="img"
+              v-else
+              :width="100"
+              :height="100"
+              :src="'/api/profile' + F1CurveUrl"
+              :preview-src-list="['/api/profile' + F1CurveUrl]"
+            />
+          </el-col>
+        </el-row>
+      </div>
+      <div v-if="resultsFlag" class="resultShow">
+        <el-row class="headerRow">
+          <el-col class="col" :span="spanNum" v-for="(agloName, index) in testResultsData['agNameList']" :key="index">
+            <span>{{ agloName }}</span>
+          </el-col>
+        </el-row>
+        <el-row class="row" v-for="(item, index) in testResultsData['resultList']" :key="index">
+          <el-col class="col" :span="spanNum" v-for="(url, index1) in item" :key="index1">
+            <!-- <span>{{ url }}</span> -->
+            <ImagePreview class="img" :width="100" :height="100" :src="'/api/profile' + url" :preview-src-list="['/api/profile' + url]" />
+          </el-col>
+        </el-row>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="tsx" name="BizProcess">
+import { ref, reactive, onMounted, onUnmounted, watch, nextTick } from 'vue'
+import { useHandleData } from '@/hooks/useHandleData'
+import { useDownload } from '@/hooks/useDownload'
+import { ElMessageBox, ElMessage } from 'element-plus'
+import ProTable from '@/components/ProTable/index.vue'
+import ImportExcel from '@/components/ImportExcel/index.vue'
+import FormDialog from '@/components/FormDialog/index.vue'
+import { ProTableInstance, ColumnProps } from '@/components/ProTable/interface'
+import {
+  listBizProcessApi,
+  delBizProcessApi,
+  addBizProcessApi,
+  updateBizProcessApi,
+  exportBizProcessApi,
+  getBizProcessApi,
+  getTrainResultApi,
+  getVerifyResultApi,
+  getTestResultApi
+} from '@/api/modules/task/bizProcess'
+// getTrainResultApi,getVerifyResultApi,getTestResultApi
+import { getSubtaskApi } from '@/api/modules/task/subtask'
+import { getDictsApi } from '@/api/modules/system/dictData'
+import { useRoute } from 'vue-router'
+import ImagePreview from '@/components/ImagePreview/index.vue'
+const route = useRoute()
+const subTaskId = route.query.id as string
+// ProTable 实例
+const proTable = ref<ProTableInstance>()
+const dialogVisible = ref(false)
+const resultVisible = ref(false)
+let resultsData = ref({})
+let testResultsData = ref({})
+let resultsFlag = ref(false)
+let spanNum = ref<number>(4)
+// let logList = ref()
+const logRef = ref<HTMLElement | null>(null) // 显式声明 logRef 的类型;
+let logInfo = ref([] as any[])
+let taskType = ref()
+let taskStatus = ref()
+
+let bizProcessList = ref()
+// 每隔10秒请求一下列表
+const timer = ref() // 定时器
+const refreshList = () => {
+  setTimeout(() => {
+    listBizProcessApi({
+      pageNum: 1,
+      pageSize: 100,
+      subTaskId
+    }).then(res => {
+      bizProcessList.value = res.data['list'].sort((a, b) => b.index - a.index)
+    })
+  }, 0)
+}
+onMounted(() => {
+  getSubtaskApi(subTaskId).then(res => {
+    taskType.value = res.data.type
+    taskStatus.value = res.data.status
+  })
+  refreshList()
+  timer.value = setInterval(() => {
+    refreshList()
+  }, 10000)
+  // 组件挂载后,logRef 将指向实际的 DOM 元素
+  if (logRef.value) {
+    // 操作 logRef 对应的 DOM 元素
+    logRef.value.scrollTop = logRef.value.scrollHeight
+  }
+})
+// 删除算法业务处理信息
+const deleteBizProcess = async (params: any) => {
+  await useHandleData(delBizProcessApi, params.id, '删除【' + params.id + '】算法业务处理')
+  proTable.value?.getTableList()
+}
+
+// 批量删除算法业务处理信息
+const batchDelete = async (ids: string[]) => {
+  await useHandleData(delBizProcessApi, ids, '删除所选算法业务处理信息')
+  proTable.value?.clearSelection()
+  proTable.value?.getTableList()
+}
+
+// 导出算法业务处理列表
+const downloadFile = async () => {
+  ElMessageBox.confirm('确认导出算法业务处理数据?', '温馨提示', { type: 'warning' }).then(() =>
+    useDownload(exportBizProcessApi, '算法业务处理列表', proTable.value?.searchParam)
+  )
+}
+
+// 批量添加算法业务处理
+const dialogRef = ref<InstanceType<typeof ImportExcel> | null>(null)
+// const batchAdd = () => {
+//   const params = {
+//     title: '算法业务处理',
+//     tempApi: importTemplateApi,
+//     importApi: importBizProcessDataApi,
+//     getTableList: proTable.value?.getTableList
+//   }
+//   dialogRef.value?.acceptParams(params)
+// }
+
+// 对比结果
+const contrastResults = () => {
+  const statusFlag = bizProcessList.value.every(item => {
+    return item.status == '2'
+  })
+  if (statusFlag) {
+    switch (taskType.value) {
+      case '1':
+        getTrainResultApi(subTaskId).then(res => {
+          resultsFlag.value = false
+          handleResultData(res.data)
+          resultVisible.value = true
+        })
+        break
+      case '2':
+        getVerifyResultApi(subTaskId).then(res => {
+          resultsFlag.value = false
+          handleResultData(res.data)
+          resultVisible.value = true
+        })
+        break
+      case '3':
+        getTestResultApi(subTaskId).then(res => {
+          console.log('333', res)
+          resultsFlag.value = true
+          testResultsData.value = res.data as any
+          const num = testResultsData.value['agNameList'].length
+          spanNum.value = 24 / num <= 4 ? 4 : Math.floor(24 / num)
+          resultVisible.value = true
+        })
+        break
+      default:
+        break
+    }
+  } else {
+    ElMessage.warning(`所有算法状态为‘已完成’,才可以对比`)
+  }
+}
+const handleResultData = data => {
+  resultsData.value = data
+  resultsData.value['agNameList'].unshift('')
+  const num = resultsData.value['agNameList'].length + 1
+  spanNum.value = 24 / num <= 4 ? 4 : Math.floor(24 / num)
+  resultsData.value['rcureList'].unshift('R_curve')
+  resultsData.value['pcureList'].unshift('P_curve')
+  resultsData.value['f1cureList'].unshift('F1_curve')
+}
+// 查看日志
+let timer2 = ref()
+const viewLog = row => {
+  // if (row.status === '0') {
+  //   ElMessage.warning('算法状态为待处理,暂无日志')
+  //   return
+  // }
+  const url = `/api/profile${row.log}`
+  logShow(url)
+  dialogVisible.value = true
+  timer2.value = setInterval(() => {
+    if (dialogVisible.value) {
+      logShow(url)
+    }
+  }, 5000)
+}
+// 日志读取
+const logShow = (url: any) => {
+  fetchLogFile(url)
+    .then(text => {
+      logInfo.value = []
+      logInfo.value = text.split('\n')
+      nextTick(() => {
+        const logContainer = logRef.value
+        if (logContainer) {
+          ;(logContainer as HTMLElement).scrollTop = (logContainer as HTMLElement).scrollHeight
+        }
+      })
+    })
+    .catch(error => {
+      console.error('Failed to fetch the log file:', error)
+      ElMessage.error('日志读取错误')
+    })
+}
+const fetchLogFile = async url => {
+  try {
+    const response = await fetch(url, { method: 'GET' })
+    if (!response.ok) {
+      throw new Error(`HTTP error! status: ${response.status}`)
+    }
+    return await response.text()
+  } catch (error) {
+    throw error
+  }
+}
+const formDialogRef = ref<InstanceType<typeof FormDialog> | null>(null)
+// 打开弹框的功能
+const openDialog = async (type: number, title: string, row?: any) => {
+  let res = { data: {} }
+  if (row?.id) {
+    res = await getBizProcessApi(row?.id || null)
+  }
+  // 重置表单
+  setItemsOptions()
+  const params = {
+    title,
+    width: 580,
+    isEdit: type !== 3,
+    itemsOptions: itemsOptions,
+    model: type == 1 ? {} : res.data,
+    api: type == 1 ? addBizProcessApi : updateBizProcessApi,
+    getTableList: proTable.value?.getTableList
+  }
+  formDialogRef.value?.openDialog(params)
+}
+onUnmounted(() => {
+  clearInterval(timer.value)
+  timer.value = null
+})
+watch(
+  () => dialogVisible.value,
+  val => {
+    if (!val) {
+      clearInterval(timer2.value)
+      timer2.value = null
+    }
+  }
+)
+// 表格配置项
+const columns = reactive<ColumnProps<any>[]>([
+  { type: 'selection', fixed: 'left', width: 70 },
+  // { prop: 'id', label: '主键ID' },
+  // {
+  //   prop: 'subTaskId',
+  //   label: '子任务id',
+  //   search: {
+  //     el: 'input'
+  //   },
+  //   width: 120
+  // },
+  {
+    prop: 'name',
+    label: '任务名称',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  // {
+  //   prop: 'type',
+  //   label: '任务类型',
+  //   search: {
+  //     el: 'input'
+  //   },
+  //   width: 120
+  // },
+  {
+    prop: 'status',
+    label: '任务状态',
+    tag: true,
+    enum: () => getDictsApi('biz_task_status'),
+    search: {
+      el: 'tree-select'
+    },
+    width: 100,
+    fieldNames: { label: 'dictLabel', value: 'dictValue' }
+  },
+  // {
+  //   prop: 'algorithmId',
+  //   label: '算法',
+  //   width: 120
+  // },
+  // {
+  //   prop: 'modelId',
+  //   label: '模型',
+  //   width: 120
+  // },
+  {
+    prop: 'parameters',
+    label: '调用算法时所用的参数'
+  },
+  {
+    prop: 'preprocessPath',
+    label: '预处理数据路径'
+  },
+  {
+    prop: 'resultPath',
+    label: '结果数据路径'
+  },
+  {
+    prop: 'index',
+    label: '序号',
+    width: 120
+  },
+  {
+    prop: 'startTime',
+    label: '开始时间'
+  },
+  {
+    prop: 'endTime',
+    label: '结束时间'
+  },
+  {
+    prop: 'costSecond',
+    label: '耗时'
+  },
+  {
+    prop: 'log',
+    label: '日志'
+  },
+  { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
+])
+// 结果表格配置项
+// const resultColumns = reactive<ColumnProps<any>[]>([])
+// 表单配置项
+let itemsOptions: ProForm.ItemsOptions[] = []
+const setItemsOptions = () => {
+  itemsOptions = [
+    {
+      label: '子任务id',
+      prop: 'subTaskId',
+      compOptions: {
+        placeholder: '请输入子任务id'
+      }
+    },
+    {
+      label: '任务名称',
+      prop: 'name',
+      compOptions: {
+        placeholder: '请输入任务名称'
+      }
+    },
+    {
+      label: '任务类型',
+      prop: 'type',
+      compOptions: {
+        placeholder: '请输入任务类型'
+      }
+    },
+    {
+      label: '任务状态',
+      prop: 'status',
+      compOptions: {
+        elTagName: 'select',
+        labelKey: 'dictLabel',
+        valueKey: 'dictValue',
+        enum: () => getDictsApi('biz_task_status'),
+        placeholder: '请选择任务状态'
+      }
+    },
+    {
+      label: '算法',
+      prop: 'algorithmId',
+      compOptions: {
+        placeholder: '请输入算法'
+      }
+    },
+    {
+      label: '模型',
+      prop: 'modelId',
+      compOptions: {
+        placeholder: '请输入模型'
+      }
+    },
+    {
+      label: '调用算法时所用的参数',
+      prop: 'parameters',
+      compOptions: {
+        type: 'textarea',
+        clearable: true,
+        placeholder: '请输入内容'
+      }
+    },
+    {
+      label: '预处理数据路径',
+      prop: 'preprocessPath',
+      compOptions: {
+        placeholder: '请输入预处理数据路径'
+      }
+    },
+    {
+      label: '结果数据路径',
+      prop: 'resultPath',
+      compOptions: {
+        placeholder: '请输入结果数据路径'
+      }
+    },
+    {
+      label: '序号',
+      prop: 'index',
+      compOptions: {
+        placeholder: '请输入序号'
+      }
+    },
+    {
+      label: '开始时间',
+      prop: 'startTime',
+      compOptions: {
+        elTagName: 'date-picker',
+        type: 'date',
+        placeholder: '请选择开始时间'
+      }
+    },
+    {
+      label: '结束时间',
+      prop: 'endTime',
+      compOptions: {
+        elTagName: 'date-picker',
+        type: 'date',
+        placeholder: '请选择结束时间'
+      }
+    },
+    {
+      label: '耗时',
+      prop: 'costSecond',
+      compOptions: {
+        placeholder: '请输入耗时'
+      }
+    },
+    {
+      label: '日志',
+      prop: 'log',
+      compOptions: {
+        type: 'textarea',
+        clearable: true,
+        placeholder: '请输入内容'
+      }
+    }
+  ]
+}
+</script>
+<style scoped lang="scss">
+.log {
+  width: 90%;
+  height: 60vh; /* 根据需要调整 */
+  padding: 10px;
+
+  // padding-bottom: 80px;
+  margin-left: 50px;
+  overflow-y: auto;
+  font-family: 'Courier New', monospace;
+  color: #4aff84;
+  background-color: #1e1e1e;
+}
+.p {
+  padding-left: 10px;
+  margin-bottom: 5px;
+  border-left: 3px solid #4aff84;
+}
+.resultShow {
+  width: 100%;
+  height: 60vh;
+  overflow: hidden;
+  overflow: scroll scroll;
+  .headerRow {
+    height: 50px;
+    font-size: 1.2rem;
+    line-height: 50px;
+    text-align: center;
+  }
+  .row {
+    .col {
+      text-align: center;
+      .oneCol {
+        margin-top: 45px;
+        font-size: 1.2rem;
+      }
+      .img {
+        margin: 10px 0;
+      }
+    }
+  }
+}
+</style>

+ 300 - 0
src/views/task/dataProcess/index.vue

@@ -0,0 +1,300 @@
+<template>
+  <div class="table-box">
+    <ProTable ref="proTable" :columns="columns" row-key="id" :request-api="listDataProcessApi">
+      <!-- 表格 header 按钮 -->
+      <template #tableHeader="scope">
+        <el-button type="primary" v-auth="['task:dataProcess:add']" icon="CirclePlus" @click="openDialog(1, '算法数据处理新增')"> 新增 </el-button>
+        <el-button type="primary" v-auth="['task:dataProcess:import']" icon="Upload" plain @click="batchAdd"> 导入 </el-button>
+        <el-button type="primary" v-auth="['task:dataProcess:export']" icon="Download" plain @click="downloadFile"> 导出 </el-button>
+        <el-button
+          type="danger"
+          v-auth="['task:dataProcess: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="['task:dataProcess:query']" @click="openDialog(3, '算法数据处理查看', scope.row)">
+          查看
+        </el-button>
+        <el-button type="primary" link icon="EditPen" v-auth="['task:dataProcess:edit']" @click="openDialog(2, '算法数据处理编辑', scope.row)">
+          编辑
+        </el-button>
+        <el-button type="primary" link icon="Delete" v-auth="['task:dataProcess:remove']" @click="deleteDataProcess(scope.row)"> 删除 </el-button>
+      </template>
+    </ProTable>
+    <FormDialog ref="formDialogRef" />
+    <ImportExcel ref="dialogRef" />
+  </div>
+</template>
+
+<script setup lang="tsx" name="DataProcess">
+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 {
+  listDataProcessApi,
+  delDataProcessApi,
+  addDataProcessApi,
+  updateDataProcessApi,
+  importTemplateApi,
+  importDataProcessDataApi,
+  exportDataProcessApi,
+  getDataProcessApi
+} from '@/api/modules/task/dataProcess'
+
+// ProTable 实例
+const proTable = ref<ProTableInstance>()
+
+// 删除算法数据处理信息
+const deleteDataProcess = async (params: any) => {
+  await useHandleData(delDataProcessApi, params.id, '删除【' + params.id + '】算法数据处理')
+  proTable.value?.getTableList()
+}
+
+// 批量删除算法数据处理信息
+const batchDelete = async (ids: string[]) => {
+  await useHandleData(delDataProcessApi, ids, '删除所选算法数据处理信息')
+  proTable.value?.clearSelection()
+  proTable.value?.getTableList()
+}
+
+// 导出算法数据处理列表
+const downloadFile = async () => {
+  ElMessageBox.confirm('确认导出算法数据处理数据?', '温馨提示', { type: 'warning' }).then(() =>
+    useDownload(exportDataProcessApi, '算法数据处理列表', proTable.value?.searchParam)
+  )
+}
+
+// 批量添加算法数据处理
+const dialogRef = ref<InstanceType<typeof ImportExcel> | null>(null)
+const batchAdd = () => {
+  const params = {
+    title: '算法数据处理',
+    tempApi: importTemplateApi,
+    importApi: importDataProcessDataApi,
+    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 getDataProcessApi(row?.id || null)
+  }
+  // 重置表单
+  setItemsOptions()
+  const params = {
+    title,
+    width: 580,
+    isEdit: type !== 3,
+    itemsOptions: itemsOptions,
+    model: type == 1 ? {} : res.data,
+    api: type == 1 ? addDataProcessApi : updateDataProcessApi,
+    getTableList: proTable.value?.getTableList
+  }
+  formDialogRef.value?.openDialog(params)
+}
+
+// 表格配置项
+const columns = reactive<ColumnProps<any>[]>([
+  { type: 'selection', fixed: 'left', width: 70 },
+  { prop: 'id', label: '主键ID' },
+  {
+    prop: 'subTaskId',
+    label: '子任务id',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'name',
+    label: '任务名称',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'type',
+    label: '任务类型',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'status',
+    label: '任务状态',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'algorithmId',
+    label: '算法',
+    width: 120
+  },
+  {
+    prop: 'parameters',
+    label: '调用算法时所用的参数',
+    width: 120
+  },
+  {
+    prop: 'preprocessPath',
+    label: '预处理数据路径',
+    width: 120
+  },
+  {
+    prop: 'resultPath',
+    label: '结果数据路径',
+    width: 120
+  },
+  {
+    prop: 'startTime',
+    label: '开始时间',
+    width: 120
+  },
+  {
+    prop: 'index',
+    label: '序号',
+    width: 120
+  },
+  {
+    prop: 'endTime',
+    label: '结束时间',
+    width: 120
+  },
+  {
+    prop: 'costSecond',
+    label: '耗时',
+    width: 120
+  },
+  {
+    prop: 'log',
+    label: '日志',
+    width: 120
+  },
+  { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
+])
+// 表单配置项
+let itemsOptions: ProForm.ItemsOptions[] = []
+const setItemsOptions = () => {
+  itemsOptions = [
+    {
+      label: '子任务id',
+      prop: 'subTaskId',
+      compOptions: {
+        placeholder: '请输入子任务id'
+      }
+    },
+    {
+      label: '任务名称',
+      prop: 'name',
+      compOptions: {
+        placeholder: '请输入任务名称'
+      }
+    },
+    {
+      label: '任务类型',
+      prop: 'type',
+      compOptions: {
+        placeholder: '请输入任务类型'
+      }
+    },
+    {
+      label: '任务状态',
+      prop: 'status',
+      compOptions: {
+        placeholder: '请输入任务状态'
+      }
+    },
+    {
+      label: '算法',
+      prop: 'algorithmId',
+      compOptions: {
+        placeholder: '请输入算法'
+      }
+    },
+    {
+      label: '调用算法时所用的参数',
+      prop: 'parameters',
+      compOptions: {
+        type: 'textarea',
+        clearable: true,
+        placeholder: '请输入内容'
+      }
+    },
+    {
+      label: '预处理数据路径',
+      prop: 'preprocessPath',
+      compOptions: {
+        placeholder: '请输入预处理数据路径'
+      }
+    },
+    {
+      label: '结果数据路径',
+      prop: 'resultPath',
+      compOptions: {
+        placeholder: '请输入结果数据路径'
+      }
+    },
+    {
+      label: '开始时间',
+      prop: 'startTime',
+      compOptions: {
+        elTagName: 'date-picker',
+        type: 'date',
+        placeholder: '请选择开始时间'
+      }
+    },
+    {
+      label: '序号',
+      prop: 'index',
+      compOptions: {
+        placeholder: '请输入序号'
+      }
+    },
+    {
+      label: '结束时间',
+      prop: 'endTime',
+      compOptions: {
+        elTagName: 'date-picker',
+        type: 'date',
+        placeholder: '请选择结束时间'
+      }
+    },
+    {
+      label: '耗时',
+      prop: 'costSecond',
+      compOptions: {
+        placeholder: '请输入耗时'
+      }
+    },
+    {
+      label: '日志',
+      prop: 'log',
+      compOptions: {
+        type: 'textarea',
+        clearable: true,
+        placeholder: '请输入内容'
+      }
+    }
+  ]
+}
+</script>

+ 276 - 0
src/views/task/dataSet/index.vue

@@ -0,0 +1,276 @@
+<template>
+  <div class="table-box">
+    <ProTable ref="proTable" :columns="columns" row-key="id" :request-api="listDataSetApi">
+      <!-- 表格 header 按钮 -->
+      <template #tableHeader="scope">
+        <el-button type="primary" v-auth="['task:dataSet:add']" icon="CirclePlus" @click="openDialog(1, '算法数据集合新增')"> 新增 </el-button>
+        <el-button type="primary" v-auth="['task:dataSet:import']" icon="Upload" plain @click="batchAdd"> 导入 </el-button>
+        <el-button type="primary" v-auth="['task:dataSet:export']" icon="Download" plain @click="downloadFile"> 导出 </el-button>
+        <el-button
+          type="danger"
+          v-auth="['task:dataSet: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="['task:dataSet:query']" @click="openDialog(3, '算法数据集合查看', scope.row)">
+          查看
+        </el-button>
+        <el-button type="primary" link icon="EditPen" v-auth="['task:dataSet:edit']" @click="openDialog(2, '算法数据集合编辑', scope.row)">
+          编辑
+        </el-button>
+        <el-button type="primary" link icon="Delete" v-auth="['task:dataSet:remove']" @click="deleteDataSet(scope.row)"> 删除 </el-button>
+      </template>
+    </ProTable>
+    <FormDialog ref="formDialogRef" />
+    <ImportExcel ref="dialogRef" />
+  </div>
+</template>
+
+<script setup lang="tsx" name="DataSet">
+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 {
+  listDataSetApi,
+  delDataSetApi,
+  addDataSetApi,
+  updateDataSetApi,
+  importTemplateApi,
+  importDataSetDataApi,
+  exportDataSetApi,
+  getDataSetApi
+} from '@/api/modules/task/dataSet'
+
+// ProTable 实例
+const proTable = ref<ProTableInstance>()
+
+// 删除算法数据集合信息
+const deleteDataSet = async (params: any) => {
+  await useHandleData(delDataSetApi, params.id, '删除【' + params.id + '】算法数据集合')
+  proTable.value?.getTableList()
+}
+
+// 批量删除算法数据集合信息
+const batchDelete = async (ids: string[]) => {
+  await useHandleData(delDataSetApi, ids, '删除所选算法数据集合信息')
+  proTable.value?.clearSelection()
+  proTable.value?.getTableList()
+}
+
+// 导出算法数据集合列表
+const downloadFile = async () => {
+  ElMessageBox.confirm('确认导出算法数据集合数据?', '温馨提示', { type: 'warning' }).then(() =>
+    useDownload(exportDataSetApi, '算法数据集合列表', proTable.value?.searchParam)
+  )
+}
+
+// 批量添加算法数据集合
+const dialogRef = ref<InstanceType<typeof ImportExcel> | null>(null)
+const batchAdd = () => {
+  const params = {
+    title: '算法数据集合',
+    tempApi: importTemplateApi,
+    importApi: importDataSetDataApi,
+    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 getDataSetApi(row?.id || null)
+  }
+  // 重置表单
+  setItemsOptions()
+  const params = {
+    title,
+    width: 580,
+    isEdit: type !== 3,
+    itemsOptions: itemsOptions,
+    model: type == 1 ? {} : res.data,
+    api: type == 1 ? addDataSetApi : updateDataSetApi,
+    getTableList: proTable.value?.getTableList
+  }
+  formDialogRef.value?.openDialog(params)
+}
+
+// 表格配置项
+const columns = reactive<ColumnProps<any>[]>([
+  { type: 'selection', fixed: 'left', width: 70 },
+  { prop: 'id', label: '主键ID' },
+  {
+    prop: 'subTaskId',
+    label: '子任务id',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'name',
+    label: '任务名称',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'type',
+    label: '任务类型',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'status',
+    label: '任务状态',
+    search: {
+      el: 'input'
+    },
+    width: 120
+  },
+  {
+    prop: 'parameters',
+    label: '调用算法时所用的参数',
+    width: 120
+  },
+  {
+    prop: 'resultPath',
+    label: '结果数据路径',
+    width: 120
+  },
+  {
+    prop: 'startTime',
+    label: '开始时间',
+    width: 120
+  },
+  {
+    prop: 'index',
+    label: '序号',
+    width: 120
+  },
+  {
+    prop: 'endTime',
+    label: '结束时间',
+    width: 120
+  },
+  {
+    prop: 'costSecond',
+    label: '耗时',
+    width: 120
+  },
+  {
+    prop: 'log',
+    label: '日志',
+    width: 120
+  },
+  { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
+])
+// 表单配置项
+let itemsOptions: ProForm.ItemsOptions[] = []
+const setItemsOptions = () => {
+  itemsOptions = [
+    {
+      label: '子任务id',
+      prop: 'subTaskId',
+      compOptions: {
+        placeholder: '请输入子任务id'
+      }
+    },
+    {
+      label: '任务名称',
+      prop: 'name',
+      compOptions: {
+        placeholder: '请输入任务名称'
+      }
+    },
+    {
+      label: '任务类型',
+      prop: 'type',
+      compOptions: {
+        placeholder: '请输入任务类型'
+      }
+    },
+    {
+      label: '任务状态',
+      prop: 'status',
+      compOptions: {
+        placeholder: '请输入任务状态'
+      }
+    },
+    {
+      label: '调用算法时所用的参数',
+      prop: 'parameters',
+      compOptions: {
+        type: 'textarea',
+        clearable: true,
+        placeholder: '请输入内容'
+      }
+    },
+    {
+      label: '结果数据路径',
+      prop: 'resultPath',
+      compOptions: {
+        placeholder: '请输入结果数据路径'
+      }
+    },
+    {
+      label: '开始时间',
+      prop: 'startTime',
+      compOptions: {
+        elTagName: 'date-picker',
+        type: 'date',
+        placeholder: '请选择开始时间'
+      }
+    },
+    {
+      label: '序号',
+      prop: 'index',
+      compOptions: {
+        placeholder: '请输入序号'
+      }
+    },
+    {
+      label: '结束时间',
+      prop: 'endTime',
+      compOptions: {
+        elTagName: 'date-picker',
+        type: 'date',
+        placeholder: '请选择结束时间'
+      }
+    },
+    {
+      label: '耗时',
+      prop: 'costSecond',
+      compOptions: {
+        placeholder: '请输入耗时'
+      }
+    },
+    {
+      label: '日志',
+      prop: 'log',
+      compOptions: {
+        type: 'textarea',
+        clearable: true,
+        placeholder: '请输入内容'
+      }
+    }
+  ]
+}
+</script>

+ 100 - 47
src/views/task/subtask/index.vue

@@ -1,10 +1,10 @@
 <template>
   <div class="table-box">
-    <ProTable ref="proTable" :columns="columns" row-key="id" :request-api="listSubtaskApi">
+    <ProTable ref="proTable" :is-show-search="false" :columns="columns" row-key="id" :data="subTaskList">
       <!-- 表格 header 按钮 -->
       <template #tableHeader="scope">
-        <el-button type="primary" v-auth="['task:subtask:add']" icon="CirclePlus" @click="openDialog(1, '算法子任务新增')"> 新增 </el-button>
-        <el-button type="primary" v-auth="['task:subtask:import']" icon="Upload" plain @click="batchAdd"> 导入 </el-button>
+        <!-- <el-button type="primary" v-auth="['task:subtask:add']" icon="CirclePlus" @click="openDialog(1, '算法子任务新增')"> 新增 </el-button>
+        <el-button type="primary" v-auth="['task:subtask:import']" icon="Upload" plain @click="batchAdd"> 导入 </el-button> -->
         <el-button type="primary" v-auth="['task:subtask:export']" icon="Download" plain @click="downloadFile"> 导出 </el-button>
         <el-button
           type="danger"
@@ -19,9 +19,7 @@
       </template>
       <!-- 表格操作 -->
       <template #operation="scope">
-        <el-button type="primary" link icon="View" v-auth="['task:subtask:query']" @click="openDialog(3, '算法子任务查看', scope.row)">
-          查看
-        </el-button>
+        <el-button type="primary" link icon="View" v-auth="['task:subtask:query']" @click="viewDetails(scope.row)"> 查看详情 </el-button>
         <el-button type="primary" link icon="EditPen" v-auth="['task:subtask:edit']" @click="openDialog(2, '算法子任务编辑', scope.row)">
           编辑
         </el-button>
@@ -34,29 +32,48 @@
 </template>
 
 <script setup lang="tsx" name="Subtask">
-import { ref, reactive } from 'vue'
+import { ref, reactive, onUnmounted, onMounted } 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 { useRoute, useRouter } from 'vue-router'
 import { ProTableInstance, ColumnProps } from '@/components/ProTable/interface'
-import {
-  listSubtaskApi,
-  delSubtaskApi,
-  addSubtaskApi,
-  updateSubtaskApi,
-  importTemplateApi,
-  importSubtaskDataApi,
-  exportSubtaskApi,
-  getSubtaskApi
-} from '@/api/modules/task/subtask'
+import { listSubtaskApi, delSubtaskApi, addSubtaskApi, updateSubtaskApi, exportSubtaskApi, getSubtaskApi } from '@/api/modules/task/subtask'
 import { getDictsApi } from '@/api/modules/system/dictData'
-
+const router = useRouter()
+const route = useRoute()
+const taskId = route.query.id as string
 // ProTable 实例
 const proTable = ref<ProTableInstance>()
+let subTaskList = ref()
 
+// 每隔10秒请求一下列表
+const timer = ref() // 定时器
+const refreshList = () => {
+  setTimeout(() => {
+    listSubtaskApi({
+      pageNum: 1,
+      pageSize: 100,
+      taskId: taskId
+    }).then(res => {
+      subTaskList.value = res.data['list']
+    })
+  }, 0)
+}
+onMounted(() => {
+  // timer
+  refreshList()
+  timer.value = setInterval(() => {
+    refreshList()
+  }, 10000)
+})
+// 查看详情
+const viewDetails = row => {
+  router.push({ path: `/task/bizProcess/`, query: { id: row.id } })
+}
 // 删除算法子任务信息
 const deleteSubtask = async (params: any) => {
   await useHandleData(delSubtaskApi, params.id, '删除【' + params.id + '】算法子任务')
@@ -79,15 +96,15 @@ const downloadFile = async () => {
 
 // 批量添加算法子任务
 const dialogRef = ref<InstanceType<typeof ImportExcel> | null>(null)
-const batchAdd = () => {
-  const params = {
-    title: '算法子任务',
-    tempApi: importTemplateApi,
-    importApi: importSubtaskDataApi,
-    getTableList: proTable.value?.getTableList
-  }
-  dialogRef.value?.acceptParams(params)
-}
+// const batchAdd = () => {
+//   const params = {
+//     title: '算法子任务',
+//     tempApi: importTemplateApi,
+//     importApi: importSubtaskDataApi,
+//     getTableList: proTable.value?.getTableList
+//   }
+//   dialogRef.value?.acceptParams(params)
+// }
 
 const formDialogRef = ref<InstanceType<typeof FormDialog> | null>(null)
 // 打开弹框的功能
@@ -109,10 +126,14 @@ const openDialog = async (type: number, title: string, row?: any) => {
   }
   formDialogRef.value?.openDialog(params)
 }
-
+onUnmounted(() => {
+  clearInterval(timer.value)
+  timer.value = null
+})
 // 表格配置项
 const columns = reactive<ColumnProps<any>[]>([
   { type: 'selection', fixed: 'left', width: 70 },
+  { prop: 'id', label: '主键ID' },
   {
     prop: 'name',
     label: '任务名称',
@@ -128,30 +149,54 @@ const columns = reactive<ColumnProps<any>[]>([
     search: {
       el: 'tree-select'
     },
-    fieldNames: { label: 'dictLabel', value: 'dictValue' },
-    width: 120
-  },
-  {
-    prop: 'startTime',
-    label: '开始时间',
-    width: 200
+    fieldNames: { label: 'dictLabel', value: 'dictValue' }
   },
   {
-    prop: 'endTime',
-    label: '结束时间',
-    width: 200
-  },
-  {
-    prop: 'costSecond',
-    label: '耗时',
-    width: 120
+    prop: 'type',
+    label: '任务类型',
+    tag: true,
+    enum: () => getDictsApi('biz_ag_type'),
+    fieldNames: { label: 'dictLabel', value: 'dictValue' }
   },
-  { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
+  // {
+  //   prop: 'parameters',
+  //   label: '调用算法时所用的参数'
+  // },
+  // {
+  //   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: '耗时'
+  // },
+  { prop: 'operation', label: '操作', width: 270, fixed: 'right' }
 ])
 // 表单配置项
 let itemsOptions: ProForm.ItemsOptions[] = []
 const setItemsOptions = () => {
   itemsOptions = [
+    {
+      label: '任务ID',
+      prop: 'taskId',
+      compOptions: {
+        placeholder: '请输入任务ID'
+      }
+    },
     {
       label: '任务名称',
       prop: 'name',
@@ -172,6 +217,14 @@ const setItemsOptions = () => {
         placeholder: '请选择任务状态'
       }
     },
+    {
+      label: '任务类型',
+      prop: 'type',
+      rules: [{ required: true, message: '任务类型不能为空', trigger: 'blur' }],
+      compOptions: {
+        placeholder: '请输入任务类型'
+      }
+    },
     {
       label: '调用算法时所用的参数',
       prop: 'parameters',
@@ -216,10 +269,10 @@ const setItemsOptions = () => {
       }
     },
     {
-      label: '是否包含详情',
-      prop: 'hasDetails',
+      label: '序号',
+      prop: 'index',
       compOptions: {
-        placeholder: '请输入是否包含详情'
+        placeholder: '请输入序号'
       }
     }
   ]

+ 35 - 35
src/views/task/task/index.vue

@@ -19,7 +19,7 @@
       </template>
       <!-- 表格操作 -->
       <template #operation="scope">
-        <el-button type="primary" link icon="View" v-auth="['task:task:query']" @click="openDialog(3, '算法任务查看', scope.row)"> 查看 </el-button>
+        <el-button type="primary" link icon="View" v-auth="['task:task:query']" @click="viewDetails(scope.row)"> 查看详情 </el-button>
         <el-button type="primary" link icon="EditPen" v-auth="['task:task:edit']" @click="openDialog(2, '算法任务编辑', scope.row)"> 编辑 </el-button>
         <el-button type="primary" link icon="Delete" v-auth="['task:task:remove']" @click="deleteTask(scope.row)"> 删除 </el-button>
       </template>
@@ -34,6 +34,7 @@ import { ref, reactive } from 'vue'
 import { useHandleData } from '@/hooks/useHandleData'
 import { useDownload } from '@/hooks/useDownload'
 import { ElMessageBox } from 'element-plus'
+import { useRouter } from 'vue-router'
 import ProTable from '@/components/ProTable/index.vue'
 import ImportExcel from '@/components/ImportExcel/index.vue'
 import FormDialog from '@/components/FormDialog/index.vue'
@@ -49,7 +50,7 @@ import {
   getTaskApi
 } from '@/api/modules/task/task'
 import { getDictsApi } from '@/api/modules/system/dictData'
-
+const router = useRouter()
 // ProTable 实例
 const proTable = ref<ProTableInstance>()
 
@@ -105,6 +106,10 @@ const openDialog = async (type: number, title: string, row?: any) => {
   }
   formDialogRef.value?.openDialog(params)
 }
+// 查看详情
+const viewDetails = row => {
+  router.push({ path: `/task/subtask/`, query: { id: row.id } })
+}
 
 // 表格配置项
 const columns = reactive<ColumnProps<any>[]>([
@@ -124,36 +129,35 @@ const columns = reactive<ColumnProps<any>[]>([
     search: {
       el: 'tree-select'
     },
-    fieldNames: { label: 'dictLabel', value: 'dictValue' },
-    width: 120
-  },
-  {
-    prop: 'startTime',
-    label: '开始时间',
-    search: {
-      el: 'date-picker',
-      props: { type: 'datetimerange', valueFormat: 'YYYY-MM-DD HH:mm:ss' }
-    },
-    width: 200
-  },
-  {
-    prop: 'endTime',
-    label: '结束时间',
-    search: {
-      el: 'date-picker',
-      props: { type: 'datetimerange', valueFormat: 'YYYY-MM-DD HH:mm:ss' }
-    },
-    width: 200
-  },
-  {
-    prop: 'costSecond',
-    label: '耗时',
-    search: {
-      el: 'input'
-    },
-    width: 120
+    fieldNames: { label: 'dictLabel', value: 'dictValue' }
   },
-  { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
+  // {
+  //   prop: 'startTime',
+  //   label: '开始时间',
+  //   search: {
+  //     el: 'date-picker',
+  //     props: { type: 'datetimerange', valueFormat: 'YYYY-MM-DD HH:mm:ss' }
+  //   },
+  //   width: 200
+  // },
+  // {
+  //   prop: 'endTime',
+  //   label: '结束时间',
+  //   search: {
+  //     el: 'date-picker',
+  //     props: { type: 'datetimerange', valueFormat: 'YYYY-MM-DD HH:mm:ss' }
+  //   },
+  //   width: 200
+  // },
+  // {
+  //   prop: 'costSecond',
+  //   label: '耗时',
+  //   search: {
+  //     el: 'input'
+  //   },
+  //   width: 120
+  // },
+  { prop: 'operation', label: '操作', fixed: 'right' }
 ])
 // 表单配置项
 let itemsOptions: ProForm.ItemsOptions[] = []
@@ -170,10 +174,6 @@ const setItemsOptions = () => {
     {
       label: '任务状态',
       prop: 'status',
-      options: {
-        labelKey: 'dictLabel',
-        valueKey: 'dictValue'
-      },
       compOptions: {
         elTagName: 'select',
         labelKey: 'dictLabel',

文件差异内容过多而无法显示
+ 557 - 586
yarn.lock


部分文件因为文件数量过多而无法显示