houzhongjian
2024-12-04 bb203eb72ee4604be8c9272cc583ecb9e393aeb8
提交 | 用户 | 时间
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
295                 v-for="(item, index) in pointList"
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",
660c92 346 })
L 347 const operatorList = ref(['+', '-', '*', '/', '&', '|', '!', '>', '<'])
348 const formData = ref({
349   id: undefined,
350   pointNo: undefined,
351   pointName: undefined,
352   pointType: undefined,
353   dataType: undefined,
354   valueType: undefined,
355   storeType: undefined,
356   unit: undefined,
357   unittransfactor: undefined,
358   defaultValue: undefined,
359   maxValue: undefined,
360   minValue: undefined,
361   minfreqid: undefined,
362   remark: undefined,
363   isEnable: undefined,
364   sourceOption: [],
365   mathPoint: {
366     id: '',
367     pointId: '',
368     expression: ''
369   },
370   measurePoint: {
371     id: '',
372     pointId: '',
373     sourceType: '',
374     sourceId: '',
375     tagNo: '',
376     dimension: '',
15a226 377     valueType: '',
d6c836 378   },
379   cumulatePoint: {
380     id: '',
381     pointId: '',
c7f369 382     momentPoint: '',
d6c836 383     length: '',
384     divisor: ''
660c92 385   }
L 386 })
387 const formRules = reactive({
388   pointName: [{required: true, message: '测点名称不能为空', trigger: 'blur'}],
389   pointType: [{required: true, message: '测点类型不能为空', trigger: 'blur'}],
390   dataType: [{required: true, message: '数据类型不能为空', trigger: 'blur'}],
c4b4d2 391   minfreqid: [{required: true, message: '采集频率不能为空', trigger: 'blur'}],
d6c836 392   "measurePoint.valueType": [{required: true, message: '值类型不能为空', trigger: 'blur'}],
393   "measurePoint.dimension": [{required: true, message: '平滑尺度不能为空', trigger: 'blur'}],
c7f369 394   "cumulatePoint.momentPoint": [{required: true, message: '累计测点不能为空', trigger: 'blur'}],
d6c836 395   "cumulatePoint.length": [{required: true, message: '累计长度不能为空', trigger: 'blur'}],
396   "cumulatePoint.divisor": [{required: true, message: '除数不能为空', trigger: 'blur'}],
660c92 397 })
L 398 const formRef = ref() // 表单 Ref
399
400 /** 打开弹窗 */
401 const open = async (type: string, id?: number) => {
402   dialogVisible.value = true
403   dialogTitle.value = t('action.' + type)
404   formType.value = type
405   resetForm()
406   getSourceOption()
407   getPointList()
408   // 修改时,设置数据
409   if (id) {
410     formLoading.value = true
411     try {
412       getInfo(id)
413     } finally {
414       formLoading.value = false
415     }
416   }
417 }
418 defineExpose({open}) // 提供 open 方法,用于打开弹窗
419
420 /** 提交表单 */
421 const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
422 const submitForm = async () => {
423   // 校验表单
424   if (!formRef) return
425   const valid = await formRef.value.validate()
426   if (!valid) return
427   // 提交请求
428   formLoading.value = true
429   try {
430     if (formData.value.pointType === 'CALCULATE' &&
431       expressionList.value && expressionList.value.length > 0) {
432       let parenthesesLeftRex = /^[(]*$/
433       let parenthesesRightRex = /^[)]*$/
434       let expression = ''
435       debugger
436       for (let i = 0; i < expressionList.value.length; i++) {
437         let value = expressionList.value[i]
438         if (!parenthesesLeftRex.test(value.parenthesesLeft)) {
439           message.error('第${i + 1}行左括号输入不正确!')
440           return
441         }
442         if (!parenthesesRightRex.test(value.parenthesesRight)) {
443           message.error('第${i + 1}行右括号输入不正确!')
444           return
445         }
446         if (i !== (expressionList.value.length - 1) && !value.operator) {
447           message.error('第${i + 1}行运算符不能为空!')
448           return
449         }
450         expression = expression + value.parenthesesLeft + value.point + value.parenthesesRight + (i === (expressionList.value.length - 1) ? '' : value.operator)
451       }
452       formData.value['mathPoint']['expression'] = expression
453     } else {
454       formData.value['mathPoint'] = {}
455     }
456     const data = formData.value as unknown as DaPoint.DaPointVO
457     if (formType.value === 'create') {
458       await DaPoint.createDaPoint(data)
459       message.success(t('common.createSuccess'))
460     } else {
461       await DaPoint.updateDaPoint(data)
462       message.success(t('common.updateSuccess'))
463     }
464     dialogVisible.value = false
465     // 发送操作成功的事件
466     emit('success')
467   } finally {
468     formLoading.value = false
469   }
470 }
471
472 /** 重置表单 */
473 const resetForm = () => {
474   expressionList.value = [{
475     parenthesesLeft: '',
476     point: '',
477     parenthesesRight: '',
478     operator: ''
479   }]
480   formData.value = {
1c14d6 481     id: undefined,
L 482     pointNo: undefined,
483     pointName: undefined,
484     pointType: undefined,
485     dataType: undefined,
486     valueType: undefined,
487     storeType: undefined,
488     unit: undefined,
660c92 489     unittransfactor: 1,
c4b4d2 490     defaultValue: 0,
491     maxValue: 100000000,
660c92 492     minValue: 0,
1c14d6 493     minfreqid: undefined,
L 494     remark: undefined,
660c92 495     isEnable: 1,
L 496     sourceOption: [],
dead8d 497     mathPoint: {
L 498       id: '',
499       pointId: '',
500       expression: ''
501     },
502     measurePoint: {
503       id: '',
504       pointId: '',
505       sourceType: '',
506       sourceId: '',
507       tagNo: '',
508       dimension: '1',
509       valueType: 'SIMULATE',
d6c836 510     },
511     cumulatePoint: {
512       id: '',
513       pointId: '',
c7f369 514       momentPoint: '',
d6c836 515       length: 60,
516       divisor: 60
dead8d 517     }
1c14d6 518   }
660c92 519   formRef.value?.resetFields()
L 520 }
1c14d6 521
660c92 522 function deleteExpressionRow(index, rows) {
L 523   if (!rows || rows.length === 1) {
524     message.error('不能全部删除!')
525     return
526   }
527   rows.splice(index, 1)
528 }
529
530 function addExpressionRow(index, rows) {
531   let row = JSON.parse(JSON.stringify(rows[index]))
532   rows.splice(index, 0, row)
533 }
534
535 function addParenthesesLeft(index, row) {
536   if (row.parenthesesLeft) {
537     row.parenthesesLeft = row.parenthesesLeft + '('
538   } else {
539     row.parenthesesLeft = '('
540   }
541 }
542
543 function removeParenthesesLeft(index, row) {
544   if (row.parenthesesLeft) {
545     row.parenthesesLeft = row.parenthesesLeft.substring(0, row.parenthesesLeft.length - 1)
546   } else {
547     row.parenthesesLeft = ''
548   }
549 }
550
551 function addParenthesesRight(index, row) {
552   if (row.parenthesesRight) {
553     row.parenthesesRight = row.parenthesesRight + ')'
554   } else {
555     row.parenthesesRight = ')'
556   }
557 }
558
559 function removeParenthesesRight(index, row) {
560   if (row.parenthesesRight) {
561     row.parenthesesRight = row.parenthesesRight.substring(0, row.parenthesesRight.length - 1)
562   } else {
563     row.parenthesesRight = ''
564   }
565 }
566
567 function numAscSort(a, b) {
568   return a - b
569 }
570
571 // 获取数据源选项
572 const getSourceOption = async () => {
573   sourceOptions.value = await TagApi.getTagTree()
574 }
575
576 const getPointList = async () => {
577   pointList.value = await DaPoint.getPointList(queryParams)
578 }
579
580 const getInfo = async (id) => {
581   formData.value = await DaPoint.getDaPoint(id)
582   expressionList.value = []
583   if (formData.value.pointType &&
584     formData.value.pointType === 'CALCULATE' &&
585     formData.value.mathPoint.expression) {
586     let expression = formData.value.mathPoint.expression
587     do {
588       let indexArray = [
589         expression.indexOf('+'),
590         expression.indexOf('-'),
591         expression.indexOf('*'),
592         expression.indexOf('/'),
593         expression.indexOf('&'),
594         expression.indexOf('|'),
595         expression.indexOf('!'),
596         expression.indexOf('>'),
597         expression.indexOf('<')
598       ].sort(numAscSort)
599       if (indexArray[indexArray.length - 1] !== -1) {
600         let endIndex = 0
601         for (let key in indexArray) {
602           if (indexArray[key] > -1) {
603             endIndex = indexArray[key]
604             break
605           }
606         }
607
608         // 运算值
609         let pointStr = expression.substring(0, endIndex)
610         debugger
611         // 运算符
612         let operator = expression.substr(endIndex, 1)
613         let indexOfParenthesesLeft = pointStr.indexOf('(')
614         let lastIndexOfParenthesesLeft = pointStr.lastIndexOf('(')
615
616         // 左括号
617         let parenthesesLeft = ''
618         if (indexOfParenthesesLeft !== -1 && lastIndexOfParenthesesLeft !== -1) {
619           parenthesesLeft = pointStr.substring(indexOfParenthesesLeft, lastIndexOfParenthesesLeft + 1)
620           pointStr = pointStr.substring(lastIndexOfParenthesesLeft + 1)
621         }
622
623         let indexOfParenthesesRight = pointStr.indexOf(')')
624         let lastIndexOfParenthesesRight = pointStr.lastIndexOf(')')
625
626         // 右括号
627         let parenthesesRight = ''
628         if (indexOfParenthesesRight !== -1 && lastIndexOfParenthesesRight !== -1) {
629           parenthesesRight = pointStr.substring(indexOfParenthesesRight, lastIndexOfParenthesesRight + 1)
630           pointStr = pointStr.substring(0, indexOfParenthesesRight)
631         }
632         expressionList.value.push({
633           parenthesesLeft: parenthesesLeft,
634           point: pointStr,
635           parenthesesRight: parenthesesRight,
636           operator: operator
637         })
638         expression = expression.substring(endIndex + 1)
1c14d6 639       } else {
660c92 640         let pointStr = expression
L 641         let indexOfParenthesesLeft = pointStr.indexOf('(')
642         let lastIndexOfParenthesesLeft = pointStr.lastIndexOf('(')
643         let parenthesesLeft = ''
644         if (indexOfParenthesesLeft !== -1 && lastIndexOfParenthesesLeft !== -1) {
645           parenthesesLeft = pointStr.substring(indexOfParenthesesLeft, lastIndexOfParenthesesLeft + 1)
646           pointStr = pointStr.substring(lastIndexOfParenthesesLeft + 1)
647         }
648         let indexOfParenthesesRight = pointStr.indexOf(')')
649         let lastIndexOfParenthesesRight = pointStr.lastIndexOf(')')
650         let parenthesesRight = ''
651         if (indexOfParenthesesRight !== -1 && lastIndexOfParenthesesRight !== -1) {
652           parenthesesRight = pointStr.substring(indexOfParenthesesRight, lastIndexOfParenthesesRight + 1)
653           pointStr = pointStr.substring(0, indexOfParenthesesRight)
654         }
655         expressionList.value.push({
656           parenthesesLeft: parenthesesLeft,
657           point: pointStr,
658           parenthesesRight: parenthesesRight,
659           operator: ''
660         })
661         expression = ''
1c14d6 662       }
660c92 663     } while (expression && expression.length > 0)
1c14d6 664   }
660c92 665 }
1c14d6 666
L 667 </script>
660c92 668 <style>
L 669 .el-select {
670   width: 100%
671 }
672 </style>