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