潘志宝
2024-12-10 cd09bed74c2b40d46f4391b4fe3fcd0c43c725f7
提交 | 用户 | 时间
1c14d6 1 <template>
c4b4d2 2   <Dialog v-model="dialogVisible" :title="dialogTitle" width="60%">
1c14d6 3     <el-form
L 4       ref="formRef"
5       v-loading="formLoading"
6       :model="formData"
7       :rules="formRules"
8       label-width="120px"
9     >
10       <el-row>
11         <el-col :span="12">
12           <el-form-item label="测点编码" prop="pointNo">
e9d8f9 13             <el-input v-model="formData.pointNo" disabled/>
1c14d6 14           </el-form-item>
L 15         </el-col>
16         <el-col :span="12">
17           <el-form-item label="测点名称" prop="pointName">
660c92 18             <el-input v-model="formData.pointName" placeholder="请输入测点名称"/>
1c14d6 19           </el-form-item>
L 20         </el-col>
660c92 21       </el-row>
L 22       <el-row>
1c14d6 23         <el-col :span="12">
L 24           <el-form-item label="测点类型" prop="pointType">
660c92 25             <el-select
L 26               v-model="formData.pointType"
27               clearable
28               placeholder="请选择测点类型"
29             >
30               <el-option
e9d8f9 31                 v-for="dict in getDictOptions(DICT_TYPE.DATA_POINT_TYPE)"
660c92 32                 :key="dict.value"
L 33                 :label="dict.label"
34                 :value="dict.value"
35               />
36             </el-select>
1c14d6 37           </el-form-item>
L 38         </el-col>
39         <el-col :span="12">
40           <el-form-item label="数据类型" prop="dataType">
660c92 41             <el-select
L 42               v-model="formData.dataType"
43               clearable
44               placeholder="请选择数据类型"
45             >
46               <el-option
e9d8f9 47                 v-for="dict in getDictOptions(DICT_TYPE.POINT_DATA_TYPE)"
660c92 48                 :key="dict.value"
L 49                 :label="dict.label"
50                 :value="dict.value"
51               />
52             </el-select>
1c14d6 53           </el-form-item>
L 54         </el-col>
55       </el-row>
56       <el-row>
57         <el-col :span="12">
58           <el-form-item label="测量单位" prop="unit">
660c92 59             <el-input v-model="formData.unit" placeholder="请输入测量单位"/>
1c14d6 60           </el-form-item>
L 61         </el-col>
62         <el-col :span="12">
63           <el-form-item label="单位转换" prop="unittransfactor">
15a226 64             <el-input-number v-model="formData.unittransfactor" style="width: 100%" :controls="false"/>
1c14d6 65           </el-form-item>
L 66         </el-col>
67       </el-row>
68       <el-row>
69         <el-col :span="12">
70           <el-form-item label="采集频率" prop="minfreqid">
660c92 71             <el-select
L 72               v-model="formData.minfreqid"
73               clearable
74               placeholder="请选择采集频率"
75             >
76               <el-option
77                 v-for="dict in getDictOptions(DICT_TYPE.MINFREQID)"
78                 :key="dict.value"
79                 :label="dict.label"
80                 :value="dict.value"
81               />
82             </el-select>
1c14d6 83           </el-form-item>
L 84         </el-col>
85         <el-col :span="12">
660c92 86           <el-form-item label="默认值" prop="defaultValue">
L 87             <el-input-number v-model="formData.defaultValue" style="width: 100%" :controls="false"/>
88           </el-form-item>
89         </el-col>
90       </el-row>
91       <el-row>
92         <el-col :span="12">
93           <el-form-item label="最大值" prop="maxValue">
94             <el-input-number v-model="formData.maxValue" style="width: 100%" :controls="false"/>
95           </el-form-item>
96         </el-col>
97         <el-col :span="12">
98           <el-form-item label="最小值" prop="minValue">
99             <el-input-number v-model="formData.minValue" style="width: 100%" :controls="false"/>
1c14d6 100           </el-form-item>
L 101         </el-col>
102       </el-row>
103       <el-row>
104         <el-col :span="12">
105           <el-form-item label="是否启用" prop="isEnable">
660c92 106             <el-select
L 107               v-model="formData.isEnable"
108               clearable
109               placeholder="请选择是否启用"
110             >
111               <el-option
e9d8f9 112                 v-for="dict in getIntDictOptions(DICT_TYPE.COM_IS_INT)"
660c92 113                 :key="dict.value"
L 114                 :label="dict.label"
115                 :value="dict.value"
116               />
117             </el-select>
118           </el-form-item>
119         </el-col>
120         <el-col :span="12">
121           <el-form-item label="备注" prop="remark">
122             <el-input v-model="formData.remark" placeholder="请输入备注"/>
123           </el-form-item>
124         </el-col>
125       </el-row>
126       <!--计量点-->
127       <el-row v-if="formData.pointType === 'MEASURE'">
e9d8f9 128         <el-col :span="24">
660c92 129           <el-form-item prop="sourceOption" label="数据源">
L 130             <el-cascader
131               style="width: 100%;"
132               v-model="formData.sourceOption"
133               :options="sourceOptions"
134               filterable/>
135           </el-form-item>
136         </el-col>
137       </el-row>
c4da14 138       <el-row v-if="formData.pointType === 'MEASURE'">
L 139         <el-col :span="12">
c4b4d2 140           <el-form-item label="测量值类型" prop="measurePoint.valueType">
c4da14 141             <el-select
L 142               v-model="formData.measurePoint.valueType"
143               clearable
144               placeholder="请选择值类型"
145             >
146               <el-option
c4b4d2 147                 v-for="dict in getDictOptions(DICT_TYPE.MEASURE_VALUE_TYPE)"
c4da14 148                 :key="dict.value"
L 149                 :label="dict.label"
150                 :value="dict.value"
151               />
152             </el-select>
153           </el-form-item>
154         </el-col>
155         <el-col :span="12">
c4b4d2 156           <el-form-item label="平滑尺度(min)" prop="measurePoint.dimension">
157             <el-input-number v-model="formData.measurePoint.dimension" style="width: 100%"
158                              :min="0" :max="100"
159                              :controls="false"/>
c4da14 160           </el-form-item>
L 161         </el-col>
162       </el-row>
660c92 163       <!--计算点-->
L 164       <el-row :gutter="20" v-if="formData.pointType === 'CALCULATE'">
165         <el-col :span="24">
166           <el-form-item label="表达式">
167             <el-table
168               :data="expressionList"
169               border
170               style="width: 100%">
c4b4d2 171               <el-table-column
660c92 172                 type="index"
L 173                 align="center"
c4b4d2 174                 width="60"
175                 label="序号"/>
660c92 176               <el-table-column
L 177                 prop=""
178                 label="左括号"
179                 width="140"
180                 align="center">
181                 <template #default="scope">
182                   <el-input
183                     v-model="scope.row.parenthesesLeft"
184                     placeholder=""
185                     readonly
186                     maxlength="16">
187                     <template #prepend>
188                       <el-button @click="addParenthesesLeft(scope.$index, scope.row)">+</el-button>
189                     </template>
190                     <template #append>
191                       <el-button @click="removeParenthesesLeft(scope.$index, scope.row)">-</el-button>
192                     </template>
193                   </el-input>
194                 </template>
195               </el-table-column>
196               <el-table-column
197                 prop=""
198                 label="测点"
c4b4d2 199                 min-width="160"
660c92 200                 align="center">
L 201                 <template #default="scope">
202                   <el-select
203                     v-model="scope.row.point"
204                     filterable
205                     placeholder="请选择">
206                     <el-option
207                       v-for="(item, index) in pointList"
208                       :key="index"
209                       :label="item.pointName"
210                       :value="item.pointNo"/>
211                   </el-select>
212                 </template>
213               </el-table-column>
214               <el-table-column
215                 prop=""
216                 label="运算值"
c4b4d2 217                 min-width="120"
660c92 218                 align="center">
L 219                 <template #default="scope">
220                   <el-input
221                     v-model="scope.row.point"
222                     placeholder="运算值"
223                     maxlength="16"
224                     clearable/>
225                 </template>
226               </el-table-column>
227               <el-table-column
228                 prop=""
229                 label="右括号"
230                 width="140"
231                 align="center">
232                 <template #default="scope">
233                   <el-input
234                     v-model="scope.row.parenthesesRight"
235                     placeholder=""
236                     readonly
237                     maxlength="16">
238                     <template #prepend>
239                       <el-button @click="addParenthesesRight(scope.$index, scope.row)">+</el-button>
240                     </template>
241                     <template #append>
242                       <el-button @click="removeParenthesesRight(scope.$index, scope.row)">-</el-button>
243                     </template>
244                   </el-input>
245                 </template>
246               </el-table-column>
247               <el-table-column
248                 prop=""
249                 label="运算符"
c4b4d2 250                 width="100"
660c92 251                 align="center">
L 252                 <template #default="scope">
253                   <el-select v-model="scope.row.operator" clearable>
254                     <el-option
255                       v-for="item in operatorList"
256                       :key="item"
257                       :label="item"
258                       :value="item"/>
259                   </el-select>
260                 </template>
261               </el-table-column>
262               <el-table-column
263                 prop=""
264                 label="操作"
c4b4d2 265                 width="120"
660c92 266                 align="center">
L 267                 <template #default="scope">
268                   <el-button
269                     @click="addExpressionRow(scope.$index, expressionList)"
270                     type="text"
c4b4d2 271                     size="mini">
660c92 272                     添加
L 273                   </el-button>
274                   <el-button
275                     @click="deleteExpressionRow(scope.$index, expressionList)"
276                     type="text"
c4b4d2 277                     size="mini">
660c92 278                     删除
L 279                   </el-button>
280                 </template>
281               </el-table-column>
282             </el-table>
1c14d6 283           </el-form-item>
L 284         </el-col>
285       </el-row>
d6c836 286       <!--累计点-->
287       <el-row :gutter="20" v-if="formData.pointType === 'CUMULATE'">
288         <el-col :span="24">
c7f369 289           <el-form-item label="瞬时测点" prop="cumulatePoint.momentPoint">
d6c836 290             <el-select
c7f369 291               v-model="formData.cumulatePoint.momentPoint"
d6c836 292               filterable
293               placeholder="请选择">
294               <el-option
cd09be 295                 v-for="(item, index) in pointList2"
d6c836 296                 :key="index"
297                 :label="item.pointName"
298                 :value="item.pointNo"/>
299             </el-select>
300           </el-form-item>
301         </el-col>
302         <el-col :span="12">
303           <el-form-item label="累计长度" prop="cumulatePoint.length">
304             <el-input-number v-model="formData.cumulatePoint.length" style="width: 100%"
305                              :min="1" :max="3000"
306                              :controls="false"/>
307           </el-form-item>
308         </el-col>
309         <el-col :span="12">
310           <el-form-item label="除数" prop="cumulatePoint.divisor">
311             <el-input-number v-model="formData.cumulatePoint.divisor" style="width: 100%"
312                              :min="1" :max="3000"
313                              :controls="false"/>
314           </el-form-item>
315         </el-col>
316
317       </el-row>
1c14d6 318     </el-form>
L 319     <template #footer>
320       <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
321       <el-button @click="dialogVisible = false">取 消</el-button>
322     </template>
323   </Dialog>
324 </template>
325 <script lang="ts" setup>
326 import * as DaPoint from '@/api/data/da/point'
660c92 327 import * as TagApi from '@/api/data/channel/tag'
L 328 import {DICT_TYPE, getDictOptions, getIntDictOptions} from "@/utils/dict";
1c14d6 329
660c92 330 defineOptions({name: 'DataDaPointForm'})
1c14d6 331
660c92 332 const {t} = useI18n() // 国际化
L 333 const message = useMessage() // 消息弹窗
334 const dialogVisible = ref(false) // 弹窗的是否展示
335 const dialogTitle = ref('') // 弹窗的标题
336 const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
337 const formType = ref('') // 表单的类型:create - 新增;update - 修改
338 const sourceOptions = ref([])
339 const expressionList = ref([])
340 const pointList = ref([{
341   pointName: '',
342   pointNo: ''
343 }])
344 const queryParams = reactive({
13c97d 345   pointTypes: "MEASURE,CONSTANT",
cd09be 346 })
347 const pointList2 = ref([{
348   pointName: '',
349   pointNo: ''
350 }])
351 const queryParams2 = reactive({
352   pointTypes: "MEASURE,CONSTANT,CALCULATE",
660c92 353 })
L 354 const operatorList = ref(['+', '-', '*', '/', '&', '|', '!', '>', '<'])
355 const formData = ref({
356   id: undefined,
357   pointNo: undefined,
358   pointName: undefined,
359   pointType: undefined,
360   dataType: undefined,
361   valueType: undefined,
362   storeType: undefined,
363   unit: undefined,
364   unittransfactor: undefined,
365   defaultValue: undefined,
366   maxValue: undefined,
367   minValue: undefined,
368   minfreqid: undefined,
369   remark: undefined,
370   isEnable: undefined,
371   sourceOption: [],
372   mathPoint: {
373     id: '',
374     pointId: '',
375     expression: ''
376   },
377   measurePoint: {
378     id: '',
379     pointId: '',
380     sourceType: '',
381     sourceId: '',
382     tagNo: '',
383     dimension: '',
15a226 384     valueType: '',
d6c836 385   },
386   cumulatePoint: {
387     id: '',
388     pointId: '',
c7f369 389     momentPoint: '',
d6c836 390     length: '',
391     divisor: ''
660c92 392   }
L 393 })
394 const formRules = reactive({
395   pointName: [{required: true, message: '测点名称不能为空', trigger: 'blur'}],
396   pointType: [{required: true, message: '测点类型不能为空', trigger: 'blur'}],
397   dataType: [{required: true, message: '数据类型不能为空', trigger: 'blur'}],
c4b4d2 398   minfreqid: [{required: true, message: '采集频率不能为空', trigger: 'blur'}],
d6c836 399   "measurePoint.valueType": [{required: true, message: '值类型不能为空', trigger: 'blur'}],
400   "measurePoint.dimension": [{required: true, message: '平滑尺度不能为空', trigger: 'blur'}],
c7f369 401   "cumulatePoint.momentPoint": [{required: true, message: '累计测点不能为空', trigger: 'blur'}],
d6c836 402   "cumulatePoint.length": [{required: true, message: '累计长度不能为空', trigger: 'blur'}],
403   "cumulatePoint.divisor": [{required: true, message: '除数不能为空', trigger: 'blur'}],
660c92 404 })
L 405 const formRef = ref() // 表单 Ref
406
407 /** 打开弹窗 */
408 const open = async (type: string, id?: number) => {
409   dialogVisible.value = true
410   dialogTitle.value = t('action.' + type)
411   formType.value = type
412   resetForm()
413   getSourceOption()
414   getPointList()
cd09be 415   getPointList2()
660c92 416   // 修改时,设置数据
L 417   if (id) {
418     formLoading.value = true
419     try {
420       getInfo(id)
421     } finally {
422       formLoading.value = false
423     }
424   }
425 }
426 defineExpose({open}) // 提供 open 方法,用于打开弹窗
427
428 /** 提交表单 */
429 const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
430 const submitForm = async () => {
431   // 校验表单
432   if (!formRef) return
433   const valid = await formRef.value.validate()
434   if (!valid) return
435   // 提交请求
436   formLoading.value = true
437   try {
438     if (formData.value.pointType === 'CALCULATE' &&
439       expressionList.value && expressionList.value.length > 0) {
440       let parenthesesLeftRex = /^[(]*$/
441       let parenthesesRightRex = /^[)]*$/
442       let expression = ''
443       debugger
444       for (let i = 0; i < expressionList.value.length; i++) {
445         let value = expressionList.value[i]
446         if (!parenthesesLeftRex.test(value.parenthesesLeft)) {
447           message.error('第${i + 1}行左括号输入不正确!')
448           return
449         }
450         if (!parenthesesRightRex.test(value.parenthesesRight)) {
451           message.error('第${i + 1}行右括号输入不正确!')
452           return
453         }
454         if (i !== (expressionList.value.length - 1) && !value.operator) {
455           message.error('第${i + 1}行运算符不能为空!')
456           return
457         }
458         expression = expression + value.parenthesesLeft + value.point + value.parenthesesRight + (i === (expressionList.value.length - 1) ? '' : value.operator)
459       }
460       formData.value['mathPoint']['expression'] = expression
461     } else {
462       formData.value['mathPoint'] = {}
463     }
464     const data = formData.value as unknown as DaPoint.DaPointVO
465     if (formType.value === 'create') {
466       await DaPoint.createDaPoint(data)
467       message.success(t('common.createSuccess'))
468     } else {
469       await DaPoint.updateDaPoint(data)
470       message.success(t('common.updateSuccess'))
471     }
472     dialogVisible.value = false
473     // 发送操作成功的事件
474     emit('success')
475   } finally {
476     formLoading.value = false
477   }
478 }
479
480 /** 重置表单 */
481 const resetForm = () => {
482   expressionList.value = [{
483     parenthesesLeft: '',
484     point: '',
485     parenthesesRight: '',
486     operator: ''
487   }]
488   formData.value = {
1c14d6 489     id: undefined,
L 490     pointNo: undefined,
491     pointName: undefined,
492     pointType: undefined,
493     dataType: undefined,
494     valueType: undefined,
495     storeType: undefined,
496     unit: undefined,
660c92 497     unittransfactor: 1,
c4b4d2 498     defaultValue: 0,
499     maxValue: 100000000,
660c92 500     minValue: 0,
1c14d6 501     minfreqid: undefined,
L 502     remark: undefined,
660c92 503     isEnable: 1,
L 504     sourceOption: [],
dead8d 505     mathPoint: {
L 506       id: '',
507       pointId: '',
508       expression: ''
509     },
510     measurePoint: {
511       id: '',
512       pointId: '',
513       sourceType: '',
514       sourceId: '',
515       tagNo: '',
516       dimension: '1',
517       valueType: 'SIMULATE',
d6c836 518     },
519     cumulatePoint: {
520       id: '',
521       pointId: '',
c7f369 522       momentPoint: '',
d6c836 523       length: 60,
524       divisor: 60
dead8d 525     }
1c14d6 526   }
660c92 527   formRef.value?.resetFields()
L 528 }
1c14d6 529
660c92 530 function deleteExpressionRow(index, rows) {
L 531   if (!rows || rows.length === 1) {
532     message.error('不能全部删除!')
533     return
534   }
535   rows.splice(index, 1)
536 }
537
538 function addExpressionRow(index, rows) {
539   let row = JSON.parse(JSON.stringify(rows[index]))
540   rows.splice(index, 0, row)
541 }
542
543 function addParenthesesLeft(index, row) {
544   if (row.parenthesesLeft) {
545     row.parenthesesLeft = row.parenthesesLeft + '('
546   } else {
547     row.parenthesesLeft = '('
548   }
549 }
550
551 function removeParenthesesLeft(index, row) {
552   if (row.parenthesesLeft) {
553     row.parenthesesLeft = row.parenthesesLeft.substring(0, row.parenthesesLeft.length - 1)
554   } else {
555     row.parenthesesLeft = ''
556   }
557 }
558
559 function addParenthesesRight(index, row) {
560   if (row.parenthesesRight) {
561     row.parenthesesRight = row.parenthesesRight + ')'
562   } else {
563     row.parenthesesRight = ')'
564   }
565 }
566
567 function removeParenthesesRight(index, row) {
568   if (row.parenthesesRight) {
569     row.parenthesesRight = row.parenthesesRight.substring(0, row.parenthesesRight.length - 1)
570   } else {
571     row.parenthesesRight = ''
572   }
573 }
574
575 function numAscSort(a, b) {
576   return a - b
577 }
578
579 // 获取数据源选项
580 const getSourceOption = async () => {
581   sourceOptions.value = await TagApi.getTagTree()
582 }
583
584 const getPointList = async () => {
585   pointList.value = await DaPoint.getPointList(queryParams)
586 }
587
cd09be 588 const getPointList2 = async () => {
589   pointList2.value = await DaPoint.getPointList(queryParams2)
590 }
591
660c92 592 const getInfo = async (id) => {
L 593   formData.value = await DaPoint.getDaPoint(id)
594   expressionList.value = []
595   if (formData.value.pointType &&
596     formData.value.pointType === 'CALCULATE' &&
597     formData.value.mathPoint.expression) {
598     let expression = formData.value.mathPoint.expression
599     do {
600       let indexArray = [
601         expression.indexOf('+'),
602         expression.indexOf('-'),
603         expression.indexOf('*'),
604         expression.indexOf('/'),
605         expression.indexOf('&'),
606         expression.indexOf('|'),
607         expression.indexOf('!'),
608         expression.indexOf('>'),
609         expression.indexOf('<')
610       ].sort(numAscSort)
611       if (indexArray[indexArray.length - 1] !== -1) {
612         let endIndex = 0
613         for (let key in indexArray) {
614           if (indexArray[key] > -1) {
615             endIndex = indexArray[key]
616             break
617           }
618         }
619
620         // 运算值
621         let pointStr = expression.substring(0, endIndex)
622         debugger
623         // 运算符
624         let operator = expression.substr(endIndex, 1)
625         let indexOfParenthesesLeft = pointStr.indexOf('(')
626         let lastIndexOfParenthesesLeft = pointStr.lastIndexOf('(')
627
628         // 左括号
629         let parenthesesLeft = ''
630         if (indexOfParenthesesLeft !== -1 && lastIndexOfParenthesesLeft !== -1) {
631           parenthesesLeft = pointStr.substring(indexOfParenthesesLeft, lastIndexOfParenthesesLeft + 1)
632           pointStr = pointStr.substring(lastIndexOfParenthesesLeft + 1)
633         }
634
635         let indexOfParenthesesRight = pointStr.indexOf(')')
636         let lastIndexOfParenthesesRight = pointStr.lastIndexOf(')')
637
638         // 右括号
639         let parenthesesRight = ''
640         if (indexOfParenthesesRight !== -1 && lastIndexOfParenthesesRight !== -1) {
641           parenthesesRight = pointStr.substring(indexOfParenthesesRight, lastIndexOfParenthesesRight + 1)
642           pointStr = pointStr.substring(0, indexOfParenthesesRight)
643         }
644         expressionList.value.push({
645           parenthesesLeft: parenthesesLeft,
646           point: pointStr,
647           parenthesesRight: parenthesesRight,
648           operator: operator
649         })
650         expression = expression.substring(endIndex + 1)
1c14d6 651       } else {
660c92 652         let pointStr = expression
L 653         let indexOfParenthesesLeft = pointStr.indexOf('(')
654         let lastIndexOfParenthesesLeft = pointStr.lastIndexOf('(')
655         let parenthesesLeft = ''
656         if (indexOfParenthesesLeft !== -1 && lastIndexOfParenthesesLeft !== -1) {
657           parenthesesLeft = pointStr.substring(indexOfParenthesesLeft, lastIndexOfParenthesesLeft + 1)
658           pointStr = pointStr.substring(lastIndexOfParenthesesLeft + 1)
659         }
660         let indexOfParenthesesRight = pointStr.indexOf(')')
661         let lastIndexOfParenthesesRight = pointStr.lastIndexOf(')')
662         let parenthesesRight = ''
663         if (indexOfParenthesesRight !== -1 && lastIndexOfParenthesesRight !== -1) {
664           parenthesesRight = pointStr.substring(indexOfParenthesesRight, lastIndexOfParenthesesRight + 1)
665           pointStr = pointStr.substring(0, indexOfParenthesesRight)
666         }
667         expressionList.value.push({
668           parenthesesLeft: parenthesesLeft,
669           point: pointStr,
670           parenthesesRight: parenthesesRight,
671           operator: ''
672         })
673         expression = ''
1c14d6 674       }
660c92 675     } while (expression && expression.length > 0)
1c14d6 676   }
660c92 677 }
1c14d6 678
L 679 </script>
660c92 680 <style>
L 681 .el-select {
682   width: 100%
683 }
684 </style>