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