潘志宝
3 天以前 afd12bd4683489925575346214080faf05394a73
提交 | 用户 | 时间
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">
6a72da 23             <el-tree-select
J 24               v-model="formData.itemCategory"
25               :data="dataCategoryList"
26               :default-expanded-keys="[0]"
27               :props="defaultProps"
28               check-strictly
29               node-key="id"
30             />
67ea85 31           </el-form-item>
J 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'
6a72da 142   import {handleTree} from "@/utils/tree";
67ea85 143
J 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({})
6a72da 194
J 195   const dataCategoryList = ref<Tree[]>([])
196   const getCategoryTree = async () => {
197     dataCategoryList.value = []
198     const res = await CategoryApi.getCategoryListAllSimple()
199     let category: Tree = {id: 0, label: '主类目', children: []}
200     category.children = handleTree(res, 'id', 'pid')
201     dataCategoryList.value.push(category)
202   }
67ea85 203   /** 打开弹窗 */
J 204   const open = async (type: string, id?: number) => {
205     dialogVisible.value = true
206     dialogTitle.value = '复合指标'
207     formType.value = type
208     resetForm()
209
210     // 加载数据源列表
6a72da 211     await getCategoryTree()
67ea85 212     itemList.value = await ItemApi.getItemList(queryParams)
J 213     // 修改时,设置数据
214     if (id) {
215       formLoading.value = true
216       try {
217         formData.value = await ItemApi.getItem(id)
218         expressionList.value = []
219         let expression = formData.value.calItem.expression
220         do {
221           let indexArray = [
222             expression.indexOf('+'),
223             expression.indexOf('-'),
224             expression.indexOf('*'),
225             expression.indexOf('/'),
226             expression.indexOf('&'),
227             expression.indexOf('|'),
228             expression.indexOf('!'),
229             expression.indexOf('>'),
230             expression.indexOf('<')
231           ].sort(numAscSort)
232           if (indexArray[indexArray.length - 1] !== -1) {
233             let endIndex = 0
234             for (let key in indexArray) {
235               if (indexArray[key] > -1) {
236                 endIndex = indexArray[key]
237                 break
238               }
239             }
240             // 运算值
241             let itemNoStr = expression.substring(0, endIndex)
242
243             // 运算符
244             let operator = expression.substr(endIndex, 1)
245             let indexOfParenthesesLeft = itemNoStr.indexOf('(')
246             let lastIndexOfParenthesesLeft = itemNoStr.lastIndexOf('(')
247
248             // 左括号
249             let parenthesesLeft = ''
250             if (indexOfParenthesesLeft !== -1 && lastIndexOfParenthesesLeft !== -1) {
251               parenthesesLeft = itemNoStr.substring(indexOfParenthesesLeft, lastIndexOfParenthesesLeft + 1)
252               itemNoStr = itemNoStr.substring(lastIndexOfParenthesesLeft + 1)
253             }
254
255             let indexOfParenthesesRight = itemNoStr.indexOf(')')
256             let lastIndexOfParenthesesRight = itemNoStr.lastIndexOf(')')
257
258             // 右括号
259             let parenthesesRight = ''
260             if (indexOfParenthesesRight !== -1 && lastIndexOfParenthesesRight !== -1) {
261               parenthesesRight = itemNoStr.substring(indexOfParenthesesRight, lastIndexOfParenthesesRight + 1)
262               itemNoStr = itemNoStr.substring(0, indexOfParenthesesRight)
263             }
264             expressionList.value.push({
265               parenthesesLeft: parenthesesLeft,
266               itemNo: itemNoStr,
267               parenthesesRight: parenthesesRight,
268               operator: operator
269             })
270             expression = expression.substring(endIndex + 1)
271           } else {
272             let pointStr = expression
273             let indexOfParenthesesLeft = pointStr.indexOf('(')
274             let lastIndexOfParenthesesLeft = pointStr.lastIndexOf('(')
275             let parenthesesLeft = ''
276             if (indexOfParenthesesLeft !== -1 && lastIndexOfParenthesesLeft !== -1) {
277               parenthesesLeft = pointStr.substring(indexOfParenthesesLeft, lastIndexOfParenthesesLeft + 1)
278               pointStr = pointStr.substring(lastIndexOfParenthesesLeft + 1)
279             }
280             let indexOfParenthesesRight = pointStr.indexOf(')')
281             let lastIndexOfParenthesesRight = pointStr.lastIndexOf(')')
282             let parenthesesRight = ''
283             if (indexOfParenthesesRight !== -1 && lastIndexOfParenthesesRight !== -1) {
284               parenthesesRight = pointStr.substring(indexOfParenthesesRight, lastIndexOfParenthesesRight + 1)
285               pointStr = pointStr.substring(0, indexOfParenthesesRight)
286             }
287             expressionList.value.push({
288               parenthesesLeft: parenthesesLeft,
289               itemNo: pointStr,
290               parenthesesRight: parenthesesRight,
291               operator: ''
292             })
293             expression = ''
294           }
295         } while (expression && expression.length > 0)
296
297       } finally {
298         formLoading.value = false
299       }
300     }
301   }
302   function numAscSort(a, b) {
303     return a - b
304   }
305
306   defineExpose({open}) // 提供 open 方法,用于打开弹窗
307
308   /** 提交表单 */
309   const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
310   const submitForm = async () => {
311     // 校验表单
312     if (!formRef) return
313     const valid = await formRef.value.validate()
314     if (!valid) return
315     // 提交请求
316     formLoading.value = true
317     try {
318       if (expressionList.value && expressionList.value.length > 0) {
319         let parenthesesLeftRex = /^[(]*$/
320         let parenthesesRightRex = /^[)]*$/
321         let expression = ''
322         for (let i = 0; i < expressionList.value.length; i++) {
323           let value = expressionList.value[i]
324           if (!parenthesesLeftRex.test(value.parenthesesLeft)) {
325             ElMessage({
326               message: `第${i + 1}行左括号输入不正确!`,
327               type: 'error',
328               duration: 1500
329             })
330             return
331           }
332           if (!parenthesesRightRex.test(value.parenthesesRight)) {
333             ElMessage({
334               message: `第${i + 1}行右括号输入不正确!`,
335               type: 'error',
336               duration: 1500
337             })
338             return
339           }
340           if (i !== (expressionList.value.length - 1) && !value.operator) {
341             ElMessage({
342               message: `第${i + 1}行运算符不能为空!`,
343               type: 'error',
344               duration: 1500
345             })
346             return
347           }
348           expression = expression + value.parenthesesLeft + value.itemNo + value.parenthesesRight + (i === (expressionList.value.length - 1) ? '' : value.operator)
349         }
350         formData.value.calItem.expression = expression
351       } else {
352         ElMessage({
353           message: `表达式不可以为空`,
354           type: 'error',
355           duration: 1500
356         })
357         return
358       }
359       formData.value.itemType = 'CAL'
360       const data = formData.value as ItemApi.ItemVO
361       if (formType.value === 'create') {
362         await ItemApi.createItem(data)
363         message.success(t('common.createSuccess'))
364       } else {
365         await ItemApi.updateItem(data)
366         message.success(t('common.updateSuccess'))
367       }
368       dialogVisible.value = false
369       // 发送操作成功的事件
370       emit('success')
371     } finally {
372       formLoading.value = false
373     }
374   }
375
376   function addExpressionRow(index, rows) {
377     let row = JSON.parse(JSON.stringify(rows[index]))
378     rows.splice(index, 0, row)
379   }
380
381   function addParenthesesLeft(index, row) {
382     if (row.parenthesesLeft) {
383       row.parenthesesLeft = row.parenthesesLeft + '('
384     } else {
385       row.parenthesesLeft = '('
386     }
387   }
388
389   function removeParenthesesLeft(index, row) {
390     if (row.parenthesesLeft) {
391       row.parenthesesLeft = row.parenthesesLeft.substring(0, row.parenthesesLeft.length - 1)
392     } else {
393       row.parenthesesLeft = ''
394     }
395   }
396
397   function addParenthesesRight(index, row) {
398     if (row.parenthesesRight) {
399       row.parenthesesRight = row.parenthesesRight + ')'
400     } else {
401       row.parenthesesRight = ')'
402     }
403   }
404
405   function removeParenthesesRight(index, row) {
406     if (row.parenthesesRight) {
407       row.parenthesesRight = row.parenthesesRight.substring(0, row.parenthesesRight.length - 1)
408     } else {
409       row.parenthesesRight = ''
410     }
411   }
412
413   function deleteExpressionRow(index, rows) {
414     if (!rows || rows.length === 1) {
415       ElMessage({
416         message: '不能全部删除!',
417         type: 'error',
418         duration: 1500
419       })
420       return
421     }
422     rows.splice(index, 1)
423   }
424
425   /** 重置表单 */
426   const resetForm = () => {
427     formData.value = {
428       id: undefined,
429       itemNo: '',
430       itemName: '',
431       itemType: '',
432       itemCategory: '',
433       coefficient: '',
434       precision: '',
435       businessType: '',
436       timeRange: '',
437       timeGranularity: '',
438       remark: '',
439       calItem: {
440         id: '',
441         expression: '',
442       }}
443     formRef.value?.resetFields()
444   }
445 </script>