From 8d139bf079918171f140a53004ad4221937e3ad0 Mon Sep 17 00:00:00 2001
From: 潘志宝 <979469083@qq.com>
Date: 星期五, 21 三月 2025 14:48:18 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 src/views/model/mpk/file/MpkRun.vue |  271 +++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 186 insertions(+), 85 deletions(-)

diff --git a/src/views/model/mpk/file/MpkRun.vue b/src/views/model/mpk/file/MpkRun.vue
index 6b0111b..908d883 100644
--- a/src/views/model/mpk/file/MpkRun.vue
+++ b/src/views/model/mpk/file/MpkRun.vue
@@ -12,46 +12,50 @@
       <el-form-item style="width: 100%">
         <el-divider content-position="left">模型信息</el-divider>
       </el-form-item>
-      <el-form-item label="全类名" style="width: 90%" prop="className">
-        <el-input v-model="formData.className" placeholder=""/>
-      </el-form-item>
-      <el-form-item label="方法名" prop="methodName">
-        <el-select v-model="formData.methodName" @change="methodChange" style="width: 240px">
-          <el-option
-            v-for="item in methodList"
-            :key="item.id"
-            :label="item.methodName"
-            :value="item.methodName"
-          />
-        </el-select>
-      </el-form-item>
-      <el-divider content-position="left">模型参数信息</el-divider>
-      <el-row :gutter="20">
-        <el-col :span="2" style="margin-bottom: 10px;margin-left: 20px">
-          <el-button tag="a" href="/template/模型参数导入模板.xlsx" download="模型参数导入模板.xlsx" style="text-decoration: none;" type="primary" size="small" link>模板下载</el-button>
-        </el-col>
-        <el-col :span="2" style="margin-bottom: 10px;">
-          <el-upload
-            ref="uploadRef"
-            v-model:file-list="fileList"
-            :show-file-list="false"
-            :action="importUrl"
-            :auto-upload="true"
-            :disabled="formLoading"
-            :before-upload="beforeUpload"
-            :headers="uploadHeaders"
-            :on-error="submitFormError"
-            :on-success="submitFormSuccess"
-            accept=".xlsx"
-          >
-            <el-button type="primary" size="small" link>参数导入</el-button>
-          </el-upload>
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="全类名" style="width: 100%" prop="className">
+            <el-input v-model="formData.className" placeholder=""/>
+          </el-form-item>
         </el-col>
       </el-row>
-      <el-row v-for="(item,index) in formData.datas" :key="index" :gutter="20">
-        <el-col :span="20">
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="方法名" prop="methodName">
+            <el-select v-model="formData.methodName" @change="methodChange" style="width: 240px">
+              <el-option
+                v-for="item in methodList"
+                :key="item.id"
+                :label="item.methodName"
+                :value="item.methodName"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-divider content-position="left">模型参数信息</el-divider>
+      <div style="display:flex;flex-direction: row;align-items: center;margin-bottom: 6px">
+        <el-button tag="a" :href="staticDir + '/template/模型参数导入模板.xlsx'" download="模型参数导入模板.xlsx" style="text-decoration: none;" type="primary" size="small" link>模板下载</el-button>
+        <el-upload
+          ref="uploadRef"
+          v-model:file-list="fileList"
+          :show-file-list="false"
+          :action="importUrl"
+          :auto-upload="true"
+          :disabled="formLoading"
+          :before-upload="beforeUpload"
+          :headers="uploadHeaders"
+          :on-error="submitFormError"
+          :on-success="submitFormSuccess"
+          accept=".xlsx"
+        >
+          <el-button type="primary" size="small" link>参数导入</el-button>
+        </el-upload>
+      </div>
+      <el-row v-for="(item,index) in datas" :key="index" :gutter="20">
+        <el-col :span="24">
           <el-form-item :label="'参数_' + (index)" required style="width: 100%">
-            <el-input v-model="formData.datas[index]" placeholder="" />
+            <el-input type="textarea" :disabled="true" :rows="3" v-model="datas[index]" placeholder="" />
           </el-form-item>
         </el-col>
       </el-row>
@@ -63,18 +67,26 @@
         </el-col>
       </el-row>
       <el-divider content-position="left">模型设置信息</el-divider>
-      <el-row :gutter="20">
-        <el-col :span="4">
-          <el-button type="primary" size="small" @click="addRow()">新增</el-button>
-        </el-col>
-      </el-row>
+<!--      <el-row :gutter="20">-->
+<!--        <el-col :span="4">-->
+<!--          <el-button type="primary" size="small" @click="addRow()">新增</el-button>-->
+<!--        </el-col>-->
+<!--      </el-row>-->
       <el-table :data="formData.modelSettings" border>
         <el-table-column
           prop=""
           label="参数key"
           align="center">
           <template #default="scope">
-            <el-input size="small" v-model="scope.row.settingKey" maxlength="50" clearable />
+            <el-input size="small" v-model="scope.row.settingKey" :disabled="true" maxlength="50" clearable />
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop=""
+          label="参数名称"
+          align="center">
+          <template #default="scope">
+            <el-input size="small" v-model="scope.row.name" :disabled="true" maxlength="50" clearable />
           </template>
         </el-table-column>
         <el-table-column
@@ -82,21 +94,23 @@
           label="参数value"
           align="center">
           <template #default="scope">
-            <el-input size="small" v-model="scope.row.settingValue" maxlength="50" clearable />
+            <el-input size="small" v-model="scope.row.settingValue" :disabled="scope.row.settingKey === 'pyFile'" maxlength="50" clearable />
           </template>
         </el-table-column>
-        <el-table-column label="操作" fixed="right" header-align="center" align="center" width="100">
-          <template #default="scope">
-            <el-button
-              @click="deleteRow(scope.$index)"
-              key="danger"
-              type="danger"
-              link
-            >删除</el-button>
-          </template>
-        </el-table-column>
+<!--        <el-table-column label="操作" fixed="right" header-align="center" align="center" width="100">-->
+<!--          <template #default="scope">-->
+<!--            <el-button-->
+<!--              @click="deleteRow(scope.$index)"-->
+<!--              key="danger"-->
+<!--              type="danger"-->
+<!--              :disabled="scope.row.settingKey === 'pyFile'"-->
+<!--              link-->
+<!--            >删除</el-button>-->
+<!--          </template>-->
+<!--        </el-table-column>-->
       </el-table>
       <el-divider content-position="left">模型运行结果</el-divider>
+      <el-button type="primary" size="small" link @click="saveModel" v-if="showSaveModel && formData.methodName === 'train'">下载模型(.miail)</el-button>
       <el-input v-model="modelRunResult" placeholder="" rows="4" type="textarea" />
       <div style="display: flex;flex-direction: row;justify-content: end;margin-top: 16px">
         <el-button :loading="modelRunloading" type="primary" @click="modelRun()">运行</el-button>
@@ -108,6 +122,8 @@
   import * as MpkApi from '@/api/model/mpk/mpk'
   import {FormRules} from "element-plus";
   import {getAccessToken, getTenantId} from "@/utils/auth";
+  import download from "@/utils/download";
+  const staticDir = ref(import.meta.env.VITE_STATIC_DIR)
 
   const { t } = useI18n() // 国际化
   const message = useMessage() // 消息弹窗
@@ -119,10 +135,12 @@
     pyName: '',
     className: '',
     methodName: '',
-    datas: [],
+    uuids: [],
     modelSettings: [],
     model: undefined
   })
+
+  const datas = ref([])
 
   // 模型方法下拉列表
   const methodList = ref([])
@@ -136,21 +154,22 @@
     const mpk = await MpkApi.getMpk(row.id)
     methodList.value = mpk.modelMethods
     formData.methodName = mpk.modelMethods[0].methodName
-    formData.datas = []
+    datas.value = []
+    formData.uuids = [];
     for (let i = 0 ; i < mpk.modelMethods[0].dataLength ; i++) {
-     formData.datas[i] = '[[]]'
+     datas.value[i] = '[[]]';
+     formData.uuids[i] = '';
     }
     hasModel.value = mpk.modelMethods[0].model === 1
 
     // 回显参数
     if (mpk.modelMethods[0].methodSettings && mpk.modelMethods[0].methodSettings.length > 0) {
       formData.modelSettings = mpk.modelMethods[0].methodSettings.map(e => {
-        return {
-          settingKey: e.settingKey,
-          settingValue: e.value
-        }
+        e.settingValue = e.value;
+        return e;
       })
     }
+
   }
   defineExpose({ open }) // 提供 open 方法,用于打开弹窗
 
@@ -160,6 +179,9 @@
     ],
     className: [
       {required: true, message: '全类名不能为空', trigger: 'blur'}
+    ],
+    model: [
+      {required: true, message: 'model不能为空', trigger: 'blur'}
     ]
   })
 
@@ -173,19 +195,19 @@
     formData.modelSettings.splice(index, 1)
   }
   const methodChange = function (value) {
-    formData.datas = []
+    datas.value = []
+    formData.uuids = [];
     var method = methodList.value.find(e => e.methodName === value);
     for (let i = 0 ; i < method?.dataLength ; i++) {
-      formData.datas[i] = '[[]]'
+      datas.value[i] = '[[]]';
+      formData.uuids[i] = '';
     }
     hasModel.value = method?.model === 1
     // 回显参数
     if (method.methodSettings && method.methodSettings.length > 0) {
       formData.modelSettings = method.methodSettings.map(e => {
-        return {
-          settingKey: e.settingKey,
-          settingValue: e.value
-        }
+        e.settingValue = e.value;
+        return e;
       })
     }else {
       formData.modelSettings = []
@@ -203,17 +225,24 @@
     formLoading.value = false
   }
   const submitFormSuccess = (response: any) => {
-    if (response.code !== 0) {
-      message.error(response.msg)
+    try {
+      if (response.code !== 0) {
+        message.error(response.msg)
+        return
+      }
+      const data = response.data;
+      if (datas.value.length > data.length) {
+        message.error("导入数据长度为" + data.length + ",应≥" + datas.value.length)
+        return
+      }
+      for (let i = 0; i < datas.value.length; i++) {
+        datas.value[i] = data[i].data
+        formData.uuids[i] = data[i].uuid;
+      }
+      message.success('导入成功')
+    } finally {
       formLoading.value = false
-      return
     }
-    const datas = response.data;
-    for (let i=0;i<formData.datas.length;i++) {
-      formData.datas[i] = datas[i]
-    }
-    message.success('导入成功')
-    formLoading.value = false
   }
   const beforeUpload = function (file) {
     // 提交请求
@@ -233,10 +262,30 @@
   const formRef = ref()
   // 运行
   const modelRun = async () => {
-// 校验表单
+    modelRunResult.value = ''
+    showSaveModel.value = false
+  // 校验表单
     if (!formRef) return
     const valid = await formRef.value.validate()
     if (!valid) return
+
+    if (hasModel.value) {
+      debugger
+      if (!formData.model || formData.model === '') {
+        message.error("model为必填项!")
+        return
+      }
+
+      try {
+        JSON.parse(formData.model)
+      } catch (e) {
+        message.error("model参数异常!")
+        return
+      }
+
+    }
+
+
     // 提交请求
     modelRunloading.value = true
     try {
@@ -245,23 +294,75 @@
       }
 
       //处理modelSettings
-      let settingsPredict = {};
-      data.modelSettings.forEach(e => {
-        settingsPredict[e.settingKey] = e.settingValue;
-      })
-      data.modelSettings = settingsPredict
+      // let settingsPredict = {};
+      // data.modelSettings.forEach(e => {
+      //   settingsPredict[e.settingKey] = e.settingValue;
+      // })
+      // data.modelSettings = settingsPredict
       data.hasModel = hasModel.value
       if (data.hasModel && data.model) {
-        data.model = {model_path:data.model}
+        data.model = JSON.parse(data.model)
       }else {
         data.model = undefined
       }
 
-      modelRunResult.value = await MpkApi.modelRun(data)
-      modelRunloading.value = false
+      let result = await MpkApi.modelRun(data)
+
+      modelRunResult.value = result;
       message.success('运行成功')
+      // 训练方法
+      if (formData.methodName === 'train') {
+        result = JSON.parse(result);
+        // 返回结果正确
+        if (result?.status_code === '100' && result?.models?.model_path) {
+          // 有预测方法
+          if (methodList.value.some(e => e.methodName === 'predict')) {
+            saveModelParams.modelResult = result
+            saveModelParams.model = result?.models
+            showSaveModel.value = true
+          }
+        }
+      }
     } finally {
       modelRunloading.value = false
     }
   }
+
+  const showSaveModel = ref(false)
+
+  const saveModelParams = reactive({
+    pyName: '',
+    className: '',
+    methodName: '',
+    uuids: [],
+    modelSettings: [],
+    predModelSettings: [],
+    hasModel: false,
+    model: undefined,
+    modelResult: undefined,
+    dataLength: undefined,
+    resultKey: undefined,
+  })
+
+  const saveModel = async () => {
+    saveModelParams.className = formData.className
+    saveModelParams.pyName = formData.pyName
+    saveModelParams.modelSettings = formData.modelSettings
+    const predMethod = methodList.value.find(e => e.methodName === 'predict');
+    saveModelParams.methodName = predMethod.methodName
+    saveModelParams.resultKey = predMethod.resultKey
+    //predModelSettings
+    if (predMethod.methodSettings && predMethod.methodSettings.length > 0) {
+      saveModelParams.predModelSettings = predMethod.methodSettings.map(e => {
+        e.settingValue = e.value;
+        return e;
+      })
+    }
+    saveModelParams.hasModel = predMethod.model === 1
+
+    saveModelParams.dataLength = predMethod.dataLength
+
+    const data = await MpkApi.saveModel(saveModelParams)
+    download.downloadFile(data, saveModelParams.pyName + '.miail')
+  }
 </script>

--
Gitblit v1.9.3