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