潘志宝
2024-11-22 df90c0c5cfa4de114798015b92120ad8ba8b4826
提交 | 用户 | 时间
67ea85 1 <template>
J 2   <Dialog v-model="dialogVisible" :title="dialogTitle" width="55%">
3     <el-form
4       ref="formRef"
5       v-loading="formLoading"
6       :model="formData"
7       :rules="formRules" label-width="100px">
8       <el-row>
9         <el-col :span="12">
10           <el-form-item label="指标编码" prop="itemNo">
11             <el-input v-model="formData.itemNo" disabled/>
12           </el-form-item>
13         </el-col>
14         <el-col :span="12">
15           <el-form-item label="指标名称" prop="itemName">
16             <el-input v-model="formData.itemName" placeholder="请输入指标名称"/>
17           </el-form-item>
18         </el-col>
19       </el-row>
20       <el-row>
21         <el-col :span="12">
22           <el-form-item label="指标分类" prop="itemCategory">
23             <el-select v-model="formData.itemCategory" clearable placeholder="请选择指标分类">
24               <el-option
25                 v-for="item in dataCategoryList"
26                 :key="item.id"
27                 :label="item.label"
28                 :value="item.id + ''"
29               />
30             </el-select>
31           </el-form-item>
32         </el-col>
33         <el-col :span="12">
34           <el-form-item label="时间粒度" prop="timeGranularity">
35             <el-select v-model="formData.timeGranularity" placeholder="请选择">
36               <el-option
37                 v-for="dict in getStrDictOptions(DICT_TYPE.TIME_GRANULARITY)"
38                 :key="dict.value"
39                 :label="dict.label"
40                 :value="dict.value"
41               />
42             </el-select>
43           </el-form-item>
44         </el-col>
45       </el-row>
46       <el-row>
47         <el-col :span="8">
48           <el-form-item label="指标精度" prop="precision">
49             <el-input v-model="formData.precision"/>
50           </el-form-item>
51         </el-col>
52         <el-col :span="8">
53           <el-form-item label="转换系数" prop="coefficient">
54             <el-input v-model="formData.coefficient"/>
55           </el-form-item>
56         </el-col>
57         <el-col :span="8">
58           <el-form-item label="数量单位" prop="unit">
59             <el-input v-model="formData.unit"/>
60           </el-form-item>
61         </el-col>
62       </el-row>
63       <el-row>
64         <el-col :span="24">
65           <el-form-item label="备注" prop="remark">
66             <el-input v-model="formData.remark" type="textarea" maxlength="100"/>
67           </el-form-item>
68         </el-col>
69       </el-row>
70       <el-row>
71         <el-col :span="24">
72           <el-form-item label="表达式">
73             <el-table :data="expressionList" border style="width: 100%">
74               <el-table-column type="index" align="center" width="60" label="序号"/>
75               <el-table-column prop="" label="左括号" width="100" align="center">
76                 <template #default="scope">
77                   <el-input size="small" v-model="scope.row.parenthesesLeft" placeholder="" readonly maxlength="10"/>
78                   <el-button size="small" @click="addParenthesesLeft(scope.$index, scope.row)">+</el-button>
79                   <el-button size="small" @click="removeParenthesesLeft(scope.$index, scope.row)">-</el-button>
80                 </template>
81               </el-table-column>
82               <el-table-column prop="" label="指标" align="center">
83                 <template #default="scope">
84                   <el-select size="mini" v-model="scope.row.itemNo" filterable placeholder="请选择">
85                     <el-option v-for="(item, index) in itemList"
86                                :key="index"
87                                :label="item.itemName"
88                                :value="item.itemNo"/>
89                   </el-select>
90                 </template>
91               </el-table-column>
92               <el-table-column prop="" label="运算值" align="center">
93                 <template #default="scope">
94                   <el-input size="mini" v-model="scope.row.itemNo" placeholder="运算值" clearable/>
95                 </template>
96               </el-table-column>
97               <el-table-column prop="" label="右括号" width="100" align="center">
98                 <template #default="scope">
99                   <el-input size="small" v-model="scope.row.parenthesesRight" placeholder="" readonly/>
100                     <el-button size="small" @click="addParenthesesRight(scope.$index, scope.row, ')')">+
101                     </el-button>
102                     <el-button size="small" @click="removeParenthesesRight(scope.$index, scope.row)">-
103                     </el-button>
104                 </template>
105               </el-table-column>
106               <el-table-column prop="" label="运算符" width="100" align="center">
107                 <template #default="scope">
108                   <el-select size="mini" v-model="scope.row.operator" clearable placeholder="请选择"
109                              style="font-weight: 600;">
110                     <el-option v-for="item in operatorList"
111                                :key="item"
112                                :label="item"
113                                :value="item"/>
114                   </el-select>
115                 </template>
116               </el-table-column>
117               <el-table-column prop="" label="操作" width="100" align="center">
118                 <template #default="scope">
119                   <el-button @click="addExpressionRow(scope.$index, expressionList)" link type="primary" size="small">添加</el-button>
120                   <el-button @click="deleteExpressionRow(scope.$index, expressionList)" link type="danger" size="small">删除</el-button>
121                 </template>
122               </el-table-column>
123             </el-table>
124           </el-form-item>
125         </el-col>
126       </el-row>
127     </el-form>
128     <template #footer>
129       <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
130       <el-button @click="dialogVisible = false">取 消</el-button>
131     </template>
132   </Dialog>
133 </template>
134 <script lang="ts" setup>
135   import {DICT_TYPE, getStrDictOptions} from '@/utils/dict'
136   import * as DataSetApi from '@/api/data/ind/data/data.set'
137   import {CommonStatusEnum} from '@/utils/constants'
138   import * as DataSourceConfigApi from "@/api/infra/dataSourceConfig";
139   import * as ItemApi from '@/api/data/ind/item/item'
140   import { ElMessage } from 'element-plus'
141   import * as CategoryApi from '@/api/data/ind/category/index'
142
143   defineOptions({name: 'IndDataSetForm'})
144
145   const {t} = useI18n() // 国际化
146   const message = useMessage() // 消息弹窗
147
148   const dialogVisible = ref(false) // 弹窗的是否展示
149   const dialogTitle = ref('') // 弹窗的标题
150   const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
151   const formType = ref('') // 表单的类型:create - 新增;update - 修改
152   const itemList = ref([] as ItemApi.ItemVO[])
153   let formData = ref({
154     id: undefined,
155     itemNo: '',
156     itemName: '',
157     itemType: '',
158     itemCategory: '',
159     coefficient: '',
160     precision: '',
161     businessType: '',
162     timeRange: '',
163     timeGranularity: '',
164     remark: '',
165     calItem: {
166       id: '',
167       expression: '',
168     }
169   })
170   let expressionList = ref([{
171     parenthesesLeft: '',
172     itemNo: '',
173     parenthesesRight: '',
174     operator: ''
175   }])
176
177   const validateAsNumber = (rule, value, callback) => {
178     const regex = /^(\-|\+)?\d+(\.\d+)?$/;
179     if (!regex.test(value)) {
180       callback(new Error('请输入数字!'));
181     }
182   }
183   const operatorList = ref(['+', '-', '*', '/', '&', '|', '!', '>', '<'])
184   const formRules = reactive({
185     itemName: [{required: true, message: '指标名称不能为空', trigger: 'blur'}],
186     itemCategory: [{required: true, message: '指标类型不能为空', trigger: 'blur'}],
187     precision: [{validator: validateAsNumber, trigger: 'blur' }],
188     coefficient: [{validator: validateAsNumber, trigger: 'blur' }],
189   })
190   const formRef = ref() // 表单 Ref
191   const dataSourceList = ref([] as DataSourceConfigApi.DataSourceConfigVO[])
192   const queryParams = reactive({})
193   const dataCategoryList = ref([] as CategoryApi.IndItemCategoryVO[])
194   /** 打开弹窗 */
195   const open = async (type: string, id?: number) => {
196     dialogVisible.value = true
197     dialogTitle.value = '复合指标'
198     formType.value = type
199     resetForm()
200
201     // 加载数据源列表
202     dataCategoryList.value = await CategoryApi.getCategoryListAllSimple()
203     itemList.value = await ItemApi.getItemList(queryParams)
204     // 修改时,设置数据
205     if (id) {
206       formLoading.value = true
207       try {
208         formData.value = await ItemApi.getItem(id)
209         expressionList.value = []
210         let expression = formData.value.calItem.expression
211         do {
212           let indexArray = [
213             expression.indexOf('+'),
214             expression.indexOf('-'),
215             expression.indexOf('*'),
216             expression.indexOf('/'),
217             expression.indexOf('&'),
218             expression.indexOf('|'),
219             expression.indexOf('!'),
220             expression.indexOf('>'),
221             expression.indexOf('<')
222           ].sort(numAscSort)
223           if (indexArray[indexArray.length - 1] !== -1) {
224             let endIndex = 0
225             for (let key in indexArray) {
226               if (indexArray[key] > -1) {
227                 endIndex = indexArray[key]
228                 break
229               }
230             }
231             // 运算值
232             let itemNoStr = expression.substring(0, endIndex)
233
234             // 运算符
235             let operator = expression.substr(endIndex, 1)
236             let indexOfParenthesesLeft = itemNoStr.indexOf('(')
237             let lastIndexOfParenthesesLeft = itemNoStr.lastIndexOf('(')
238
239             // 左括号
240             let parenthesesLeft = ''
241             if (indexOfParenthesesLeft !== -1 && lastIndexOfParenthesesLeft !== -1) {
242               parenthesesLeft = itemNoStr.substring(indexOfParenthesesLeft, lastIndexOfParenthesesLeft + 1)
243               itemNoStr = itemNoStr.substring(lastIndexOfParenthesesLeft + 1)
244             }
245
246             let indexOfParenthesesRight = itemNoStr.indexOf(')')
247             let lastIndexOfParenthesesRight = itemNoStr.lastIndexOf(')')
248
249             // 右括号
250             let parenthesesRight = ''
251             if (indexOfParenthesesRight !== -1 && lastIndexOfParenthesesRight !== -1) {
252               parenthesesRight = itemNoStr.substring(indexOfParenthesesRight, lastIndexOfParenthesesRight + 1)
253               itemNoStr = itemNoStr.substring(0, indexOfParenthesesRight)
254             }
255             expressionList.value.push({
256               parenthesesLeft: parenthesesLeft,
257               itemNo: itemNoStr,
258               parenthesesRight: parenthesesRight,
259               operator: operator
260             })
261             expression = expression.substring(endIndex + 1)
262           } else {
263             let pointStr = expression
264             let indexOfParenthesesLeft = pointStr.indexOf('(')
265             let lastIndexOfParenthesesLeft = pointStr.lastIndexOf('(')
266             let parenthesesLeft = ''
267             if (indexOfParenthesesLeft !== -1 && lastIndexOfParenthesesLeft !== -1) {
268               parenthesesLeft = pointStr.substring(indexOfParenthesesLeft, lastIndexOfParenthesesLeft + 1)
269               pointStr = pointStr.substring(lastIndexOfParenthesesLeft + 1)
270             }
271             let indexOfParenthesesRight = pointStr.indexOf(')')
272             let lastIndexOfParenthesesRight = pointStr.lastIndexOf(')')
273             let parenthesesRight = ''
274             if (indexOfParenthesesRight !== -1 && lastIndexOfParenthesesRight !== -1) {
275               parenthesesRight = pointStr.substring(indexOfParenthesesRight, lastIndexOfParenthesesRight + 1)
276               pointStr = pointStr.substring(0, indexOfParenthesesRight)
277             }
278             expressionList.value.push({
279               parenthesesLeft: parenthesesLeft,
280               itemNo: pointStr,
281               parenthesesRight: parenthesesRight,
282               operator: ''
283             })
284             expression = ''
285           }
286         } while (expression && expression.length > 0)
287
288       } finally {
289         formLoading.value = false
290       }
291     }
292   }
293   function numAscSort(a, b) {
294     return a - b
295   }
296
297   defineExpose({open}) // 提供 open 方法,用于打开弹窗
298
299   /** 提交表单 */
300   const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
301   const submitForm = async () => {
302     // 校验表单
303     if (!formRef) return
304     const valid = await formRef.value.validate()
305     if (!valid) return
306     // 提交请求
307     formLoading.value = true
308     try {
309       if (expressionList.value && expressionList.value.length > 0) {
310         let parenthesesLeftRex = /^[(]*$/
311         let parenthesesRightRex = /^[)]*$/
312         let expression = ''
313         for (let i = 0; i < expressionList.value.length; i++) {
314           let value = expressionList.value[i]
315           if (!parenthesesLeftRex.test(value.parenthesesLeft)) {
316             ElMessage({
317               message: `第${i + 1}行左括号输入不正确!`,
318               type: 'error',
319               duration: 1500
320             })
321             return
322           }
323           if (!parenthesesRightRex.test(value.parenthesesRight)) {
324             ElMessage({
325               message: `第${i + 1}行右括号输入不正确!`,
326               type: 'error',
327               duration: 1500
328             })
329             return
330           }
331           if (i !== (expressionList.value.length - 1) && !value.operator) {
332             ElMessage({
333               message: `第${i + 1}行运算符不能为空!`,
334               type: 'error',
335               duration: 1500
336             })
337             return
338           }
339           expression = expression + value.parenthesesLeft + value.itemNo + value.parenthesesRight + (i === (expressionList.value.length - 1) ? '' : value.operator)
340         }
341         formData.value.calItem.expression = expression
342       } else {
343         ElMessage({
344           message: `表达式不可以为空`,
345           type: 'error',
346           duration: 1500
347         })
348         return
349       }
350       formData.value.itemType = 'CAL'
351       const data = formData.value as ItemApi.ItemVO
352       if (formType.value === 'create') {
353         await ItemApi.createItem(data)
354         message.success(t('common.createSuccess'))
355       } else {
356         await ItemApi.updateItem(data)
357         message.success(t('common.updateSuccess'))
358       }
359       dialogVisible.value = false
360       // 发送操作成功的事件
361       emit('success')
362     } finally {
363       formLoading.value = false
364     }
365   }
366
367   function addExpressionRow(index, rows) {
368     let row = JSON.parse(JSON.stringify(rows[index]))
369     rows.splice(index, 0, row)
370   }
371
372   function addParenthesesLeft(index, row) {
373     if (row.parenthesesLeft) {
374       row.parenthesesLeft = row.parenthesesLeft + '('
375     } else {
376       row.parenthesesLeft = '('
377     }
378   }
379
380   function removeParenthesesLeft(index, row) {
381     if (row.parenthesesLeft) {
382       row.parenthesesLeft = row.parenthesesLeft.substring(0, row.parenthesesLeft.length - 1)
383     } else {
384       row.parenthesesLeft = ''
385     }
386   }
387
388   function addParenthesesRight(index, row) {
389     if (row.parenthesesRight) {
390       row.parenthesesRight = row.parenthesesRight + ')'
391     } else {
392       row.parenthesesRight = ')'
393     }
394   }
395
396   function removeParenthesesRight(index, row) {
397     if (row.parenthesesRight) {
398       row.parenthesesRight = row.parenthesesRight.substring(0, row.parenthesesRight.length - 1)
399     } else {
400       row.parenthesesRight = ''
401     }
402   }
403
404   function deleteExpressionRow(index, rows) {
405     if (!rows || rows.length === 1) {
406       ElMessage({
407         message: '不能全部删除!',
408         type: 'error',
409         duration: 1500
410       })
411       return
412     }
413     rows.splice(index, 1)
414   }
415
416   /** 重置表单 */
417   const resetForm = () => {
418     formData.value = {
419       id: undefined,
420       itemNo: '',
421       itemName: '',
422       itemType: '',
423       itemCategory: '',
424       coefficient: '',
425       precision: '',
426       businessType: '',
427       timeRange: '',
428       timeGranularity: '',
429       remark: '',
430       calItem: {
431         id: '',
432         expression: '',
433       }}
434     formRef.value?.resetFields()
435   }
436 </script>