Selaa lähdekoodia

[Wip 0000] 瓦斯、通风、粉尘及火灾预测曲线图开发及对接

houzekong 2 kuukautta sitten
vanhempi
commit
2ab39410a7

+ 59 - 111
src/views/vent/monitorManager/alarmMonitor/common/echartLine3.vue

@@ -4,22 +4,23 @@
 
 <script lang="ts" setup>
   import * as echarts from 'echarts';
-  import { ref, nextTick, reactive, watch, defineProps } from 'vue';
+  import { ref, nextTick, watch, defineProps } from 'vue';
 
-  let props = defineProps({
-    deviceId: {
-      type: String,
-    },
-  });
+  let props = defineProps<{
+    xData: string[];
+    y1Data: number[];
+    y2Data: number[];
+    y3Data: number[];
+    y4Data: number[];
+    yUnit?: string;
+  }>();
 
   //获取dom元素节点
   let work = ref<any>();
-  let echartDataWds = reactive({});
 
   watch(
-    () => props.deviceId,
-    (data) => {
-      echartDataWds = Object.assign({}, data);
+    () => props.xData,
+    () => {
       getOption();
     },
     { immediate: true, deep: true }
@@ -30,112 +31,69 @@
       const myChart = echarts.init(work.value);
       let option = {
         tooltip: {
-          trigger: 'axis',
+          trigger: 'item',
           backgroundColor: 'rgba(0, 0, 0, .6)',
           textStyle: {
             color: '#fff',
             fontSize: 12,
           },
         },
-
+        grid: {
+          top: '15%',
+          left: '10%',
+          bottom: '10%',
+          right: '2%',
+        },
         legend: {
           align: 'left',
-          right: '50%',
           top: '0%',
           type: 'plain',
           textStyle: {
             color: '#7ec7ff',
             fontSize: 14,
           },
-          // icon:'rect',
-          itemGap: 25,
-          itemWidth: 18,
-          icon: 'path://M0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v0a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z',
-          data: [
-            {
-              name: echartDataWds.maxData ? echartDataWds.maxData.lengedData : '',
-            },
-          ],
+          itemGap: 10,
+          itemWidth: 5,
         },
-
-        grid: {
-          top: '20%',
-          left: '4%',
-          right: '4%',
-          bottom: '20%',
-          // containLabel: true
-        },
-
         xAxis: [
           {
             type: 'category',
-            boundaryGap: false,
-            axisLine: {
-              //坐标轴轴线相关设置。数学上的x轴
-              show: true,
-              lineStyle: {
-                color: '#244a94',
-              },
-            },
             axisLabel: {
-              //坐标轴刻度标签的相关设置
               textStyle: {
                 color: '#b3b8cc',
-                padding: 5,
-                fontSize: 14,
-              },
-              formatter: function (data) {
-                return data;
               },
             },
+            // axisLine: {
+            //   lineStyle: {
+            //     color: '#244a94',
+            //   },
+            // },
             splitLine: {
-              show: true,
-              lineStyle: {
-                color: '#0d2973',
-                type: 'dashed',
-              },
+              show: false,
             },
             axisTick: {
               show: false,
             },
-            data: echartDataWds.xData,
+            data: props.xData,
           },
         ],
-
         yAxis: [
           {
-            name: '(℃)',
-            nameTextStyle: {
-              color: '#7ec7ff',
-              fontSize: 14,
-              padding: 0,
-            },
-            min: 0,
-            max: 100,
-            splitLine: {
-              show: true,
-              lineStyle: {
-                color: '#0d2973',
-                type: 'dashed',
-              },
-            },
-            axisLine: {
-              show: true,
-              lineStyle: {
-                color: '#244a94',
-              },
-            },
+            // boundaryGap: false,
             axisLabel: {
-              show: true,
               textStyle: {
                 color: '#b3b8cc',
-                padding: 5,
               },
-              formatter: function (value) {
-                if (value === 0) {
-                  return value;
-                }
-                return value;
+            },
+            name: props.yUnit,
+            // nameTextStyle: {
+            //   color: '#fff',
+            //   fontSize: 12,
+            //   lineHeight: 10,
+            // },
+            splitLine: {
+              lineStyle: {
+                color: '#0d2973',
               },
             },
             axisTick: {
@@ -145,66 +103,56 @@
         ],
         series: [
           {
-            name: echartDataWds.maxData ? echartDataWds.maxData.lengedData : '',
+            name: '平均值',
             type: 'line',
             smooth: true,
             yAxisIndex: 0,
-            symbolSize: 8,
+            symbolSize: 4,
             lineStyle: {
               normal: {
                 width: 2,
-                color: '#4653fd', // 线条颜色
               },
-              borderColor: 'rgba(0,0,0,.4)',
             },
-            itemStyle: {
-              color: '#4653fd',
-              borderColor: '#646ace',
-              borderWidth: 0,
-            },
-            data: echartDataWds.maxData ? echartDataWds.maxData.data : [],
+            data: props.y1Data,
           },
           {
-            name: echartDataWds.minData ? echartDataWds.minData.lengedData : '',
+            name: '最大值',
             type: 'line',
             smooth: true,
             yAxisIndex: 0,
-            symbolSize: 8,
-
+            symbolSize: 4,
             lineStyle: {
               normal: {
                 width: 2,
-                color: '#46fda8', // 线条颜色
               },
-              borderColor: 'rgba(0,0,0,.4)',
             },
-            itemStyle: {
-              color: '#46fda8',
-              borderColor: '#646ace',
-              borderWidth: 0,
-            },
-            data: echartDataWds.minData ? echartDataWds.minData.data : [],
+            data: props.y2Data,
           },
           {
-            name: echartDataWds.aveaData ? echartDataWds.aveaData.lengedData : '',
+            name: '最小值',
             type: 'line',
             smooth: true,
             yAxisIndex: 0,
-            symbolSize: 8,
-
+            symbolSize: 4,
             lineStyle: {
               normal: {
                 width: 2,
-                color: '#1eb0fc', // 线条颜色
               },
-              borderColor: 'rgba(0,0,0,.4)',
             },
-            itemStyle: {
-              color: '#1eb0fc',
-              borderColor: '#646ace',
-              borderWidth: 0,
+            data: props.y3Data,
+          },
+          {
+            name: '实时值',
+            type: 'line',
+            smooth: true,
+            yAxisIndex: 0,
+            symbolSize: 4,
+            lineStyle: {
+              normal: {
+                width: 2,
+              },
             },
-            data: echartDataWds.aveaData ? echartDataWds.aveaData.data : [],
+            data: props.y4Data,
           },
         ],
       };

+ 15 - 3
src/views/vent/monitorManager/alarmMonitor/common/fireWork.vue

@@ -35,7 +35,15 @@
     <div class="bot-content">
       <div class="title">
         <div class="text">束管系统监测</div>
-        <div class="select-box">
+        <div class="select-box flex">
+          <BaseTab
+            style="width: 200px; color: var(--vent-font-color); margin-right: 10px"
+            :tabs="[
+              { name: '束管监测', id: 'default' },
+              { name: '预测曲线', id: 'predict' },
+            ]"
+            v-model:id="shownChart"
+          />
           <a-select v-model:value="selectData" style="width: 250px" @change="changeSelect">
             <a-select-option v-for="file in selectList" :key="file.label" :value="file.value">{{ file.label }}</a-select-option>
           </a-select>
@@ -60,22 +68,26 @@
         </div>
       </div>
       <div class="echart-box">
-        <echartLine1 :echartDataSg="echartDataSg" :maxY="maxY1" :lengedDataName="echartDataSg.lengedDataName" />
+        <echartLine1 v-if="shownChart === 'default'" :echartDataSg="echartDataSg" :maxY="maxY1" :lengedDataName="echartDataSg.lengedDataName" />
+        <echartLine3 v-if="shownChart === 'predict'" :x-data="[]" :y1-data="[]" :y2-data="[]" :y3-data="[]" :y4-data="[]" />
       </div>
     </div>
   </div>
 </template>
 
 <script lang="ts" setup>
-  import { onMounted, ref, reactive, watch, defineProps } from 'vue';
+  import { ref, reactive, watch, defineProps } from 'vue';
   import imgUrl from '/@/assets/images/fire/pie.png';
   import echartLine from './echartLine.vue';
   import echartLine1 from './echartLine1.vue';
+  import echartLine3 from './echartLine3.vue';
   import { topList, contentList } from '../common.data';
+  import BaseTab from '../../../gas/components/tab/baseTab.vue';
 
   let props = defineProps({
     listData: Object,
   });
+  const shownChart = ref('default');
   let selectSj = ref<any[]>([]);
   let selectData = ref('');
   let selectList = reactive<any[]>([]);

+ 89 - 12
src/views/vent/monitorManager/alarmMonitor/common/measurePoint.vue

@@ -16,28 +16,36 @@
       />
     </div>
     <div v-if="shown === 'default'" class="content-item">
-      <div class="card-content" v-for="(item, index) in cards" :key="index">
+      <div class="card-content" v-for="(item, index) in cards" :key="`vmac${index}`">
         <div class="item-l">
           <div class="label-l">{{ item.label }}</div>
-          <div class="value-l">{{ `${item.value}%` }}</div>
+          <div class="value-l">{{ item.value }}</div>
         </div>
         <div class="item-r">
-          <div class="content-r" v-for="(items, ind) in item.listR" :key="ind">
-            <span>{{ `${items.label} : ` }}</span>
+          <div class="content-r" v-for="el in item.listR" :key="el.id">
+            <span>{{ `${el.label} : ` }}</span>
             <span
               :class="{
-                'status-f': items.value == 1,
-                'status-l': items.value == 0,
+                'status-f': el.value == 1,
+                'status-l': el.value == 0,
               }"
-              >{{ items.value == 1 ? '异常' : items.value == 0 ? '正常' : items.value }}</span
             >
+              {{ el.value == 1 ? '异常' : el.value == 0 ? '正常' : el.value }}
+            </span>
           </div>
         </div>
       </div>
     </div>
     <div v-if="shown === 'chart'" class="chart-item">
-      <div v-for="(item, index) in charts" :key="`acmt${index}`">
-        <EchartLine3 style="height: 270px; width: 350px; margin: 0 5px" />
+      <div v-for="(item, index) in chartsConfig" :key="`acmt${index}`">
+        <EchartLine3
+          style="height: 300px; width: 400px; margin: 0 5px"
+          :x-data="item.x"
+          :y1-data="item.y1"
+          :y2-data="item.y2"
+          :y3-data="item.y3"
+          :y4-data="item.y4"
+        />
         <div class="text-center">
           {{ item.label }}
         </div>
@@ -46,17 +54,86 @@
   </div>
 </template>
 <script setup lang="ts">
-  import { ref } from 'vue';
+  import { ref, watch } from 'vue';
   import EchartLine3 from './echartLine3.vue';
   import BaseTab from '../../../gas/components/tab/baseTab.vue';
+  import moment from 'moment';
 
-  defineProps<{
+  const props = defineProps<{
     cards: { label: string; value: any; listR: { id: number; label: string; dw: string; value: any }[] }[];
-    charts: { label: string; data: { x: string; y: number }[] }[];
+    charts: { label: string; time: Date; data: [number, number, number, number] }[];
     title: string;
+    timeout?: number;
   }>();
 
   const shown = ref('default');
+  const chartsConfig = ref<
+    {
+      label: string;
+      /** 下一项数据更新后应该替换配置中的哪项数据的标志 */
+      indexMark: number;
+      x: string[];
+      y1: number[];
+      y2: number[];
+      y3: number[];
+      y4: number[];
+    }[]
+  >([]);
+
+  watch(
+    () => props.charts,
+    () => {
+      const arr = new Array(20).fill(0);
+      props.charts.forEach((el, i) => {
+        if (chartsConfig.value[i]) {
+          // 由于上面这些数据都是 20 项组成的,当指针移动到 20 时说明上次更新了最后一项
+          // 那么应该按先进后出的队列模式更新数据了
+          const val = chartsConfig.value[i];
+          if (val.indexMark === 20) {
+            val.x.shift();
+            val.y1.shift();
+            val.y2.shift();
+            val.y3.shift();
+            val.y4.shift();
+            val.indexMark = 19;
+          }
+          val.x[val.indexMark] = moment(el.time).format('HH:mm:ss');
+          val.y1[val.indexMark] = el.data[0];
+          val.y2[val.indexMark] = el.data[1];
+          val.y3[val.indexMark] = el.data[2];
+          val.y4[val.indexMark] = el.data[3];
+          // 指针向后移动1
+          val.indexMark += 1;
+        } else {
+          // 更新配置
+          // 初始化配置数据,按照一项数据,生成一个由 20 项数据组成的数组,该数组由此项数据衍生
+          const startFrom = moment(el.time);
+          chartsConfig.value[i] = {
+            label: el.label,
+            indexMark: 1,
+            x: arr.map(() => {
+              const str = startFrom.format('HH:mm:ss');
+              startFrom.add(props.timeout || 3000);
+              return str;
+            }),
+            y1: arr.map(() => {
+              return el.data[0];
+            }),
+            y2: arr.map(() => {
+              return el.data[1];
+            }),
+            y3: arr.map(() => {
+              return el.data[2];
+            }),
+            y4: arr.map(() => {
+              return el.data[3];
+            }),
+          };
+        }
+      });
+    },
+    { immediate: true, deep: true }
+  );
 </script>
 <style lang="less">
   @import '/@/design/theme.less';

+ 11 - 6
src/views/vent/monitorManager/alarmMonitor/warn/dustWarn.vue

@@ -61,6 +61,7 @@
   import CustomHeader from '/@/components/vent/customHeader.vue';
   import { usePermission } from '/@/hooks/web/usePermission';
   import MeasurePoint from '../common/measurePoint.vue';
+  import moment from 'moment';
 
   const { hasPermission } = usePermission();
   const { options, optionValue, getSelectRow, getSysDataSource } = useSystemSelect('sys_surface_caimei'); // 参数为场景类型(设备类型管理中可以查询到)
@@ -98,7 +99,7 @@
     right: '5%',
     containLabel: true,
   });
-  let cardListTf = reactive<any[]>([]);
+  const cardListTf = reactive<any[]>([]);
   const chartListTf = reactive<any[]>([]);
   let router = useRouter();
   let echartNow = ref<any[]>([]);
@@ -181,6 +182,7 @@
     sysWarn({ sysid: id, type: type }).then((res) => {
       // listData.common = res;
       topAreaList.length = 0;
+      chartListTf.length = 0;
 
       if (JSON.stringify(res) != '{}') {
         res.dust.forEach((el) => {
@@ -193,6 +195,13 @@
               { ids: 3, label: '喷雾状态', value: el.readData.atomizingState || '--' },
             ],
           });
+
+          // 初始化预测曲线配置,分别为x轴时间、平均、最大、最小、实时
+          chartListTf.push({
+            label: el.strinstallpos,
+            time: new Date(),
+            data: [moment().format('ss'), 15, 5, 10],
+          });
         });
         choiceData = res.dust;
 
@@ -287,10 +296,10 @@
       }
     });
   }
+
   //获取粉尘监控测点信息
   async function getWindDeviceList() {
     cardListTf.length = 0;
-    chartListTf.length = 0;
     let res = await getDevice({ devicetype: 'dusting', pagetype: 'normal' });
     if (res && res.msgTxt[0]) {
       let list = res.msgTxt[0].datalist || [];
@@ -319,10 +328,6 @@
               },
             ],
           });
-          chartListTf.push({
-            label: el.strinstallpos,
-            data: [],
-          });
         });
       }
     }

+ 6 - 3
src/views/vent/monitorManager/alarmMonitor/warn/gasWarn.vue

@@ -76,7 +76,7 @@
         </div>
 
         <div :class="topAreaListWs.length != 0 ? 'bot-area' : 'bot-area1'">
-          <MeasurePoint title="安全监控测点信息" :cards="cardListWs" :charts="chartListWs" />
+          <MeasurePoint title="安全监控测点信息" :timeout="1000" :cards="cardListWs" :charts="chartListWs" />
         </div>
       </div>
       <div style="width: 100%; height: 100%" v-else-if="isShow == 'yjzb'">
@@ -101,6 +101,7 @@
   import { usePermission } from '/@/hooks/web/usePermission';
   import { useGlobSetting } from '/@/hooks/setting';
   import MeasurePoint from '../common/measurePoint.vue';
+  import moment from 'moment';
 
   let typeMenuListGas = getMonitorComponent();
   const { sysOrgCode } = useGlobSetting();
@@ -173,7 +174,7 @@
           el.strinstallpos = el.strinstallpos.indexOf('&') == -1 ? el.strinstallpos : el.strinstallpos.substring(0, el.strinstallpos.indexOf('&'));
           cardListWs.push({
             label: '甲烷',
-            value: el.readData.gasC || '--',
+            value: el.readData.gasC + '%' || '--',
             // value: 0,
             listR: [
               { id: 0, label: '测点类型', value: '瓦斯' },
@@ -183,9 +184,11 @@
               { id: 3, label: '测点状态', value: el.warnFlag },
             ],
           });
+          // 初始化预测曲线配置,分别为x轴时间、平均、最大、最小、实时
           chartListWs.push({
             label: el.strinstallpos,
-            data: [],
+            time: new Date(),
+            data: [moment().format('ss'), 15, 5, 10],
           });
         });
       }

+ 12 - 7
src/views/vent/monitorManager/alarmMonitor/warn/ventilateWarn.vue

@@ -58,7 +58,7 @@
     </div>
     <div class="ventilate-bottom">
       <div class="bot-area">
-        <MeasurePoint title="通风监控测点信息" :cards="cardListTf" :charts="chartListTf" />
+        <MeasurePoint title="通风监控测点信息" :timeout="1000" :cards="cardListTf" :charts="chartListTf" />
       </div>
     </div>
   </div>
@@ -74,6 +74,7 @@
   import echartLine from '../common/echartLine.vue';
   import { usePermission } from '/@/hooks/web/usePermission';
   import MeasurePoint from '../common/measurePoint.vue';
+  import moment from 'moment';
 
   const { hasPermission } = usePermission();
   const { options, optionValue, getSelectRow, getSysDataSource } = useSystemSelect('sys_surface_caimei'); // 参数为场景类型(设备类型管理中可以查询到)
@@ -124,7 +125,6 @@
   //获取左侧数据列表
   async function getMenuList() {
     let res = await sysTypeWarnList({ type: 'vent' });
-    console.log(res, '通风预警监测左侧列表数据-------------');
     if (res.length != 0) {
       menuList.length = 0;
       res.forEach((el) => {
@@ -151,12 +151,22 @@
       echartDataFc1.minData.data.length = 0;
       echartDataFc1.aveValue.data.length = 0;
       echartDataFc1.xData.length = 0;
+      chartListTf.length = 0;
       if (JSON.stringify(res) != '{}') {
         ventilateTopList[0].value = res.jin || '--';
         ventilateTopList[1].value = res.hui || '--';
         ventilateTopList[2].value = res.xufengliang || '--';
         ventilateTopList[3].text = res.warnFlag ? res.warnDes : '正常';
 
+        res.vent.forEach((el) => {
+          // 初始化预测曲线配置,分别为x轴时间、平均、最大、最小、实时
+          chartListTf.push({
+            label: el.strinstallpos,
+            time: new Date(),
+            data: [moment().format('ss'), 15, 5, 10],
+          });
+        });
+
         if (res.history.length != 0) {
           res.history.forEach((v) => {
             echartDataFc1.maxData.data.push(parseFloat(v.jin));
@@ -199,7 +209,6 @@
   //获取通风监控测点信息
   async function getWindDeviceList() {
     cardListTf.length = 0;
-    chartListTf.length = 0;
     let res = await getDevice({ devicetype: 'windrect', pagetype: 'normal' });
     if (res && res.msgTxt[0]) {
       let list = res.msgTxt[0].datalist || [];
@@ -223,10 +232,6 @@
               },
             ],
           });
-          chartListTf.push({
-            label: el.strinstallpos,
-            data: [],
-          });
         });
       }
     }