Forráskód Böngészése

feat: 任务创建流程、显示日志页面、推理结果

R 1 éve
szülő
commit
c874df8f2f

+ 1 - 1
.env

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

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

@@ -0,0 +1,6 @@
+import taskDataList from '@/assets/mock/taskData.json'
+
+export const getTaskApi = (taskId?: string) => {
+  return taskDataList.data.filter(item => item.taskId === taskId)[0]
+  // return http.get<any>('/system/user/list', query, { loading: true })
+}

+ 144 - 0
src/assets/mock/Untitled-1.json

@@ -0,0 +1,144 @@
+[
+  "from  n    params  module                                       arguments",
+  "0                  -1  1      2320  ultralytics.nn.modules.conv.Conv             [3, 80, 3, 2]             ",
+  "1                  -1  1    115520  ultralytics.nn.modules.conv.Conv             [80, 160, 3, 2]",
+  "2                  -1  3    436800  ultralytics.nn.modules.block.C2f             [160, 160, 3, True]",
+  "3                  -1  1    461440  ultralytics.nn.modules.conv.Conv             [160, 320, 3, 2]",
+  "4                  -1  6   3281920  ultralytics.nn.modules.block.C2f             [320, 320, 6, True]           ",
+  "5                  -1  3    308454  ultralytics.nn.modules.conv.CBAM             [320, 7]",
+  "6                  -1  1   1844480  ultralytics.nn.modules.conv.Conv             [320, 640, 3, 2]",
+  "7                  -1  6   5848320  ultralytics.nn.modules.conv.CNeB             [640, 640, 6, True]           ",
+  "8                  -1  1   3687680  ultralytics.nn.modules.conv.Conv             [640, 640, 3, 2]              ",
+  "9                  -1  3   6969600  ultralytics.nn.modules.block.C2f             [640, 640, 3, True]           ",
+  "10                  -1  1   1025920  ultralytics.nn.modules.block.SPPF            [640, 640, 5]",
+  "11                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']",
+  "12             [-1, 7]  1         0  ultralytics.nn.modules.conv.Concat           [1]",
+  "13                  -1  3   7379200  ultralytics.nn.modules.block.C2f             [1280, 640, 3]                ",
+  "14                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']",
+  "15             [-1, 4]  1         0  ultralytics.nn.modules.conv.Concat           [1]",
+  "16                  -1  3   1948800  ultralytics.nn.modules.block.C2f             [960, 320, 3]                 ",
+  "17                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']",
+  "18             [-1, 2]  1         0  ultralytics.nn.modules.conv.Concat           [1]",
+  "19                  -1  3    488000  ultralytics.nn.modules.block.C2f             [480, 160, 3]",
+  "20                  -1  1    230720  ultralytics.nn.modules.conv.Conv             [160, 160, 3, 2]",
+  "21            [-1, 16]  1         0  ultralytics.nn.modules.conv.Concat           [1]",
+  "22                  -1  3   1795200  ultralytics.nn.modules.block.C2f             [480, 320, 3]                 ",
+  "23                  -1  1    922240  ultralytics.nn.modules.conv.Conv             [320, 320, 3, 2]",
+  "24            [-1, 13]  1         0  ultralytics.nn.modules.conv.Concat           [1]",
+  "25                  -1  3   7174400  ultralytics.nn.modules.block.C2f             [960, 640, 3]                 ",
+  "26                  -1  1   3687680  ultralytics.nn.modules.conv.Conv             [640, 640, 3, 2]              ",
+  "27            [-1, 10]  1         0  ultralytics.nn.modules.conv.Concat           [1]",
+  "28                  -1  3   7379200  ultralytics.nn.modules.block.C2f             [1280, 640, 3]                ",
+  "29    [19, 22, 25, 28]  1   4643896  ultralytics.nn.modules.head.Detect           [10, [160, 320, 640, 640]]    ",
+  "YOLOv8x-p2_VisDrone_CBAM+ConvNext summary: 473 layers, 59631790 parameters, 59631774 gradients",
+  "",
+  "Transferred 156/722 items from pretrained weights",
+  "New https://pypi.org/project/ultralytics/8.1.29 available  Update with 'pip install -U ultralytics'",
+  "Ultralytics YOLOv8.0.126  Python-3.9.18 torch-1.13.1+cu116 CUDA:0 (NVIDIA GeForce RTX 3070 Ti Laptop GPU, 8192MiB)",
+  "WARNING  Upgrade to torch>=2.0.0 for deterministic training.",
+  "yolo\\engine\\trainer: task=detect, mode=train, model=yolov8x-p2_VisDrone_CBAM+ConvNext.yaml, data=MyVisDrone.yaml, epochs=1, patience=50, batch=2, imgsz=640, save=True, save_pe",
+  "riod=-1, cache=False, device=[0], workers=8, project=runs\\detect, name=train, exist_ok=False, pretrained=True, optimizer=auto, verbose=True, seed=0, deterministic=True, single",
+  "_cls=False, rect=False, cos_lr=False, close_mosaic=10, resume=False, amp=True, fraction=1.0, profile=False, overlap_mask=True, mask_ratio=4, dropout=0.0, val=True, split=val, ",
+  "save_json=False, save_hybrid=False, conf=None, iou=0.7, max_det=300, half=False, dnn=False, plots=True, source=None, show=False, save_txt=False, save_conf=False, save_crop=Fal",
+  "se, show_labels=True, show_conf=True, vid_stride=1, line_width=None, visualize=False, augment=False, agnostic_nms=False, classes=None, retina_masks=False, boxes=True, format=t",
+  "orchscript, keras=False, optimize=False, int8=False, dynamic=False, simplify=False, opset=None, workspace=4, nms=False, lr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005",
+  ", warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=7.5, cls=0.5, dfl=1.5, pose=12.0, kobj=1.0, label_smoothing=0.0, nbs=64, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, d",
+  "egrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0, copy_paste=0.0, cfg=None, v5loader=False, tracker=botsort.yaml, save_dir=runs\\detect\\train7",
+  "",
+  "                 from  n    params  module                                       arguments",
+  "0                  -1  1      2320  ultralytics.nn.modules.conv.Conv             [3, 80, 3, 2]",
+  "1                  -1  1    115520  ultralytics.nn.modules.conv.Conv             [80, 160, 3, 2]",
+  "2                  -1  3    436800  ultralytics.nn.modules.block.C2f             [160, 160, 3, True]",
+  "3                  -1  1    461440  ultralytics.nn.modules.conv.Conv             [160, 320, 3, 2]",
+  "4                  -1  6   3281920  ultralytics.nn.modules.block.C2f             [320, 320, 6, True]           ",
+  "5                  -1  3    308454  ultralytics.nn.modules.conv.CBAM             [320, 7]",
+  "6                  -1  1   1844480  ultralytics.nn.modules.conv.Conv             [320, 640, 3, 2]",
+  "7                  -1  6   5848320  ultralytics.nn.modules.conv.CNeB             [640, 640, 6, True]           ",
+  "8                  -1  1   3687680  ultralytics.nn.modules.conv.Conv             [640, 640, 3, 2]              ",
+  "9                  -1  3   6969600  ultralytics.nn.modules.block.C2f             [640, 640, 3, True]           ",
+  "10                  -1  1   1025920  ultralytics.nn.modules.block.SPPF            [640, 640, 5]",
+  "11                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']",
+  "12             [-1, 7]  1         0  ultralytics.nn.modules.conv.Concat           [1]",
+  "13                  -1  3   7379200  ultralytics.nn.modules.block.C2f             [1280, 640, 3]                ",
+  "14                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']",
+  "15             [-1, 4]  1         0  ultralytics.nn.modules.conv.Concat           [1]",
+  "16                  -1  3   1948800  ultralytics.nn.modules.block.C2f             [960, 320, 3]",
+  "17                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          ",
+  "18             [-1, 2]  1         0  ultralytics.nn.modules.conv.Concat           [1]",
+  "19                  -1  3    488000  ultralytics.nn.modules.block.C2f             [480, 160, 3]",
+  "20                  -1  1    230720  ultralytics.nn.modules.conv.Conv             [160, 160, 3, 2]",
+  "21            [-1, 16]  1         0  ultralytics.nn.modules.conv.Concat           [1]",
+  "22                  -1  3   1795200  ultralytics.nn.modules.block.C2f             [480, 320, 3]                 ",
+  "23                  -1  1    922240  ultralytics.nn.modules.conv.Conv             [320, 320, 3, 2]",
+  "24            [-1, 13]  1         0  ultralytics.nn.modules.conv.Concat           [1]",
+  "25                  -1  3   7174400  ultralytics.nn.modules.block.C2f             [960, 640, 3]                 ",
+  "26                  -1  1   3687680  ultralytics.nn.modules.conv.Conv             [640, 640, 3, 2]              ",
+  "27            [-1, 10]  1         0  ultralytics.nn.modules.conv.Concat           [1]",
+  "28                  -1  3   7379200  ultralytics.nn.modules.block.C2f             [1280, 640, 3]                ",
+  "29    [19, 22, 25, 28]  1   4643896  ultralytics.nn.modules.head.Detect           [10, [160, 320, 640, 640]]    ",
+  "YOLOv8x-p2_VisDrone_CBAM+ConvNext summary: 473 layers, 59631790 parameters, 59631774 gradients",
+  "",
+  "Transferred 722/722 items from pretrained weights",
+  "AMP: running Automatic Mixed Precision (AMP) checks with YOLOv8n...",
+  "AMP: checks passed ",
+  "train: Scanning D:\\workspace\\python\\DetectionSoftware\\VisDrone\\VisDrone2019-DET-train\\labels.cache... 6471 images, 0 backgrounds, 0 corrupt: 100%|██████████| 6471/6471 [00:00",
+  "train: WARNING  D:\\workspace\\python\\DetectionSoftware\\VisDrone\\VisDrone2019-DET-train\\images\\0000137_02220_d_0000163.jpg: 1 duplicate labels removed",
+  "train: WARNING  D:\\workspace\\python\\DetectionSoftware\\VisDrone\\VisDrone2019-DET-train\\images\\0000140_00118_d_0000002.jpg: 1 duplicate labels removed",
+  "train: WARNING  D:\\workspace\\python\\DetectionSoftware\\VisDrone\\VisDrone2019-DET-train\\images\\9999945_00000_d_0000114.jpg: 1 duplicate labels removed",
+  "train: WARNING  D:\\workspace\\python\\DetectionSoftware\\VisDrone\\VisDrone2019-DET-train\\images\\9999987_00000_d_0000049.jpg: 1 duplicate labels removed",
+  "val: Scanning D:\\workspace\\python\\DetectionSoftware\\VisDrone\\VisDrone2019-DET-val\\labels.cache... 548 images, 0 backgrounds, 0 corrupt: 100%|██████████| 548/548 [00:00<?, ?it",
+  "No module named 'seaborn'",
+  "optimizer: AdamW(lr=0.000714, momentum=0.9) with parameter groups 107 weight(decay=0.0), 152 weight(decay=0.0005), 142 bias(decay=0.0)",
+  "Image sizes 640 train, 640 val",
+  "Using 2 dataloader workers",
+  "Logging results to runs\\detect\\train7",
+  "Starting training for 1 epochs...",
+  "",
+  "    Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size",
+  "      1/1      5.01G      4.938       5.99      4.231        344        640:   2%|▏         | 71/3236 [00:20<18:33,  2.84it/s]",
+  "",
+  "      1/1      5.49G          4      4.316      3.937        187        640:  11%|█         | 363/3236 [01:54<14:50,  3.23it/s]",
+  "",
+  "      1/1      6.73G      2.921      2.894      2.978        152        640:  34%|███▍      | 1113/3236 [05:38<10:11,  3.47it/s]",
+  "",
+  "      1/1      6.73G      2.836       2.79      2.867        200        640:  39%|███▊      | 1250/3236 [06:22<09:54,  3.34it/s]",
+  "",
+  "      1/1      6.73G      2.692      2.621      2.679         91        640:  47%|████▋     | 1532/3236 [07:50<08:25,  3.37it/s]",
+  "",
+  "      1/1      6.73G      2.576      2.488      2.524        211        640:  56%|█████▋    | 1828/3236 [09:28<06:43,  3.49it/s]",
+  "",
+  "      1/1      6.73G      2.522      2.428      2.454        151        640:  61%|██████▏   | 1983/3236 [10:18<06:06,  3.42it/s]",
+  "",
+  "      1/1      6.77G      2.263      2.142      2.095         95        640: 100%|██████████| 3236/3236 [17:17<00:00,  3.12it/s]",
+  "",
+  "",
+  "      Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100%|██████████| 137/137 [00:29<00:00,  4.61it/s]",
+  "      all        548      38759      0.351      0.244      0.206      0.113",
+  "WARNING  ConfusionMatrix plot failure: No module named 'seaborn'",
+  "WARNING  ConfusionMatrix plot failure: No module named 'seaborn'",
+  "",
+  "1 epochs completed in 0.298 hours.",
+  "Optimizer stripped from runs\\detect\\train7\\weights\\last.pt, 119.8MB",
+  "Optimizer stripped from runs\\detect\\train7\\weights\\best.pt, 119.8MB",
+  "",
+  "Validating runs\\detect\\train7\\weights\\best.pt...",
+  "Ultralytics YOLOv8.0.126  Python-3.9.18 torch-1.13.1+cu116 CUDA:0 (NVIDIA GeForce RTX 3070 Ti Laptop GPU, 8192MiB)",
+  "YOLOv8x-p2_VisDrone_CBAM+ConvNext summary (fused): 366 layers, 59604638 parameters, 0 gradients",
+  "               Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100%|██████████| 137/137 [00:26<00:00,  5.24it/s]",
+  "                 all        548      38759      0.351      0.244      0.206      0.113",
+  "          pedestrian        548       8844        0.3      0.378      0.307      0.131",
+  "              people        548       5125      0.304       0.23      0.179     0.0632",
+  "             bicycle        548       1287     0.0887     0.0163     0.0219    0.00805",
+  "                 car        548      14064      0.572      0.719      0.702      0.456",
+  "                 van        548       1975      0.313      0.265      0.222      0.147",
+  "               truck        548        750       0.23      0.181      0.111     0.0649",
+  "            tricycle        548       1045      0.158     0.0354     0.0551     0.0293",
+  "     awning-tricycle        548        532          1          0     0.0351     0.0221",
+  "                 bus        548        251      0.188      0.335      0.182       0.12",
+  "               motor        548       4886       0.36      0.277      0.249     0.0923",
+  "WARNING  ConfusionMatrix plot failure: No module named 'seaborn'",
+  "WARNING  ConfusionMatrix plot failure: No module named 'seaborn'",
+  "Speed: 0.2ms preprocess, 27.6ms inference, 0.0ms loss, 4.1ms postprocess per image",
+  "Results saved to runs\\detect\\train7",
+  "任务完成..."
+]

+ 14 - 0
src/assets/mock/Untitled-2.json

@@ -0,0 +1,14 @@
+[
+  "Found https:\\alifei05.cfp.cn\\creative\\vcg\\800\\new\\VCG21gic19450902.jpg locally at VCG21gic19450902.jpg",
+  "image 1/1 D:\\workspace\\python\\DetectionSoftware\\ultralytics\\VCG21gic19450902.jpg: 448x640 21 pedestrians, 6 peoples, 1 bicycle, 36 cars, 3 vans, 1 bus, 23 motors, 39.1ms",
+  "Speed: 1.0ms preprocess, 39.1ms inference, 2.0ms postprocess per image at shape (1, 3, 448, 640)",
+  "127.0.0.1 - - [19/Mar/2024 09:45:12] \"POST /inference HTTP/1.1\" 200 -",
+  "127.0.0.1 - - [19/Mar/2024 09:45:14] \"POST /show_labels HTTP/1.1\" 200 -",
+  "127.0.0.1 - - [19/Mar/2024 09:45:16] \"POST /show_res HTTP/1.1\" 200 -",
+  "127.0.0.1 - - [19/Mar/2024 09:45:18] \"POST /show_matrix HTTP/1.1\" 200 -",
+  "127.0.0.1 - - [19/Mar/2024 09:45:20] \"POST /show_norm_matrix HTTP/1.1\" 200 -",
+  "127.0.0.1 - - [19/Mar/2024 09:45:22] \"POST /show_F1_curve HTTP/1.1\" 200 -",
+  "127.0.0.1 - - [19/Mar/2024 09:45:24] \"POST /show_P_curve HTTP/1.1\" 200 -",
+  "127.0.0.1 - - [19/Mar/2024 09:45:26] \"POST /show_R_curve HTTP/1.1\" 200 -",
+  "127.0.0.1 - - [19/Mar/2024 09:45:29] \"POST /show_PR_curve HTTP/1.1\" 200 -"
+]

+ 0 - 0
src/assets/mock/tableData.json


+ 16 - 0
src/assets/mock/taskData.json

@@ -0,0 +1,16 @@
+{
+  "code": 200,
+  "data": [
+    {
+      "taskId": "111111",
+      "taskName": "xxxx",
+      "status": "0"
+    },
+    {
+      "taskId": "111222",
+      "taskName": "pppp",
+      "status": "1"
+    }
+  ],
+  "msg": "成功"
+}

BIN
src/assets/taaisImg/F1_curve.png


BIN
src/assets/taaisImg/PR_curve.png


BIN
src/assets/taaisImg/P_curve.png


BIN
src/assets/taaisImg/R_curve.png


BIN
src/assets/taaisImg/bg.jpg


BIN
src/assets/taaisImg/bkg.png


BIN
src/assets/taaisImg/confusion_matrix.png


BIN
src/assets/taaisImg/confusion_matrix_normalized.png


BIN
src/assets/taaisImg/homeBKG.png


BIN
src/assets/taaisImg/homeBKG2.jpg


BIN
src/assets/taaisImg/labels.jpg


BIN
src/assets/taaisImg/results.png


BIN
src/assets/taaisImg/右框.png


+ 14 - 4
src/components/ProForm/components/Item.vue

@@ -2,8 +2,8 @@
   <component
     :is="elTagNameValue"
     v-bind="item.compOptions"
-    v-model.trim="_formModel[handleProp(item.prop)]"
-    :data="['tree-select'].includes(item.compOptions.elTagName!) ? itemEnum : []"
+    v-model.trim="_formModel[handleProp(item.formItemOptions.prop)]"
+    :data="['tree-select', 'tree'].includes(item.compOptions.elTagName!) ? itemEnum : []"
     :options="['cascader', 'select-v2'].includes(item.compOptions.elTagName!) ? itemEnum : []"
   >
     <template v-if="item.compOptions.elTagName === 'cascader'" #default="{ data }">
@@ -19,12 +19,22 @@
       ></component>
     </template>
     <template v-if="item.compOptions.elTagName === 'radio-group'">
-      <component :is="`el-radio`" v-for="(col, index) in itemEnum" :key="index" :value="col[item.compOptions.valueKey || 'value']">
+      <component
+        :is="`el-radio`"
+        v-for="(col, index) in itemEnum"
+        :key="index"
+        :value="col[item.compOptions.valueKey || 'value']"
+      >
         {{ col[item.compOptions.labelKey || 'label'] }}
       </component>
     </template>
     <template v-if="item.compOptions.elTagName === 'radio-button'">
-      <component :is="`el-radio-button`" v-for="(col, index) in itemEnum" :key="index" :label="col[item.compOptions.valueKey || 'value']">
+      <component
+        :is="`el-radio-button`"
+        v-for="(col, index) in itemEnum"
+        :key="index"
+        :label="col[item.compOptions.valueKey || 'value']"
+      >
         {{ col[item.compOptions.labelKey || 'label'] }}
       </component>
     </template>

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

@@ -33,8 +33,10 @@
       </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>
@@ -87,6 +89,7 @@ const _formOptions: ComputedRef<ProForm.FormOptions> = computed(() => {
     disabled: false,
     hasFooter: true,
     labelSuffix: ': ',
+    showSubmitButton: true,
     submitButtonText: '提交',
     resetButtonText: '重置',
     cancelButtonText: '取消'

+ 50 - 20
src/routers/modules/routerData.json

@@ -3,11 +3,11 @@
   "data": [
     {
       "path": "/index",
-      "name": "HomeIndex",
-      "component": "index",
+      "name": "home",
+      "component": "taais/homePage/index",
       "hidden": false,
       "meta": {
-        "icon": "",
+        "icon": "HomeFilled",
         "title": "首页",
         "link": "",
         "full": false,
@@ -15,13 +15,58 @@
         "noCache": true
       }
     },
+    {
+      "path": "/createTask",
+      "name": "createTask",
+      "component": "taais/homePage/createTask",
+      "hidden": true,
+      "meta": {
+        "icon": "HomeFilled",
+        "title": "创建任务",
+        "link": "",
+        "full": false,
+        "affix": true,
+        "noCache": true,
+        "activeMenu": "/index"
+      }
+    },
+    {
+      "path": "/logPage/:flag",
+      "name": "logPage",
+      "component": "taais/homePage/logPage",
+      "hidden": true,
+      "meta": {
+        "icon": "HomeFilled",
+        "title": "日志",
+        "link": "",
+        "full": false,
+        "affix": true,
+        "noCache": true,
+        "activeMenu": "/index"
+      }
+    },
+    {
+      "path": "/trainResult",
+      "name": "trainResult",
+      "component": "taais/homePage/trainResult",
+      "hidden": true,
+      "meta": {
+        "icon": "HomeFilled",
+        "title": "结果",
+        "link": "",
+        "full": false,
+        "affix": true,
+        "noCache": true,
+        "activeMenu": "/index"
+      }
+    },
     {
       "path": "/system/dict-data/index/:dictId",
       "name": "dictData",
       "component": "system/dict/data",
       "hidden": true,
       "meta": {
-        "icon": "",
+        "icon": "data",
         "title": "字典数据",
         "activeMenu": "/system/dict",
         "link": "",
@@ -36,7 +81,7 @@
       "component": "tool/gen/editGenTable",
       "hidden": true,
       "meta": {
-        "icon": "",
+        "icon": "data",
         "title": "编辑生成配置",
         "activeMenu": "/tool/gen",
         "link": "",
@@ -44,21 +89,6 @@
         "affix": false,
         "noCache": true
       }
-    },
-    {
-      "path": "/system/role-auth/user/:roleId",
-      "name": "AuthUser",
-      "component": "system/role/authUser",
-      "hidden": true,
-      "meta": {
-        "icon": "",
-        "title": "分配用户",
-        "activeMenu": "/system/role",
-        "link": "",
-        "full": false,
-        "affix": false,
-        "noCache": true
-      }
     }
   ],
   "msg": "成功"

+ 4 - 11
src/typings/ProForm.d.ts

@@ -33,6 +33,7 @@ declare namespace ProForm {
     | 'time-select'
     | 'transfer' // label不显示 使用插槽吧
     | 'icon' // 图标
+    | 'tree'
   interface FormOptions {
     inline?: boolean
     labelWidth?: string | number
@@ -40,6 +41,7 @@ declare namespace ProForm {
     disabled?: boolean // 不可编辑
     hasFooter?: boolean // 是否显示底部操作按钮
     labelSuffix?: ': ' | string
+    showSubmitButton?: boolean
     showResetButton?: boolean // 是否展示重置按钮
     showCancelButton?: boolean // 是否展示取消按钮
     submitButtonText?: string
@@ -113,16 +115,7 @@ declare namespace ProForm {
     checkStrictly?: boolean // 可选
     renderAfterExpand?: boolean // 可选
     controlsPosition?: 'left' | 'right' // 可选
-    onChange?: (value: any) => void
-    onSelect?: (value: any) => void
-    onRemove?: (value: any) => void
-    onClear?: () => void
-    onFocus?: () => void
-    onBlur?: () => void
-    onInput?: (value: any) => void
-    onSearch?: (value: any) => void
-    onVisibleChange?: (value: any) => void
-    onExpand?: (value: any) => void
-    onCheck?: (value: any) => void
+    defaultExpandAll?: boolean
+    showCheckbox?: boolean
   }
 }

+ 574 - 0
src/views/taais/homePage/createTask.vue

@@ -0,0 +1,574 @@
+<template>
+  <div class="createTask-container">
+    <h3 class="title">{{ title }}</h3>
+    <h4 class="title2" v-if="pageIndex === 4">训练算法</h4>
+    <ProForm :items-options="items" :form-options="_options" :model="model">
+      <template #transfer1="{ formModel }">
+        <el-transfer filterable v-model="formModel.transfer1" :data="dataT" />
+      </template>
+      <template #username1="{ formModel }">
+        <el-input v-model="formModel.username1" />
+      </template>
+    </ProForm>
+    <el-button class="btn back" v-if="pageIndex === 1 || pageIndex === 7" @click="onReturn()"> 返回 </el-button>
+    <el-button class="btn back" v-else @click="onBack()"> 上一步 </el-button>
+    <el-button class="btn next" type="success" @click="onNext()"> {{ nextBtnText }} </el-button>
+  </div>
+</template>
+<script setup lang="tsx" name="createTask">
+import { ref, ComputedRef, computed, watch } from 'vue'
+import ProForm from '@/components/ProForm/index.vue'
+import { useRouter } from 'vue-router'
+let model = {
+  parameter1: 'yolov8n.pt',
+  parameter2: 'yolov8n.yaml',
+  parameter3: '100',
+  parameter4: 'true',
+  parame1: '0.25',
+  parame2: '0.7',
+  parame3: '300',
+  parame4: 'false'
+}
+const router = useRouter()
+let pageIndex = ref<number>(1)
+let title = ref('目标精准捕获任务选择')
+let nextBtnText = ref('下一步')
+watch(
+  () => pageIndex.value,
+  value => {
+    switch (value) {
+      case 1:
+        title.value = '任务创建:目标精准捕获任务选择'
+        break
+      case 2:
+        title.value = '任务创建:训练数据选择'
+        break
+      case 3:
+        title.value = '任务创建:训练数据预处理'
+        break
+      case 4:
+        title.value = '任务创建:训练参数设置'
+        break
+      case 5:
+        title.value = '任务创建:推理数据选择'
+        break
+      case 6:
+        title.value = '任务创建:推理数据预处理'
+        nextBtnText.value = '下一步'
+        break
+      case 7:
+        title.value = '任务创建:推理参数设置'
+        nextBtnText.value = '提交'
+        break
+      default:
+        break
+    }
+  },
+  { immediate: true }
+)
+const dataT = [
+  {
+    key: 1,
+    label: '社么',
+    disabled: false
+  },
+  {
+    key: 2,
+    label: 'wan',
+    disabled: false
+  },
+  {
+    key: 3,
+    label: '伊尔',
+    disabled: true
+  }
+]
+const enumData = [
+  {
+    label: '选项1',
+    value: '1'
+  },
+  {
+    label: '选项2',
+    value: '2'
+  },
+  {
+    label: '选项3',
+    value: '3'
+  }
+]
+const data1 = [
+  {
+    label: '训练',
+    children: [
+      {
+        label: '训练数据选择',
+        children: []
+      },
+      {
+        label: '训练数据预处理',
+        children: []
+      },
+      {
+        label: '训练',
+        children: []
+      }
+    ]
+  },
+  {
+    label: '推理',
+    children: [
+      {
+        label: '推理数据选择',
+        children: []
+      },
+      {
+        label: '推理数据预处理',
+        children: []
+      },
+      {
+        label: '推理',
+        children: []
+      }
+    ]
+  }
+]
+const defaultProps = {
+  children: 'children',
+  label: 'label'
+}
+const _options: ComputedRef<ProForm.FormOptions> = computed(() => {
+  const form = {
+    labelWidth: 120,
+    hasFooter: true,
+    disabled: false,
+
+    showNextButton: true
+  }
+  return Object.assign(form)
+})
+let items: ProForm.ItemsOptions[] = [
+  {
+    formItemOptions: {
+      label: '任务名称',
+      prop: 'taskName',
+      span: 12,
+      show: () => {
+        return pageIndex.value === 1 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'input',
+      clearable: true,
+      placeholder: '请输入任务名称'
+    }
+  },
+  {
+    formItemOptions: {
+      label: '任务选择',
+      prop: 'tree',
+      show: () => {
+        return pageIndex.value === 1 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'tree',
+      enum: data1,
+      props: defaultProps,
+      style: 'max-width: 600px',
+      defaultExpandAll: true,
+      showCheckbox: true
+    }
+  },
+  {
+    formItemOptions: {
+      label: '选择训练数据',
+      prop: 'transfer1',
+      show: () => {
+        return pageIndex.value === 2 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'slot',
+      filterable: true
+    }
+  },
+  {
+    formItemOptions: {
+      label: '增强算法',
+      prop: 'select',
+      span: 14,
+      show: () => {
+        return pageIndex.value === 3 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'select',
+      enum: enumData
+    }
+  },
+  {
+    formItemOptions: {
+      label: '增强模型',
+      prop: 'select',
+      span: 14,
+      show: () => {
+        return pageIndex.value === 3 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'select',
+      enum: enumData
+    }
+  },
+  {
+    formItemOptions: {
+      label: '参数1',
+      prop: 'parameter',
+      span: 14,
+      show: () => {
+        return pageIndex.value === 3 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'input',
+      clearable: true,
+      placeholder: '请输入参数1'
+    }
+  },
+  {
+    formItemOptions: {
+      label: '参数2',
+      prop: 'parameter',
+      span: 14,
+      show: () => {
+        return pageIndex.value === 3 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'input',
+      clearable: true,
+      placeholder: '请输入参数2'
+    }
+  },
+  {
+    formItemOptions: {
+      label: '参数3',
+      prop: 'parameter',
+      span: 14,
+      show: () => {
+        return pageIndex.value === 3 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'input',
+      clearable: true,
+      placeholder: '请输入参数3'
+    }
+  },
+  {
+    formItemOptions: {
+      label: '参数4',
+      prop: 'parameter',
+      span: 14,
+      show: () => {
+        return pageIndex.value === 3 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'input',
+      clearable: true,
+      placeholder: '请输入参数4'
+    }
+  },
+  {
+    formItemOptions: {
+      label: '训练算法',
+      prop: 'select',
+      span: 14,
+      show: () => {
+        return pageIndex.value === 4 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'select',
+      enum: enumData
+    }
+  },
+  {
+    formItemOptions: {
+      label: '预训练模型权重文件路径',
+      prop: 'parameter1',
+      labelWidth: 180,
+      span: 14,
+      show: () => {
+        return pageIndex.value === 4 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'input',
+      clearable: true,
+      placeholder: '请输入参数1'
+    }
+  },
+  {
+    formItemOptions: {
+      label: '模型结构配置文件路径',
+      prop: 'parameter2',
+      labelWidth: 180,
+      span: 14,
+      show: () => {
+        return pageIndex.value === 4 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'input',
+      clearable: true,
+      placeholder: '请输入参数2'
+    }
+  },
+  {
+    formItemOptions: {
+      label: '训练轮数',
+      prop: 'parameter3',
+      labelWidth: 180,
+      span: 14,
+      show: () => {
+        return pageIndex.value === 4 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'input',
+      clearable: true,
+      placeholder: '请输入参数3'
+    }
+  },
+  {
+    formItemOptions: {
+      label: '余弦学习率调度器',
+      prop: 'parameter4',
+      labelWidth: 180,
+      span: 14,
+      show: () => {
+        return pageIndex.value === 4 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'input',
+      clearable: true,
+      placeholder: '请输入参数4'
+    }
+  },
+  {
+    formItemOptions: {
+      label: '选择推理数据',
+      prop: 'transfer1',
+      show: () => {
+        return pageIndex.value === 5 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'slot',
+      filterable: true
+    }
+  },
+  {
+    formItemOptions: {
+      label: '预处理算法',
+      prop: 'select',
+      span: 14,
+      show: () => {
+        return pageIndex.value === 6 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'select',
+      enum: enumData
+    }
+  },
+  {
+    formItemOptions: {
+      label: '预处理模型',
+      prop: 'select',
+      span: 14,
+      show: () => {
+        return pageIndex.value === 6 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'select',
+      enum: enumData
+    }
+  },
+  {
+    formItemOptions: {
+      label: '参数1',
+      prop: 'taskName',
+      span: 12,
+      show: () => {
+        return pageIndex.value === 6 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'input',
+      clearable: true,
+      placeholder: '请输入参数1'
+    }
+  },
+  {
+    formItemOptions: {
+      label: '参数2',
+      prop: 'taskName',
+      span: 12,
+      show: () => {
+        return pageIndex.value === 6 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'input',
+      clearable: true,
+      placeholder: '请输入参数2'
+    }
+  },
+  {
+    formItemOptions: {
+      label: '参数3',
+      prop: 'taskName',
+      span: 12,
+      show: () => {
+        return pageIndex.value === 6 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'input',
+      clearable: true,
+      placeholder: '请输入参数3'
+    }
+  },
+  {
+    formItemOptions: {
+      label: '参数4',
+      prop: 'taskName',
+      span: 12,
+      show: () => {
+        return pageIndex.value === 6 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'input',
+      clearable: true,
+      placeholder: '请输入参数4'
+    }
+  },
+  {
+    formItemOptions: {
+      label: '训练算法',
+      prop: 'select',
+      span: 14,
+      show: () => {
+        return pageIndex.value === 7 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'select',
+      enum: enumData
+    }
+  },
+  {
+    formItemOptions: {
+      label: '训练模型',
+      prop: 'select',
+      span: 14,
+      show: () => {
+        return pageIndex.value === 7 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'select',
+      enum: enumData
+    }
+  },
+  {
+    formItemOptions: {
+      label: '目标置信度阈值',
+      prop: 'parame1',
+      labelWidth: 180,
+      span: 14,
+      show: () => {
+        return pageIndex.value === 7 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'input',
+      clearable: true,
+      placeholder: '请输入参数1'
+    }
+  },
+  {
+    formItemOptions: {
+      label: '非极大值抑制的IoU阈值',
+      prop: 'parame2',
+      labelWidth: 180,
+      span: 14,
+      show: () => {
+        return pageIndex.value === 7 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'input',
+      clearable: true,
+      placeholder: '请输入参数2'
+    }
+  },
+  {
+    formItemOptions: {
+      label: '测试图片最大检测器数',
+      prop: 'parame3',
+      labelWidth: 180,
+      span: 14,
+      show: () => {
+        return pageIndex.value === 7 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'input',
+      clearable: true,
+      placeholder: '请输入参数3'
+    }
+  },
+  {
+    formItemOptions: {
+      label: '使用半精度推理(FP16)',
+      prop: 'parame4',
+      labelWidth: 180,
+      span: 14,
+      show: () => {
+        return pageIndex.value === 7 ? true : false
+      }
+    },
+    compOptions: {
+      elTagName: 'input',
+      clearable: true,
+      placeholder: '请输入参数4'
+    }
+  }
+]
+const onReturn = () => {
+  router.push(`/index`)
+}
+let flag = ref<number>(0) //跳转到日志页面的flag,0为训练日志、1为推理日志
+const onNext = () => {
+  if (pageIndex.value === 7) {
+    router.push(`/logPage/${flag.value}`)
+  } else {
+    pageIndex.value++
+  }
+}
+const onBack = () => {
+  if (pageIndex.value === 1) return
+  pageIndex.value--
+}
+</script>
+<style scoped lang="scss">
+@import './index.scss';
+</style>

+ 77 - 0
src/views/taais/homePage/index.scss

@@ -0,0 +1,77 @@
+.home-container {
+  height: 100%;
+  min-height: 550px;
+}
+%box-basic {
+  width: 70%;
+  height: 700px;
+  padding: 20px;
+  margin: 0 auto;
+  border-radius: 20px;
+  box-shadow: inset 0 0 5px 1px #8b8a8a;
+}
+.createTask-container {
+  @extend %box-basic;
+
+  position: relative;
+  .title {
+    margin: 20px;
+  }
+  .title2 {
+    text-align: center;
+  }
+  .btn {
+    position: absolute;
+    bottom: 200px;
+
+    // bottom: 20px;
+  }
+  .back {
+    left: 200px;
+  }
+  .next {
+    right: 200px;
+  }
+}
+.logPage-container {
+  position: relative;
+
+  @extend %box-basic;
+  .btn {
+    position: absolute;
+    right: 100px;
+    bottom: 50px;
+  }
+  .log {
+    width: 80%;
+    height: 550px; /* 根据需要调整 */
+    padding: 10px;
+    margin-left: 100px;
+    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;
+    animation: fade-in 1s;
+  }
+
+  @keyframes fade-in {
+    from {
+      opacity: 0;
+    }
+    to {
+      opacity: 1;
+    }
+  }
+}
+.trainResult-container {
+  @extend %box-basic;
+  .table-box {
+    height: 650px;
+    margin-top: -15px;
+  }
+}

+ 125 - 0
src/views/taais/homePage/index.vue

@@ -0,0 +1,125 @@
+<template>
+  <div class="home-container">
+    <div class="table-box">
+      <ProTable
+        ref="proTable"
+        row-key="userId"
+        :data="taskDataList.data"
+        :indent="20"
+        :columns="columns"
+        :data-callback="dataCallback"
+        :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>
+    </div>
+  </div>
+</template>
+
+<script setup lang="tsx" name="homePage">
+import { onMounted, reactive, ref } from 'vue'
+import { User } from '@/api/interface'
+import ProTable from '@/components/ProTable/index.vue'
+import FormDialog from '@/components/DialogOld/form.vue'
+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 { getDictsApi } from '@/api/modules/system/dictData'
+onMounted(() => {
+  getTreeFilter()
+})
+
+// ProTable 实例
+const proTable = ref<ProTableInstance>()
+// 如果表格需要初始化请求参数,直接定义传给 ProTable(之后每次请求都会自动带上该参数,此参数更改之后也会一直带上,改变此参数会自动刷新表格数据)
+const initParam = reactive({ deptId: '' })
+
+// 获取 treeFilter 数据
+// 当 proTable 的 requestAuto 属性为 false,不会自动请求表格数据,等待 treeFilter 数据回来之后,更改 initParam.departmentId 的值,才会触发请求 proTable 数据
+const treeFilterData = ref<any>([])
+const getTreeFilter = async () => {
+  const { data } = await deptTreeSelectApi()
+  treeFilterData.value = data
+  initParam.deptId = treeFilterData.value[0].id
+}
+const dataCallback = (data: any) => {
+  return data
+}
+// 批量添加用户
+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[] = [
+    {
+      label: '任务名称',
+      placeholder: '请输入任务名称',
+      span: 12,
+      field: 'taskName',
+      rules: [{ required: true, message: '任务名称不能为空' }]
+    }
+  ]
+  const params = {
+    title,
+    width: 680,
+    isEdit: type !== 3,
+    fieldList: fieldList,
+    model: res,
+    api: type == 1 ? addUserApi : updateUserApi,
+    getTableList: proTable.value?.getTableList
+  }
+
+  formDialogRef.value?.openDialog(params)
+}
+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: '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)}
+    //     />
+    //   )
+    // }
+  },
+  { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
+])
+</script>

+ 54 - 0
src/views/taais/homePage/logPage.vue

@@ -0,0 +1,54 @@
+<template>
+  <div class="logPage-container">
+    <el-divider content-position="left">
+      <span style="font-size: 18px; font-weight: 700">{{ title }}</span>
+    </el-divider>
+    <div class="log">
+      <div class="p" v-for="(item, index) in logInfo" :key="index">{{ item }}</div>
+    </div>
+    <el-button type="success" class="btn" @click="onResult()"> 查看结果 </el-button>
+  </div>
+</template>
+<script setup lang="tsx" name="logPage">
+import { useRouter, useRoute } from 'vue-router'
+import { ref, watch, onMounted } from 'vue'
+import trainLog from '@/assets/mock/Untitled-1.json'
+import inferLog from '@/assets/mock/Untitled-2.json'
+const router = useRouter()
+const route = useRoute()
+let title = ref('')
+let logInfo = ref([] as string[])
+let infoList = ref([] as string[])
+const routeFlag = route.params.flag
+let timer = ref()
+// 根据flag确定是哪个值
+infoList.value = routeFlag === '0' ? trainLog : inferLog
+const info = () => {
+  let index = 0
+  timer.value = setInterval(() => {
+    if (index < infoList.value.length) {
+      logInfo.value.push(infoList.value[index])
+      index++
+    } else {
+      clearInterval(timer.value)
+    }
+  }, 500)
+}
+watch(
+  () => routeFlag,
+  value => {
+    title.value = value === '0' ? '训练日志' : '推理日志'
+  }
+)
+
+onMounted(() => {
+  info()
+})
+const onResult = () => {
+  router.push(`/trainResult`)
+}
+</script>
+
+<style scoped lang="scss">
+@import './index.scss';
+</style>

+ 56 - 0
src/views/taais/homePage/trainResult.vue

@@ -0,0 +1,56 @@
+<template>
+  <div class="trainResult-container">
+    <h4>算法运行及结果</h4>
+    <div class="table-box">
+      <ProTable
+        ref="proTable"
+        row-key="userId"
+        :indent="20"
+        :columns="columns"
+        :tool-button="false"
+        :data="tableData"
+        :request-auto="false"
+        :init-param="initParam"
+        :search-col="{ xs: 1, sm: 1, md: 2, lg: 3, xl: 3 }"
+      >
+      </ProTable>
+    </div>
+  </div>
+</template>
+<script setup lang="tsx" name="trainResult">
+import { onMounted, reactive, ref } from 'vue'
+import { User } from '@/api/interface'
+import ProTable from '@/components/ProTable/index.vue'
+import { ColumnProps, ProTableInstance } from '@/components/ProTable/interface'
+import { deptTreeSelectApi } from '@/api/modules/system/user'
+onMounted(() => {
+  getTreeFilter()
+})
+
+// ProTable 实例
+const proTable = ref<ProTableInstance>()
+// 如果表格需要初始化请求参数,直接定义传给 ProTable(之后每次请求都会自动带上该参数,此参数更改之后也会一直带上,改变此参数会自动刷新表格数据)
+const initParam = reactive({ deptId: '' })
+
+// 获取 treeFilter 数据
+// 当 proTable 的 requestAuto 属性为 false,不会自动请求表格数据,等待 treeFilter 数据回来之后,更改 initParam.departmentId 的值,才会触发请求 proTable 数据
+const treeFilterData = ref<any>([])
+const getTreeFilter = async () => {
+  const { data } = await deptTreeSelectApi()
+  treeFilterData.value = data
+  initParam.deptId = treeFilterData.value[0].id
+}
+let tableData = ref([])
+// 表格配置项
+const columns = reactive<ColumnProps<User.ResUserList>[]>([
+  { prop: 'userId', label: '' },
+  { prop: 'userId', label: '算法1' },
+  { prop: 'userName', label: '算法2' },
+  { prop: 'nickName', label: '算法3' },
+  { prop: 'dept.deptName', label: '算法4' }
+])
+</script>
+
+<style scoped lang="scss">
+@import './index.scss';
+</style>