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