houzhongjian
2024-12-05 2717813966ced88c6a1635663dd01b502158a1b8
提交 | 用户 | 时间
9ec4bd 1 <template>
2   <Dialog v-model="dialogVisible" :title="dialogTitle">
3     <el-form
4       class="-mb-15px"
5       :model="formData"
6       ref="formRef"
7       :inline="true"
8       :rules="formRules"
9       label-width="68px"
10       v-loading="formLoading"
11     >
12       <el-form-item style="width: 100%">
13         <el-divider content-position="left">模型信息</el-divider>
14       </el-form-item>
de019e 15       <el-row>
D 16         <el-col :span="24">
17           <el-form-item label="全类名" style="width: 100%" prop="className">
18             <el-input v-model="formData.className" placeholder=""/>
19           </el-form-item>
20         </el-col>
21       </el-row>
22       <el-row>
23         <el-col :span="24">
24           <el-form-item label="方法名" prop="methodName">
25             <el-select v-model="formData.methodName" @change="methodChange" style="width: 240px">
26               <el-option
27                 v-for="item in methodList"
28                 :key="item.id"
29                 :label="item.methodName"
30                 :value="item.methodName"
31               />
32             </el-select>
33           </el-form-item>
34         </el-col>
35       </el-row>
9ec4bd 36       <el-divider content-position="left">模型参数信息</el-divider>
22bece 37       <div style="display:flex;flex-direction: row;align-items: center;margin-bottom: 6px">
D 38         <el-button tag="a" :href="staticDir + '/template/模型参数导入模板.xlsx'" download="模型参数导入模板.xlsx" style="text-decoration: none;" type="primary" size="small" link>模板下载</el-button>
39         <el-upload
40           ref="uploadRef"
41           v-model:file-list="fileList"
42           :show-file-list="false"
43           :action="importUrl"
44           :auto-upload="true"
45           :disabled="formLoading"
46           :before-upload="beforeUpload"
47           :headers="uploadHeaders"
48           :on-error="submitFormError"
49           :on-success="submitFormSuccess"
50           accept=".xlsx"
51         >
52           <el-button type="primary" size="small" link>参数导入</el-button>
53         </el-upload>
54       </div>
de019e 55       <el-row v-for="(item,index) in datas" :key="index" :gutter="20">
D 56         <el-col :span="24">
9ec4bd 57           <el-form-item :label="'参数_' + (index)" required style="width: 100%">
de019e 58             <el-input type="textarea" :disabled="true" :rows="3" v-model="datas[index]" placeholder="" />
9ec4bd 59           </el-form-item>
60         </el-col>
61       </el-row>
62       <el-row v-if="hasModel" :gutter="20">
63         <el-col :span="20">
64           <el-form-item label="model" required style="width: 100%">
65             <el-input v-model="formData.model" placeholder="" />
66           </el-form-item>
67         </el-col>
68       </el-row>
69       <el-divider content-position="left">模型设置信息</el-divider>
de019e 70 <!--      <el-row :gutter="20">-->
D 71 <!--        <el-col :span="4">-->
72 <!--          <el-button type="primary" size="small" @click="addRow()">新增</el-button>-->
73 <!--        </el-col>-->
74 <!--      </el-row>-->
9ec4bd 75       <el-table :data="formData.modelSettings" border>
76         <el-table-column
77           prop=""
78           label="参数key"
79           align="center">
80           <template #default="scope">
de019e 81             <el-input size="small" v-model="scope.row.settingKey" :disabled="true" maxlength="50" clearable />
9ec4bd 82           </template>
83         </el-table-column>
84         <el-table-column
85           prop=""
22bece 86           label="参数名称"
D 87           align="center">
88           <template #default="scope">
89             <el-input size="small" v-model="scope.row.name" :disabled="true" maxlength="50" clearable />
90           </template>
91         </el-table-column>
92         <el-table-column
93           prop=""
9ec4bd 94           label="参数value"
95           align="center">
96           <template #default="scope">
627a6b 97             <el-input size="small" v-model="scope.row.settingValue" :disabled="scope.row.settingKey === 'pyFile'" maxlength="50" clearable />
9ec4bd 98           </template>
99         </el-table-column>
22bece 100 <!--        <el-table-column label="操作" fixed="right" header-align="center" align="center" width="100">-->
D 101 <!--          <template #default="scope">-->
102 <!--            <el-button-->
103 <!--              @click="deleteRow(scope.$index)"-->
104 <!--              key="danger"-->
105 <!--              type="danger"-->
106 <!--              :disabled="scope.row.settingKey === 'pyFile'"-->
107 <!--              link-->
108 <!--            >删除</el-button>-->
109 <!--          </template>-->
110 <!--        </el-table-column>-->
9ec4bd 111       </el-table>
112       <el-divider content-position="left">模型运行结果</el-divider>
113       <el-input v-model="modelRunResult" placeholder="" rows="4" type="textarea" />
114       <div style="display: flex;flex-direction: row;justify-content: end;margin-top: 16px">
115         <el-button :loading="modelRunloading" type="primary" @click="modelRun()">运行</el-button>
116       </div>
117     </el-form>
118   </Dialog>
119 </template>
120 <script lang="ts" setup>
aff5c9 121   import * as MpkApi from '@/api/model/mpk/mpk'
9ec4bd 122   import {FormRules} from "element-plus";
123   import {getAccessToken, getTenantId} from "@/utils/auth";
50af0d 124   const staticDir = ref(import.meta.env.VITE_STATIC_DIR)
9ec4bd 125
126   const { t } = useI18n() // 国际化
127   const message = useMessage() // 消息弹窗
128
129   const dialogVisible = ref(false) // 弹窗的是否展示
130   const dialogTitle = ref('模型运行') // 弹窗的标题
131
132   const formData = reactive({
2bff3e 133     pyName: '',
9ec4bd 134     className: '',
135     methodName: '',
de019e 136     uuids: [],
9ec4bd 137     modelSettings: [],
138     model: undefined
139   })
de019e 140
D 141   const datas = ref([])
9ec4bd 142
143   // 模型方法下拉列表
144   const methodList = ref([])
145   const hasModel = ref(false)
146
147   /** 打开弹窗 */
148   const open = async (row) => {
149     dialogVisible.value = true
150     formData.className = row.pkgName + '.impl.' + row.pyName + 'Impl';
2bff3e 151     formData.pyName = row.pyName;
9ec4bd 152     const mpk = await MpkApi.getMpk(row.id)
153     methodList.value = mpk.modelMethods
154     formData.methodName = mpk.modelMethods[0].methodName
de019e 155     datas.value = []
D 156     formData.uuids = [];
9ec4bd 157     for (let i = 0 ; i < mpk.modelMethods[0].dataLength ; i++) {
de019e 158      datas.value[i] = '[[]]';
D 159      formData.uuids[i] = '';
9ec4bd 160     }
161     hasModel.value = mpk.modelMethods[0].model === 1
631da1 162
D 163     // 回显参数
164     if (mpk.modelMethods[0].methodSettings && mpk.modelMethods[0].methodSettings.length > 0) {
165       formData.modelSettings = mpk.modelMethods[0].methodSettings.map(e => {
de019e 166         e.settingValue = e.value;
D 167         return e;
631da1 168       })
D 169     }
9ec4bd 170   }
171   defineExpose({ open }) // 提供 open 方法,用于打开弹窗
172
173   const formRules = reactive<FormRules>({
174     methodName: [
175       {required: true, message: '方法名不能为空', trigger: 'blur'}
176     ],
177     className: [
178       {required: true, message: '全类名不能为空', trigger: 'blur'}
627a6b 179     ],
D 180     model: [
181       {required: true, message: 'model不能为空', trigger: 'blur'}
9ec4bd 182     ]
183   })
184
185   const addRow = function () {
186     formData.modelSettings.push({
187       settingKey: '',
188       settingValue: ''
189     })
190   }
191   const deleteRow = function (index) {
192     formData.modelSettings.splice(index, 1)
193   }
194   const methodChange = function (value) {
de019e 195     datas.value = []
D 196     formData.uuids = [];
631da1 197     var method = methodList.value.find(e => e.methodName === value);
D 198     for (let i = 0 ; i < method?.dataLength ; i++) {
de019e 199       datas.value[i] = '[[]]';
D 200       formData.uuids[i] = '';
9ec4bd 201     }
631da1 202     hasModel.value = method?.model === 1
D 203     // 回显参数
204     if (method.methodSettings && method.methodSettings.length > 0) {
205       formData.modelSettings = method.methodSettings.map(e => {
de019e 206         e.settingValue = e.value;
D 207         return e;
631da1 208       })
D 209     }else {
210       formData.modelSettings = []
211     }
9ec4bd 212   }
213
214   const fileList = ref([]) // 文件列表
215   const importUrl =
216     import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL + '/model/mpk/api/import'
217   const formLoading = ref(false) // 表单的加载中
218   const uploadHeaders = ref() // 上传 Header 头
219   /** 上传错误提示 */
220   const submitFormError = (): void => {
221     message.error('导入失败,请检查导入文件!')
222     formLoading.value = false
223   }
224   const submitFormSuccess = (response: any) => {
de019e 225     try {
D 226       if (response.code !== 0) {
227         message.error(response.msg)
228         return
229       }
230       const data = response.data;
231       if (datas.value.length > data.length) {
232         message.error("导入数据长度为" + data.length + ",应≥" + datas.value.length)
233         return
234       }
235       for (let i = 0; i < datas.value.length; i++) {
236         datas.value[i] = data[i].data
237         formData.uuids[i] = data[i].uuid;
238       }
239       message.success('导入成功')
240     } finally {
9ec4bd 241       formLoading.value = false
242     }
243   }
244   const beforeUpload = function (file) {
245     // 提交请求
246     uploadHeaders.value = {
247       Authorization: 'Bearer ' + getAccessToken(),
248       'tenant-id': getTenantId()
249     }
250     formLoading.value = true
251     return true;
252   }
253
254   // 模型运行结果
255   const modelRunResult = ref('')
256   // 模型运行loading
257   const modelRunloading = ref(false)
258   // 表单 Ref
259   const formRef = ref()
260   // 运行
261   const modelRun = async () => {
afc4d5 262     modelRunResult.value = ''
9ec4bd 263 // 校验表单
264     if (!formRef) return
265     const valid = await formRef.value.validate()
266     if (!valid) return
627a6b 267
D 268     if (hasModel.value) {
269       debugger
270       if (!formData.model || formData.model === '') {
271         message.error("model为必填项!")
272         return
273       }
274
275       try {
276         JSON.parse(formData.model)
277       } catch (e) {
278         message.error("model参数异常!")
279         return
280       }
281
282     }
283
284
9ec4bd 285     // 提交请求
286     modelRunloading.value = true
287     try {
288       const data = {
289         ...formData
290       }
291
292       //处理modelSettings
de019e 293       // let settingsPredict = {};
D 294       // data.modelSettings.forEach(e => {
295       //   settingsPredict[e.settingKey] = e.settingValue;
296       // })
297       // data.modelSettings = settingsPredict
9ec4bd 298       data.hasModel = hasModel.value
299       if (data.hasModel && data.model) {
de019e 300         data.model = JSON.parse(data.model)
9ec4bd 301       }else {
302         data.model = undefined
303       }
304
305       modelRunResult.value = await MpkApi.modelRun(data)
306       message.success('运行成功')
307     } finally {
308       modelRunloading.value = false
309     }
310   }
311 </script>