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