Pārlūkot izejas kodu

多灾融合预警模块界面及功能调整优化-提交

lxh 5 dienas atpakaļ
vecāks
revīzija
e7b05badab
22 mainītis faili ar 2383 papildinājumiem un 4164 dzēšanām
  1. 0 80
      src/views/vent/monitorManager/alarmMonitor/common/PipeWarn.vue
  2. 0 898
      src/views/vent/monitorManager/alarmMonitor/common/closeWall-111.vue
  3. 11 13
      src/views/vent/monitorManager/alarmMonitor/common/closeWall.vue
  4. 0 236
      src/views/vent/monitorManager/alarmMonitor/common/echartLine1.vue
  5. 0 260
      src/views/vent/monitorManager/alarmMonitor/common/echartLine2.vue
  6. 111 93
      src/views/vent/monitorManager/alarmMonitor/common/external-gx-echart.vue
  7. 477 400
      src/views/vent/monitorManager/alarmMonitor/common/external-mb.vue
  8. 52 81
      src/views/vent/monitorManager/alarmMonitor/common/external-sgjc.vue
  9. 70 86
      src/views/vent/monitorManager/alarmMonitor/common/fireWork.vue
  10. 38 65
      src/views/vent/monitorManager/alarmMonitor/common/gasCcb.vue
  11. 141 192
      src/views/vent/monitorManager/alarmMonitor/common/internal-fire-bot.vue
  12. 22 59
      src/views/vent/monitorManager/alarmMonitor/common/internal-fire-bot1.vue
  13. 88 73
      src/views/vent/monitorManager/alarmMonitor/common/internal-fire-center.vue
  14. 24 22
      src/views/vent/monitorManager/alarmMonitor/common/internal-fire-top.vue
  15. 19 21
      src/views/vent/monitorManager/alarmMonitor/common/mainWell.vue
  16. 0 252
      src/views/vent/monitorManager/alarmMonitor/common/measurePoint copy.vue
  17. 14 19
      src/views/vent/monitorManager/alarmMonitor/common/top-area.vue
  18. 159 259
      src/views/vent/monitorManager/alarmMonitor/warn/dustWarn.vue
  19. 119 165
      src/views/vent/monitorManager/alarmMonitor/warn/fireWarn.vue
  20. 376 502
      src/views/vent/monitorManager/alarmMonitor/warn/gasWarn.vue
  21. 174 210
      src/views/vent/monitorManager/alarmMonitor/warn/ventilateWarn.vue
  22. 488 178
      src/views/vent/testChart/FiberTempChart.vue

+ 0 - 80
src/views/vent/monitorManager/alarmMonitor/common/PipeWarn.vue

@@ -1,80 +0,0 @@
-<template>
-  <div class="warnTarget">
-    <div class="top-section">
-      <a-table :columns="columns" :data-source="tableData" bordered :pagination="false">
-        <template #bodyCell="{ column, text }">
-          <template v-if="column.dataIndex === 'name'">
-            <a href="javascript:;">{{ text }}</a>
-          </template>
-        </template>
-      </a-table>
-    </div>
-    <div class="bottom-section"></div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { ref, reactive } from 'vue';
-
-let columns = reactive([
-  {
-    title: '序号',
-    width: 60,
-    align: 'center',
-  },
-  {
-    title: '一级指标',
-    dataIndex: 'one',
-    align: 'center',
-  },
-  {
-    title: '二级指标',
-    dataIndex: 'two',
-    align: 'center',
-  },
-  {
-    title: '三级指标',
-    align: 'center',
-    dataIndex: 'three',
-  },
-  {
-    title: '低风险',
-    dataIndex: 'warnLow',
-    align: 'center',
-  },
-  {
-    title: '一般风险',
-    dataIndex: 'warnCen',
-    align: 'center',
-  },
-  {
-    title: '较高风险',
-    dataIndex: 'warnJg',
-    align: 'center',
-  },
-  {
-    title: '高风险',
-    dataIndex: 'warnHign',
-    align: 'center',
-  },
-]);
-</script>
-
-<style lang="less" scoped>
-.warnTarget {
-  width: 100%;
-  height: 100%;
-  padding: 20px;
-  box-sizing: border-box;
-  display: flex;
-  flex-direction: column;
-}
-.top-section,
-.bottom-section {
-  flex: 1;
-  min-height: 0;
-}
-.bottom-section {
-  overflow: hidden;
-}
-</style>

+ 0 - 898
src/views/vent/monitorManager/alarmMonitor/common/closeWall-111.vue

@@ -1,898 +0,0 @@
-<template>
-  <div class="closeWall">
-    <div class="title">
-      <div class="box-container">
-        <div class="contents">
-          <div class="text">
-            <div class="text-label">位置: </div>
-            <!-- <div class="text-value">{{ topContent.position }}</div> -->
-            <div class="text-value">
-              <a-select v-model:value="selectData" style="width: 360px" @change="changeSelect">
-                <a-select-option v-for="file in selectList" :key="file.label" :value="file.value">{{ file.label }}</a-select-option>
-              </a-select>
-            </div>
-          </div>
-          <div class="text">
-            <span class="text-label">时间 : </span>
-            <span class="text-value">{{ topContent.time }}</span>
-          </div>
-        </div>
-        <div class="contents">
-          <img src="@/assets/images/fire/pie.png" alt="" />
-          <span class="text">{{ topContent.temperature }}</span>
-          <span class="dw">°C</span>
-        </div>
-      </div>
-      <div class="box-container">
-        <div class="text1">
-          <span>预警等级 : </span>
-          <span
-            :class="{
-              value1: topContent.warnLevel == '绿色预警',
-              value2: topContent.warnLevel == '黄色预警',
-              value3: topContent.warnLevel == '红色预警',
-              value4: topContent.warnLevel == '橙色预警',
-            }"
-            >{{ topContent.warnLevel || '-' }}</span
-          >
-        </div>
-        <div class="text1">
-          <span>煤自燃阶段 : </span>
-          <span>{{ topContent.smokeJd || '-' }}</span>
-        </div>
-      </div>
-      <div class="pl-10px pr-10px">
-        <div class="mb-10px">
-          <AButton class="w-full" type="primary" @click="controlDevice('dianwei', 'zhi')">应急启动</AButton>
-        </div>
-        <div>
-          <AButton class="w-full" type="primary" @click="controlDevice('dianwei', 'zhi')">应急关闭</AButton>
-        </div>
-      </div>
-    </div>
-    <div class="content">
-      <div class="title-b">采空区密闭参数</div>
-      <div class="card-btn">
-        <div
-          :class="activeIndex == index ? 'box-container1' : 'box-container'"
-          v-for="(item, index) in mbList"
-          :key="index"
-          @click="btnClick(item, index)"
-        >
-          <div class="box-label">
-            <span> {{ item.label }}</span>
-            <span>{{ item.dw }}</span>
-          </div>
-          <div class="box-item box-item1">
-            <span class="text-t">{{ `${item.label1}:` }}</span>
-            <span class="text-v">{{ item.nd }}</span>
-          </div>
-          <div class="box-item box-item2">
-            <span class="text-t">{{ `${item.label2}:` }}</span>
-            <span class="text-v">{{ item.time1 }}</span>
-          </div>
-          <div class="box-item box-item3">
-            <span class="text-t">{{ `${item.label3}:` }}</span>
-            <span class="text-v">{{ item.address }}</span>
-          </div>
-        </div>
-      </div>
-      <div class="echart-box">
-        <div class="left-echartbox">
-          <div class="title-f">
-            <div class="title-text">
-              {{ `${type}趋势` }}&nbsp; <span style="color: red">{{ netStatus != 1 ? '(设备未连接)' : '' }}</span>
-            </div>
-
-            <!-- <BaseTab
-              style="width: 180px; color: var(--vent-font-color)"
-              :tabs="[
-                { name: '实时监测', id: 'default' },
-                { name: '预测曲线', id: 'predict' },
-              ]"
-              v-model:id="shownChart"
-            /> -->
-          </div>
-          <div class="echarts-box">
-            <PredictionCurve v-if="shownChart === 'default'" :chart="curveConfig" />
-            <echartLine1
-              v-if="shownChart === 'predict'"
-              :echartDataSg="echartDataSg1"
-              :lengedDataName="echartDataSg1.lengedDataName"
-              :maxY="maxY"
-              :minY="minY"
-            />
-          </div>
-        </div>
-        <div class="right-echartbox">
-          <warnZb
-            :widthV="widthV"
-            :heightV="heightV"
-            :coordDw="coordDw"
-            :widthCanvas="widthCanvas"
-            :heightCanvas="heightCanvas"
-            :warnLevel="topContent.warnLevel"
-          />
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import { ref, reactive, watch, inject, h } from 'vue';
-  import echartLine1 from './echartLine1.vue';
-  import warnZb from './warnZb.vue';
-  import PredictionCurve from './predictionCurve.vue';
-  import { Modal, Input } from 'ant-design-vue';
-  import { getMaxY, getMinY } from '../common.data';
-  // import { deviceControlApi } from '/@/api/vent/index';
-
-  let props = defineProps({
-    listData: Object,
-  });
-
-  const globalConfig = inject('globalConfig');
-  const shownChart = ref('default');
-  let maxY = ref<any>(0);
-  let minY = ref<any>(0);
-  let selectSj = ref<any[]>([]);
-  let selectData = ref('');
-  let selectList = reactive<any[]>([]);
-  let widthV = ref('75%');
-  let heightV = ref('80%');
-  let coordDw = ref<any[]>([31, 62, 110]);
-  let widthCanvas = ref(562);
-  let heightCanvas = ref(316);
-  //设备连接状态
-  let netStatus = ref(0);
-  //密闭-顶部区域数据
-  let topContent = reactive({
-    temperature: 0,
-    position: '',
-    time: '',
-    warnLevel: '',
-    smokeJd: '',
-  });
-  //密闭参数列表
-  let mbList = reactive([
-    {
-      label: 'O₂',
-      dw: '(%)',
-      label1: '浓度',
-      label2: '时间',
-      label3: '位置',
-      nd: '0',
-      time1: '',
-      address: '',
-    },
-    {
-      label: 'CO',
-      dw: '(ppm)',
-      label1: '浓度',
-      label2: '时间',
-      label3: '位置',
-      nd: '0',
-      time1: '',
-      address: '',
-    },
-    {
-      label: 'CO₂',
-      dw: '(%)',
-      label1: '浓度',
-      label2: '时间',
-      label3: '位置',
-      nd: '0',
-      time1: '',
-      address: '',
-    },
-    {
-      label: 'CH₄',
-      dw: '(%)',
-      label1: '浓度',
-      label2: '时间',
-      label3: '位置',
-      nd: '0',
-      time1: '',
-      address: '',
-    },
-    {
-      label: 'C₂H₂',
-      dw: '(ppm)',
-      label1: '浓度',
-      label2: '时间',
-      label3: '位置',
-      nd: '0',
-      time1: '',
-      address: '',
-    },
-    {
-      label: 'C₂H₄',
-      dw: '(ppm)',
-      label1: '浓度',
-      label2: '时间',
-      label3: '位置',
-      nd: '0',
-      time1: '',
-      address: '',
-    },
-  ]);
-
-  //当前密闭参数激活选项
-  let activeIndex = ref(0);
-  //当前激活密闭参数类型
-  let type = ref('O₂');
-
-  let echartDataSg1 = reactive({
-    xData: [],
-    yData: [],
-    lengedData: 'O₂',
-    lengedDataName: '(%)',
-  });
-  let echartDataSgList = reactive<any[]>([]);
-
-  function getmax() {
-    getMaxY(echartDataSg1.yData);
-    getMinY(echartDataSg1.yData);
-    // maxY.value = echartDataSg1.yData.reduce((acr, cur) => {
-    //   return acr > cur ? acr : cur;
-    // });
-    // maxY.value =
-    //   maxY.value.toString().indexOf('.') == -1 ? maxY.value.toString() : maxY.value.toString().substring(0, maxY.value.toString().indexOf('.'));
-    // if (maxY.value.length < 2 && Number(maxY.value) < 1) {
-    //   maxY.value = 1;
-    // } else if (maxY.value.length < 2 && Number(maxY.value) >= 1) {
-    //   maxY.value = 10;
-    // } else if (maxY.value.length < 3) {
-    //   maxY.value = (Number(maxY.value[0]) + 1) * 10;
-    // } else if (maxY.value.length < 4) {
-    //   maxY.value = (Number(maxY.value[0]) + 1) * 100;
-    // } else if (maxY.value.length < 5) {
-    //   maxY.value = (Number(maxY.value[0]) + 1) * 1000;
-    // } else if (maxY.value.length < 6) {
-    //   maxY.value = (Number(maxY.value[0]) + 1) * 10000;
-    // }
-  }
-  //密闭参数选项切换
-  function btnClick(item, ind) {
-    // debugger;
-    activeIndex.value = ind;
-    type.value = item.label;
-    echartDataSg1.xData.length = 0;
-    echartDataSg1.yData.length = 0;
-    echartDataSg1.lengedData = type.value;
-    echartDataSg1.lengedDataName = item.dw;
-
-    const data = selectSj.value.filter((v) => v.strinstallpos == selectData.value)[0];
-    switch (type.value) {
-      case 'O₂':
-        echartDataSgList.forEach((el) => {
-          echartDataSg1.xData.push(el.time);
-          echartDataSg1.yData.push(el.o2val);
-        });
-
-        curveConfig.value = {
-          id: 'o2',
-          label: 'O₂',
-          time: echartDataSg1.xData,
-          data: [
-            // 氧气预测曲线
-            data.avgParam?.avg_o2_value || 0,
-            data.avgParam?.max_o2_value || 0,
-            data.avgParam?.min_o2_value || 0,
-            // data.readData?.o2val,
-          ],
-          monitorData: echartDataSg1.yData,
-        };
-        getmax();
-        break;
-      case 'C₂H₄':
-        echartDataSgList.forEach((el) => {
-          echartDataSg1.xData.push(el.time);
-          echartDataSg1.yData.push(el.ch2val);
-        });
-        curveConfig.value = {
-          id: 'ch2',
-          label: 'C₂H₄',
-          time: echartDataSg1.xData,
-          data: [
-            // 预测曲线
-            data.avgParam?.avg_c2h4_value || 0,
-            data.avgParam?.max_c2h4_value || 0,
-            data.avgParam?.min_c2h4_value || 0,
-            // data.readData?.ch2val,
-          ],
-          monitorData: echartDataSg1.yData,
-        };
-        getmax();
-        break;
-      case 'CO':
-        echartDataSgList.forEach((el) => {
-          echartDataSg1.xData.push(el.time);
-          echartDataSg1.yData.push(el.coval);
-        });
-        curveConfig.value = {
-          id: 'co',
-          label: 'CO',
-          time: echartDataSg1.xData,
-          data: [
-            // 预测曲线
-            data.avgParam?.avg_co_value || 0,
-            data.avgParam?.max_co_value || 0,
-            data.avgParam?.min_co_value || 0,
-            // data.readData?.coval,
-          ],
-          monitorData: echartDataSg1.yData,
-        };
-        getmax();
-        break;
-      case 'CH₄':
-        echartDataSgList.forEach((el) => {
-          echartDataSg1.xData.push(el.time);
-          echartDataSg1.yData.push(el.gasval);
-        });
-        curveConfig.value = {
-          id: 'ch',
-          label: 'CH₄',
-          time: echartDataSg1.xData,
-          data: [
-            // 预测曲线
-            data.avgParam?.avg_ch4_value || 0,
-            data.avgParam?.max_ch4_value || 0,
-            data.avgParam?.min_ch4_value || 0,
-            // data.readData?.chval,
-          ],
-          monitorData: echartDataSg1.yData,
-        };
-        getmax();
-        break;
-      case 'CO₂':
-        echartDataSgList.forEach((el) => {
-          echartDataSg1.xData.push(el.time);
-          echartDataSg1.yData.push(el.co2val);
-        });
-        curveConfig.value = {
-          id: 'co2',
-          label: 'CO₂',
-          time: echartDataSg1.xData,
-          data: [
-            // 预测曲线
-            data.avgParam?.avg_co2_value || 0,
-            data.avgParam?.max_co2_value || 0,
-            data.avgParam?.min_co2_value || 0,
-            // data.readData?.co2val,
-          ],
-          monitorData: echartDataSg1.yData,
-        };
-        getmax();
-        break;
-      case 'C₂H₂':
-        echartDataSgList.forEach((el) => {
-          echartDataSg1.xData.push(el.time);
-          echartDataSg1.yData.push(el.chval);
-        });
-        curveConfig.value = {
-          id: 'gas',
-          label: 'C₂H₂',
-          time: echartDataSg1.xData,
-          data: [
-            // 预测曲线
-            data.avgParam?.avg_c2h2_value || 0,
-            data.avgParam?.max_c2h2_value || 0,
-            data.avgParam?.min_c2h2_value || 0,
-            // data.readData?.gasval,
-          ],
-          monitorData: echartDataSg1.yData,
-        };
-        getmax();
-        break;
-    }
-  }
-
-  function changeSelect(val) {
-    selectData.value = val;
-    let data = selectSj.value.filter((v) => v.strinstallpos == selectData.value)[0];
-    topContent.time = data.readTime || '--';
-    topContent.warnLevel = data.syswarnLevel_str;
-    topContent.smokeJd = data.syswarnLevel_des;
-
-    mbList[0].nd = data.readData.o2val || '--';
-    mbList[1].nd = data.readData.coval || '--';
-    mbList[2].nd = data.readData.co2val || '--';
-    mbList[3].nd = data.readData.gasval || '--';
-    mbList[4].nd = data.readData.chval || '--';
-    mbList[5].nd = data.readData.ch2val || '--';
-    mbList.forEach((el) => {
-      el.time1 = data ? data.readTime.substring(0, data.readTime.lastIndexOf(':')) : '--';
-      el.address = data ? data.strinstallpos : '--';
-    });
-    netStatus.value = data['netStatus'];
-  }
-
-  // 设备控制
-  function controlDevice(code, value?) {
-    const passWord = ref('');
-    Modal.confirm({
-      title: '是否确认执行该操作?',
-      maskClosable: true,
-      content: () => {
-        return h(Input, {
-          placeholder: '请输入密码',
-          type: 'password',
-          modelValue: passWord.value,
-          'onUpdate:value'(val) {
-            passWord.value = val;
-          },
-        });
-      },
-      onOk() {
-        console.log('OK', passWord);
-      },
-    });
-    // Promise.all(
-    //   [].map(({ deviceID, deviceType }) => {
-    //     return deviceControlApi({
-    //       deviceid: deviceID,
-    //       devicetype: deviceType,
-    //       paramcode: code,
-    //       value,
-    //       // password: passWord || globalConfig?.simulatedPassword,
-    //     });
-    //   })
-    // ).then((res) => {
-    //   // 模拟时开启
-    //   if (res.success) {
-    //     if (globalConfig.History_Type == 'remote') {
-    //       message.success('指令已下发至生产管控平台成功!');
-    //     } else {
-    //       message.success('指令已下发成功!');
-    //     }
-    //   } else {
-    //     message.error(res.message);
-    //   }
-    // });
-  }
-
-  /** 预测曲线的配置,数据分别为平均、最大、最小、当前值 */
-  const curveConfig = ref<any>({ id: '0', label: '', time: new Date(), data: [0, 0, 0, 0] });
-
-  watch(
-    () => props.listData,
-    (val: any) => {
-      echartDataSg1.xData.length = 0;
-      echartDataSg1.yData.length = 0;
-      echartDataSgList.length = 0;
-      selectList.length = 0;
-      if (JSON.stringify(val) === '{}') return;
-      if (val.bundletube.length != 0) {
-        selectSj.value = val.bundletube;
-        selectSj.value.forEach((el) => {
-          selectList.push({ label: el.strinstallpos, value: el.strinstallpos });
-        });
-        selectData.value = selectData.value ? selectData.value : selectList[0].value;
-        let dataVal = selectData.value ? selectSj.value.filter((v) => v.strinstallpos == selectData.value)[0] : selectSj.value[0];
-        topContent.temperature = val.temperature[0] ? val.temperature[0].readData.temperature : '--';
-        topContent.time = dataVal.readTime || '--';
-        topContent.warnLevel = dataVal.syswarnLevel_str;
-        topContent.smokeJd = dataVal.syswarnLevel_des;
-
-        mbList[0].nd = dataVal.readData.o2val || '--';
-        mbList[1].nd = dataVal.readData.coval || '--';
-        mbList[2].nd = dataVal.readData.co2val || '--';
-        mbList[3].nd = dataVal.readData.gasval || '--';
-        mbList[4].nd = dataVal.readData.chval || '--';
-        mbList[5].nd = dataVal.readData.ch2val || '--';
-        mbList.forEach((el) => {
-          el.time1 = dataVal ? dataVal.readTime.substring(0, dataVal.readTime.lastIndexOf(':')) : '--';
-          el.address = dataVal ? dataVal.strinstallpos : '--';
-        });
-        netStatus.value = dataVal['netStatus'];
-        echartDataSgList = dataVal.history;
-        btnClick(
-          {
-            label: type.value,
-            dw: echartDataSg1.lengedDataName,
-          },
-          activeIndex.value
-        );
-        // dataVal.history.forEach((v) => {
-        //   echartDataSg1.xData.push(v.time);
-        //   if (echartDataSg1.lengedData == 'O₂') {
-        //     echartDataSg1.yData.push(v.o2val);
-        //   } else if (echartDataSg1.lengedData == 'C₂H₄') {
-        //     echartDataSg1.yData.push(v.ch2val);
-        //   } else if (echartDataSg1.lengedData == 'CO') {
-        //     echartDataSg1.yData.push(v.coval);
-        //   } else if (echartDataSg1.lengedData == 'CH₄') {
-        //     echartDataSg1.yData.push(v.chval);
-        //   } else if (echartDataSg1.lengedData == 'CO₂') {
-        //     echartDataSg1.yData.push(v.co2val);
-        //   } else if (echartDataSg1.lengedData == 'C₂H₂') {
-        //     echartDataSg1.yData.push(v.gasval);
-        //   }
-        //   echartDataSgList.push(v);
-        // });
-        getmax();
-      } else {
-        topContent.temperature = 0;
-        // topContent.position = '--';
-        topContent.time = '--';
-        topContent.warnLevel = '--';
-        topContent.smokeJd = '--';
-        mbList[0].nd = '--';
-        mbList[1].nd = '--';
-        mbList[2].nd = '--';
-        mbList[3].nd = '--';
-        mbList[4].nd = '--';
-        mbList[5].nd = '--';
-        mbList.forEach((el) => {
-          el.time1 = '--';
-          el.address = '--';
-        });
-      }
-    },
-    { immediate: true, deep: true }
-  );
-</script>
-
-<style lang="less" scoped>
-  @import '/@/design/theme.less';
-
-  @{theme-deepblue} {
-    .closeWall {
-      --image-bj1: url('/@/assets/images/themify/deepblue/fire/bj1.png');
-      --image-pj: url('/@/assets/images/themify/deepblue/fire/pj.svg');
-      --image-1: url('/@/assets/images/themify/deepblue/fire/1.png');
-      --image-contetn: url('/@/assets/images/themify/deepblue/fire/contetn.png');
-      --image-2: url('/@/assets/images/themify/deepblue/fire/2.png');
-    }
-  }
-
-  .closeWall {
-    --image-bj1: url('/@/assets/images/fire/bj1.png');
-    --image-pj: url('/@/assets/images/fire/pj.svg');
-    --image-1: url('/@/assets/images/fire/1.png');
-    --image-contetn: url('/@/assets/images/fire/contetn.png');
-    --image-2: url('/@/assets/images/fire/2.png');
-    --border-image-2: linear-gradient(to bottom, transparent, #024688, transparent);
-    width: 100%;
-    height: 100%;
-    padding: 20px;
-    box-sizing: border-box;
-
-    .title {
-      width: 100%;
-      height: 17%;
-      margin-bottom: 20px;
-      display: flex;
-      justify-content: space-between;
-      background: var(--image-bj1) no-repeat center;
-      background-size: 100% 100%;
-      align-items: center;
-
-      .box-container {
-        display: flex;
-
-        &:nth-child(1) {
-          justify-content: space-between;
-          align-items: center;
-          padding: 0px 40px;
-          flex: 2;
-          height: 100%;
-          border-right: 2px solid;
-          border-image: var(--border-image-2) 1 1 1;
-        }
-
-        &:nth-child(2) {
-          flex-direction: column;
-          flex: 1;
-          justify-content: space-around;
-          align-items: center;
-          height: 73%;
-          border-right: 2px solid;
-          border-image: var(--border-image-2) 1 1 1;
-        }
-
-        .contents {
-          height: 73%;
-
-          &:nth-child(1) {
-            width: 50%;
-            display: flex;
-            flex-direction: column;
-            justify-content: space-around;
-
-            .text {
-              font-size: 14px;
-              display: flex;
-              align-items: center;
-
-              .text-label {
-                color: #b3b8cc;
-                font-weight: bold;
-              }
-
-              .text-value {
-                font-family: 'douyuFont';
-                color: var(--vent-table-action-link);
-                margin-left: 10px;
-              }
-            }
-          }
-
-          &:nth-child(2) {
-            width: 50%;
-            display: flex;
-            justify-content: center;
-            align-items: center;
-
-            img {
-              position: relative;
-              width: 90px;
-              height: 100%;
-              background: var(--image-pj) no-repeat center;
-              background-size: 90px 50%;
-            }
-
-            .text {
-              font-family: 'douyuFont';
-              font-size: 28px;
-              margin: 0px 15px;
-              color: var(--vent-table-action-link);
-            }
-
-            .dw {
-              font-size: 14px;
-              color: #b3b8cc;
-            }
-          }
-        }
-
-        .text1 {
-          width: 90%;
-          height: 30px;
-          line-height: 30px;
-          font-size: 14px;
-          color: #b3b8cc;
-          font-weight: bold;
-
-          span {
-            display: inline-block;
-
-            &:nth-child(1) {
-              width: 160px;
-              text-align: right;
-            }
-
-            &:nth-child(2) {
-              font-family: 'douyuFont';
-              color: var(--vent-table-action-link);
-              margin-left: 10px;
-            }
-          }
-
-          .value1 {
-            color: rgb(145, 230, 9) !important;
-          }
-
-          .value2 {
-            // color: rgb(0, 242, 255) !important;
-            color: #ffff35 !important;
-          }
-
-          .value3 {
-            // color: #ffff35 !important;
-            color: #ff0000 !important;
-          }
-
-          .value4 {
-            color: orange !important;
-          }
-
-          .value5 {
-            color: #ff6f00 !important;
-          }
-
-          .value6 {
-            color: #ff0000 !important;
-          }
-        }
-      }
-    }
-
-    .content {
-      width: 100%;
-      height: calc(83% - 20px);
-      padding: 10px;
-      background: var(--image-bj1) no-repeat center;
-      background-size: 100% 100%;
-      box-sizing: border-box;
-
-      .title-b {
-        height: 30px;
-        line-height: 30px;
-        font-family: 'douyuFont';
-        font-size: 14px;
-        color: #fff;
-        // color: var(--vent-table-action-link);
-      }
-
-      .card-btn {
-        height: 28%;
-        margin-bottom: 10px;
-        display: flex;
-        justify-content: space-between;
-
-        .box-container {
-          position: relative;
-          width: 16%;
-          height: 100%;
-          background: var(--image-1) no-repeat center;
-          background-size: 100% 100%;
-          cursor: pointer;
-
-          .box-label {
-            position: absolute;
-            left: 50%;
-            top: 2px;
-            transform: translate(-50%);
-            color: #fff;
-          }
-
-          .box-item {
-            position: absolute;
-            left: 50%;
-            transform: translate(-50%, 0);
-            width: 89%;
-            height: 16%;
-            padding: 0px 10px;
-            display: flex;
-            justify-content: space-between;
-            align-items: center;
-            background: var(--image-contetn) no-repeat center;
-            background-size: 100% 100%;
-
-            .text-t {
-              width: 17%;
-              color: #fff;
-              font-size: 12px;
-            }
-
-            .text-v {
-              width: 83%;
-              font-family: 'douyuFont';
-              font-size: 10px;
-              color: var(--vent-table-action-link);
-              display: flex;
-              justify-content: flex-end;
-            }
-          }
-
-          .box-item1 {
-            top: 24%;
-          }
-
-          .box-item2 {
-            top: 50%;
-          }
-
-          .box-item3 {
-            top: 75%;
-          }
-        }
-
-        .box-container1 {
-          position: relative;
-          width: 16%;
-          height: 100%;
-          background: var(--image-2) no-repeat center;
-          background-size: 100% 100%;
-          cursor: pointer;
-
-          .box-label {
-            position: absolute;
-            left: 50%;
-            top: 2px;
-            transform: translate(-50%);
-            color: #fff;
-          }
-
-          .box-item {
-            position: absolute;
-            left: 50%;
-            transform: translate(-50%, 0);
-            width: 89%;
-            height: 16%;
-            padding: 0px 10px;
-            display: flex;
-            justify-content: space-between;
-            align-items: center;
-            background: var(--image-contetn) no-repeat center;
-            background-size: 100% 100%;
-
-            .text-t {
-              width: 17%;
-              color: #fff;
-              font-size: 12px;
-            }
-
-            .text-v {
-              width: 83%;
-              font-family: 'douyuFont';
-              font-size: 10px;
-              color: var(--vent-table-action-link);
-              display: flex;
-              justify-content: flex-end;
-            }
-          }
-
-          .box-item1 {
-            top: 19%;
-          }
-
-          .box-item2 {
-            top: 41%;
-          }
-
-          .box-item3 {
-            top: 63%;
-          }
-        }
-      }
-
-      .echart-box {
-        display: flex;
-        height: calc(72% - 41px);
-
-        .left-echartbox {
-          width: calc(50% - 6px);
-          margin-right: 6px;
-          border: 1px solid #114aac;
-          border-radius: 5px;
-
-          .title-f {
-            height: 40px;
-            padding: 0px 10px;
-            box-sizing: border-box;
-            display: flex;
-            justify-content: space-between;
-            align-items: center;
-
-            .title-text {
-              font-family: 'douyuFont';
-              font-size: 14px;
-              color: #fff;
-              // color: var(--vent-table-action-link);
-            }
-          }
-
-          .echarts-box {
-            height: calc(100% - 40px);
-            padding: 0px 10px;
-            box-sizing: border-box;
-          }
-        }
-
-        .right-echartbox {
-          width: calc(50% - 6px);
-          margin-left: 6px;
-          border: 1px solid #114aac;
-          border-radius: 5px;
-        }
-      }
-    }
-  }
-
-  :deep(.zxm-select:not(.zxm-select-customize-input) .zxm-select-selector) {
-    border: 1px solid #3ad8ff77 !important;
-    background-color: #ffffff00 !important;
-  }
-
-  :deep(.zxm-select-selection-item) {
-    color: #fff !important;
-  }
-
-  :deep(.zxm-select-arrow) {
-    color: #fff;
-  }
-</style>

+ 11 - 13
src/views/vent/monitorManager/alarmMonitor/common/closeWall.vue

@@ -16,21 +16,19 @@
 </template>
 
 <script lang="ts" setup>
-  import { ref, reactive, watch, inject } from 'vue';
+  import { ref, watch } from 'vue';
   import internalFireBot1 from './internal-fire-bot1.vue';
   import internalFireTop1 from './internal-fire-top1.vue';
 
-  let props = defineProps({
+  const props = defineProps({
     listData: Object,
   });
 
-  const globalConfig = inject('globalConfig');
-
-  let internalFireTopData = ref<any[]>([]);
-  let temperatureData = ref(0);
-  let internalFireBotData = ref<any[]>([]);
-  let selectData = ref('');
-  let warnLevel = ref('');
+  const internalFireTopData = ref<any[]>([]);
+  const temperatureData = ref(0);
+  const internalFireBotData = ref<any[]>([]);
+  const selectData = ref('');
+  const warnLevel = ref('');
 
   function changeSelect(data) {
     selectData.value = data;
@@ -43,10 +41,10 @@
   watch(
     () => props.listData,
     (val: any) => {
-      if (JSON.stringify(val) === '{}') return;
-      internalFireTopData.value = val.bundletube;
-      temperatureData.value = val.temperature[0] ? val.temperature[0].readData.temperature : '--';
-      internalFireBotData.value = val.bundletube;
+      if (!val || JSON.stringify(val) === '{}') return;
+      internalFireTopData.value = val.bundletube || [];
+      temperatureData.value = val.temperature?.[0]?.readData?.temperature ?? '--';
+      internalFireBotData.value = val.bundletube || [];
     },
     { immediate: true, deep: true }
   );

+ 0 - 236
src/views/vent/monitorManager/alarmMonitor/common/echartLine1.vue

@@ -1,236 +0,0 @@
-<template>
-  <div class="echartLine">
-    <div class="line" ref="line"></div>
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import * as echarts from 'echarts';
-  import { ref, nextTick, reactive, watch } from 'vue';
-  let props = defineProps({
-    echartDataSg: {
-      type: Object,
-    },
-    lengedDataName: {
-      type: String,
-    },
-    maxY: {
-      type: Number,
-    },
-    minY: {
-      type: Number,
-    },
-  });
-
-  //获取dom元素节点
-  let line = ref<any>();
-  let echartDataSgs = reactive({});
-  watch(
-    () => props.echartDataSg,
-    (data) => {
-      echartDataSgs = Object.assign({}, data);
-      getOption();
-    },
-    { immediate: true, deep: true }
-  );
-
-  function getOption() {
-    nextTick(() => {
-      const myChart = echarts.init(line.value);
-      let option = {
-        grid: {
-          top: '8%',
-          left: '5%',
-          bottom: '14%',
-          right: '5%',
-          //   containLabel: true,
-        },
-        tooltip: {
-          trigger: 'axis',
-          backgroundColor: 'rgba(0, 0, 0, .6)',
-          textStyle: {
-            color: '#fff',
-            fontSize: 12,
-          },
-        },
-        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: echartDataSgs.lengedData ? echartDataSgs.lengedData : '',
-            },
-          ],
-        },
-        xAxis: [
-          {
-            type: 'category',
-            boundaryGap: false,
-            axisLabel: {
-              // formatter: '{value}',
-              fontSize: 14,
-              margin: 10,
-              textStyle: {
-                color: '#b3b8cc',
-              },
-              // interval: 0,
-              formatter: function (params) {
-                let newParamsName = ref(''); // 最终拼接成的字符串
-                let paramsNameNumber = ref(params.length); // 实际标签的个数
-                let provideNumber = ref(10); // 每行能显示的字的个数
-                let rowNumber = Math.ceil(paramsNameNumber.value / provideNumber.value); // 换行的话,需要显示几行,向上取整
-                /**
-                 * 判断标签的个数是否大于规定的个数, 如果大于,则进行换行处理 如果不大于,即等于或小于,就返回原标签
-                 */
-                // 条件等同于rowNumber>1
-                if (paramsNameNumber.value > provideNumber.value) {
-                  /** 循环每一行,p表示行 */
-                  for (var p = 0; p < rowNumber; p++) {
-                    var tempStr = ''; // 表示每一次截取的字符串
-                    var start = p * provideNumber.value; // 开始截取的位置
-                    var end = start + provideNumber.value; // 结束截取的位置
-                    // 此处特殊处理最后一行的索引值
-                    if (p == rowNumber - 1) {
-                      // 最后一次不换行
-                      tempStr = params.substring(start, paramsNameNumber.value);
-                    } else {
-                      // 每一次拼接字符串并换行
-                      tempStr = params.substring(start, end) + '\n';
-                    }
-                    newParamsName.value += tempStr; // 最终拼成的字符串
-                  }
-                } else {
-                  // 将旧标签的值赋给新标签
-                  newParamsName.value = params;
-                }
-                //将最终的字符串返回
-                return newParamsName.value;
-              },
-            },
-            axisLine: {
-              lineStyle: {
-                color: '#244a94',
-              },
-            },
-            splitLine: {
-              show: true,
-              lineStyle: {
-                color: '#0d2973',
-                type: 'dashed',
-              },
-            },
-            axisTick: {
-              show: false,
-            },
-            data: echartDataSgs.xData,
-          },
-        ],
-        yAxis: [
-          {
-            boundaryGap: false,
-            name: props.lengedDataName ? props.lengedDataName : '',
-            type: 'value',
-            max: props.maxY,
-            min: props.minY,
-            axisLabel: {
-              textStyle: {
-                color: '#b3b8cc',
-              },
-            },
-            nameTextStyle: {
-              color: '#fff',
-              fontSize: 12,
-              lineHeight: 5,
-            },
-            splitLine: {
-              lineStyle: {
-                color: '#0d2973',
-                type: 'dashed',
-              },
-            },
-            axisLine: {
-              show: true,
-              lineStyle: {
-                color: '#244a94',
-              },
-            },
-            axisTick: {
-              show: false,
-            },
-          },
-        ],
-        series: [
-          {
-            name: echartDataSgs.lengedData ? echartDataSgs.lengedData : '',
-            type: 'line',
-            smooth: false,
-            showSymbol: false,
-            zlevel: 3,
-            itemStyle: {
-              color: '#02f2de',
-              borderColor: '#a3c8d8',
-            },
-            lineStyle: {
-              normal: {
-                width: 3,
-                color: '#02f2de',
-              },
-            },
-            areaStyle: {
-              normal: {
-                color: new echarts.graphic.LinearGradient(
-                  0,
-                  0,
-                  0,
-                  1,
-                  [
-                    {
-                      offset: 0,
-                      color: 'rgba(2, 242, 222,0.8)',
-                    },
-                    {
-                      offset: 0.5,
-                      color: 'rgba(2, 242, 222,0.4)',
-                    },
-                    {
-                      offset: 0.9,
-                      color: 'rgba(2, 242, 222,0)',
-                    },
-                  ],
-                  false
-                ),
-              },
-            },
-            data: echartDataSgs.yData,
-          },
-        ],
-      };
-      myChart.setOption(option);
-      window.onresize = function () {
-        myChart.resize();
-      };
-    });
-  }
-</script>
-
-<style scoped lang="less">
-  .echartLine {
-    width: 100%;
-    height: 100%;
-
-    .line {
-      width: 100%;
-      height: 100%;
-    }
-  }
-</style>

+ 0 - 260
src/views/vent/monitorManager/alarmMonitor/common/echartLine2.vue

@@ -1,260 +0,0 @@
-<template>
-  <div class="echart-work">
-    <div ref="work" class="work-box"></div>
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import * as echarts from 'echarts';
-  import { ref, nextTick, reactive, watch } from 'vue';
-
-  let props = defineProps({
-    echartDataWd: {
-      type: Object,
-    },
-  });
-
-  //获取dom元素节点
-  let work = ref<any>();
-  let echartDataWds = reactive({});
-
-  watch(
-    () => props.echartDataWd,
-    (data) => {
-      echartDataWds = Object.assign({}, data);
-      getOption();
-    },
-    { immediate: true, deep: true }
-  );
-
-  function getOption() {
-    nextTick(() => {
-      const myChart = echarts.init(work.value);
-      let option = {
-        tooltip: {
-          trigger: 'axis',
-          backgroundColor: 'rgba(0, 0, 0, .6)',
-          textStyle: {
-            color: '#fff',
-            fontSize: 12,
-          },
-        },
-
-        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.avgData ? echartDataWds.avgData.lengedData : '',
-            },
-            {
-              name: echartDataWds.maxData ? echartDataWds.maxData.lengedData : '',
-            },
-            {
-              name: echartDataWds.minData ? echartDataWds.minData.lengedData : '',
-            },
-            {
-              name: echartDataWds.curData ? echartDataWds.curData.lengedData : '',
-            },
-          ],
-        },
-
-        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;
-              },
-            },
-            splitLine: {
-              show: true,
-              lineStyle: {
-                color: '#0d2973',
-                type: 'dashed',
-              },
-            },
-            axisTick: {
-              show: false,
-            },
-            data: echartDataWds.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',
-              },
-            },
-            axisLabel: {
-              show: true,
-              textStyle: {
-                color: '#b3b8cc',
-                padding: 5,
-              },
-              formatter: function (value) {
-                if (value === 0) {
-                  return value;
-                }
-                return value;
-              },
-            },
-            axisTick: {
-              show: false,
-            },
-          },
-        ],
-        series: [
-          {
-            name: echartDataWds.maxData ? echartDataWds.maxData.lengedData : '',
-            type: 'line',
-            yAxisIndex: 0,
-            smooth: true,
-            showSymbol: false,
-            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 : [],
-          },
-          {
-            name: echartDataWds.minData ? echartDataWds.minData.lengedData : '',
-            type: 'line',
-            smooth: true,
-            yAxisIndex: 0,
-            showSymbol: false,
-
-            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 : [],
-          },
-          {
-            name: echartDataWds.avgData ? echartDataWds.avgData.lengedData : '',
-            type: 'line',
-            smooth: true,
-            yAxisIndex: 0,
-            showSymbol: false,
-
-            lineStyle: {
-              normal: {
-                width: 2,
-                color: '#1eb0fc', // 线条颜色
-              },
-              borderColor: 'rgba(0,0,0,.4)',
-            },
-            itemStyle: {
-              color: '#1eb0fc',
-              borderColor: '#646ace',
-              borderWidth: 0,
-            },
-            data: echartDataWds.avgData ? echartDataWds.avgData.data : [],
-          },
-          {
-            name: echartDataWds.curData ? echartDataWds.curData.lengedData : '',
-            type: 'line',
-            smooth: true,
-            yAxisIndex: 0,
-            showSymbol: false,
-            lineStyle: {
-              normal: {
-                width: 2,
-                color: '#1eb0fc', // 线条颜色
-              },
-              borderColor: 'rgba(0,0,0,.4)',
-            },
-            itemStyle: {
-              color: '#1eb0fc',
-              borderColor: '#646ace',
-              borderWidth: 0,
-            },
-            data: echartDataWds.curData ? echartDataWds.curData.data : [],
-          },
-        ],
-      };
-      myChart.setOption(option);
-      window.onresize = function () {
-        myChart.resize();
-      };
-    });
-  }
-</script>
-
-<style scoped lang="less">
-  .echart-work {
-    width: 100%;
-    height: 100%;
-
-    .work-box {
-      width: 100%;
-      height: 100%;
-    }
-  }
-</style>

+ 111 - 93
src/views/vent/monitorManager/alarmMonitor/common/external-gx-echart.vue

@@ -1,119 +1,137 @@
 <template>
-    <div class="external-gx-echart">
-        <div class="footer-title">
-            <div class="echart-label">光纤测温系统实时温度监测</div>
-        </div>
-        <div class="echart-content">
-            <echartLine2 :echartDataWd="echartDataWd" />
-        </div>
+  <div class="external-gx-echart">
+    <div class="footer-title">
+      <div class="echart-label">光纤测温系统实时温度监测</div>
     </div>
+    <div class="echart-content">
+      <FiberTempChart
+        :x-axis-data="xAxisData"
+        :series-data="seriesData"
+        :max-value="maxValue"
+        :min-value="minValue"
+        title=""
+        height="100%"
+        compact
+        :mark-symbol-size="36"
+        data-zoom-mode="index"
+        :data-zoom-start="0"
+        :data-zoom-end="20"
+      />
+    </div>
+  </div>
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, watch } from 'vue'
-import echartLine2 from './echartLine2.vue';
-
-let props = defineProps({
-    echartData: {
-        type: Array,
-        default: () => {
-            return []
-        }
-    }
-})
+import { ref, watch } from 'vue';
+import FiberTempChart from '/@/views/vent/testChart/FiberTempChart.vue';
 
-//外因火灾温度监测-图表数据
-let echartDataWd = reactive({
-    xData: [],
-    curData: {
-        lengedData: '实时温度',
-        data: [],
-    },
-    maxData: {
-        lengedData: '最大温度',
-        data: [],
-    },
-    minData: {
-        lengedData: '最小温度',
-        data: [],
-    },
-    avgData: {
-        lengedData: '平均温度',
-        data: [],
+const props = defineProps({
+  echartData: {
+    type: Array,
+    default: () => {
+      return [];
     },
+  },
 });
 
-watch(() => props.echartData, (newV, oldV) => {
-    echartDataWd.xData.length = 0;
-    echartDataWd.avgData.data.length = 0;
-    echartDataWd.maxData.data.length = 0;
-    echartDataWd.minData.data.length = 0;
-    echartDataWd.curData.data.length = 0;
-    if (newV.length != 0) {
-        const fiber: any = newV[0];
-        const arr: any[] = JSON.parse(fiber.readData.fibreTemperature);
+const xAxisData = ref<any[]>([]);
+const seriesData = ref<number[]>([]);
+const maxValue = ref(60);
+const minValue = ref(20);
+let lastSignature = '';
+
+watch(
+  () => props.echartData,
+  (newV) => {
+    const nextX: any[] = [];
+    const nextSeries: number[] = [];
+    let nextMax = 60;
+    let nextMin = 20;
+
+    if (newV && newV.length !== 0) {
+      const fiber: any = newV[0];
+      const readData = fiber?.readData || {};
+      // 上限/下限取对应字段最大温度 fmax、最小温度 fmin
+      const fmax = Number(readData.fmax);
+      const fmin = Number(readData.fmin);
+      if (!Number.isNaN(fmax)) nextMax = fmax;
+      if (!Number.isNaN(fmin)) nextMin = fmin;
+
+      // 曲线取值逻辑保持与原先一致:fibreTemperature 的 pos / value
+      try {
+        const arr: any[] = JSON.parse(readData.fibreTemperature || '[]');
         arr.forEach((el) => {
-        echartDataWd.xData.push(el.pos);
-        echartDataWd.curData.data.push(el.value);
-        echartDataWd.maxData.data.push(fiber.avgParam?.max_temperature_value || 0);
-        echartDataWd.minData.data.push(fiber.avgParam?.min_temperature_value || 0);
-        echartDataWd.avgData.data.push(fiber.avgParam?.avg_temperature_value || 0);
-      });
+          nextX.push(el.pos);
+          nextSeries.push(Number(el.value));
+        });
+      } catch (e) {
+        console.warn('fibreTemperature parse error', e);
+      }
     }
-}, { immediate: true })
 
+    const signature = JSON.stringify({ x: nextX, s: nextSeries, max: nextMax, min: nextMin });
+    if (signature === lastSignature) return;
+    lastSignature = signature;
+
+    xAxisData.value = nextX;
+    seriesData.value = nextSeries;
+    maxValue.value = nextMax;
+    minValue.value = nextMin;
+  },
+  { immediate: true, deep: true }
+);
 </script>
 
 <style lang="less" scoped>
 @import '/@/design/theme.less';
 
 @{theme-deepblue} {
-    .external-gx-echart {
-        --image-bj1: url('/@/assets/images/themify/deepblue/fire/bj1.png');
-        --image-max: url('/@/assets/images/themify/deepblue/fire/max.svg');
-        --image-min: url('/@/assets/images/themify/deepblue/fire/min.svg');
-        --image-pj: url('/@/assets/images/themify/deepblue/fire/pj.svg');
-        --image-1: url('/@/assets/images/themify/deepblue/fire/1.png');
-        --image-contetn: url('/@/assets/images/themify/deepblue/fire/contetn.png');
-        --image-2: url('/@/assets/images/themify/deepblue/fire/2.png');
-    }
+  .external-gx-echart {
+    --image-bj1: url('/@/assets/images/themify/deepblue/fire/bj1.png');
+    --image-max: url('/@/assets/images/themify/deepblue/fire/max.svg');
+    --image-min: url('/@/assets/images/themify/deepblue/fire/min.svg');
+    --image-pj: url('/@/assets/images/themify/deepblue/fire/pj.svg');
+    --image-1: url('/@/assets/images/themify/deepblue/fire/1.png');
+    --image-contetn: url('/@/assets/images/themify/deepblue/fire/contetn.png');
+    --image-2: url('/@/assets/images/themify/deepblue/fire/2.png');
+  }
 }
 
 .external-gx-echart {
-    --image-zwnr: url('/@/assets/images/fire/wy-zwnr.png');
-    --image-z: url('/@/assets/images/fire/wy-z.png');
-    --image-zt: url('/@/assets/images/fire/wy-zt.png');
-    --image-zt1: url('/@/assets/images/fire/wy-zt2.png');
-    --image-time: url('/@/assets/images/fire/wy-time.png');
-    --image-time1: url('/@/assets/images/fire/wy-time2.png');
-    --image-title: url('/@/assets/images/fire/wy-title.png');
-    --image-bj2: url('/@/assets/images/fire/wy-bj.png');
-    --image-max: url('/@/assets/images/fire/max.svg');
-    --image-min: url('/@/assets/images/fire/min.svg');
-    --image-pj: url('/@/assets/images/fire/pj.svg');
-    --image-1: url('/@/assets/images/fire/1.png');
-    --image-contetn: url('/@/assets/images/fire/contetn.png');
-    --image-2: url('/@/assets/images/fire/2.png');
-    --border-image-2: linear-gradient(to bottom, transparent, #024688, transparent);
-    position: relative;
-    width: 100%;
-    height: 100%;
+  --image-zwnr: url('/@/assets/images/fire/wy-zwnr.png');
+  --image-z: url('/@/assets/images/fire/wy-z.png');
+  --image-zt: url('/@/assets/images/fire/wy-zt.png');
+  --image-zt1: url('/@/assets/images/fire/wy-zt2.png');
+  --image-time: url('/@/assets/images/fire/wy-time.png');
+  --image-time1: url('/@/assets/images/fire/wy-time2.png');
+  --image-title: url('/@/assets/images/fire/wy-title.png');
+  --image-bj2: url('/@/assets/images/fire/wy-bj.png');
+  --image-max: url('/@/assets/images/fire/max.svg');
+  --image-min: url('/@/assets/images/fire/min.svg');
+  --image-pj: url('/@/assets/images/fire/pj.svg');
+  --image-1: url('/@/assets/images/fire/1.png');
+  --image-contetn: url('/@/assets/images/fire/contetn.png');
+  --image-2: url('/@/assets/images/fire/2.png');
+  --border-image-2: linear-gradient(to bottom, transparent, #024688, transparent);
+  position: relative;
+  width: 100%;
+  height: 100%;
 
-    .footer-title {
-        height: 30px;
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
+  .footer-title {
+    height: 30px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
 
-        .echart-label {
-            font-family: 'douyuFont';
-            font-size: 14px;
-            color: #fff;
-        }
+    .echart-label {
+      font-family: 'douyuFont';
+      font-size: 14px;
+      color: #fff;
     }
+  }
 
-    .echart-content {
-        height: calc(100% - 30px);
-    }
+  .echart-content {
+    height: calc(100% - 30px);
+  }
 }
-</style>
+</style>

+ 477 - 400
src/views/vent/monitorManager/alarmMonitor/common/external-mb.vue

@@ -1,464 +1,541 @@
 <template>
-    <div class="external-mb">
-        <div class="title-b">采空区密闭参数</div>
-        <div class="card-btn">
-            <div :class="activeIndex == 0 ? 'content-box1' : 'content-box'" @click="btnClick({ label: 'O₂', dw: '(%)' }, 0)">
-                <div class="btn-label">
-                    <span>O₂</span>
-                    <span>(%)</span>
-                </div>
-                <div class="box-item box-item1">
-                    <span class="text-t">浓度:</span>
-                    <span class="text-v">{{ mbData.o2 }}</span>
-                </div>
-                <div class="box-item box-item2">
-                    <span class="text-t">时间:</span>
-                    <span class="text-v">{{ mbData.o2time }}</span>
-                </div>
-                <div class="box-item box-item3">
-                    <span class="text-t">位置:</span>
-                    <span class="text-v">{{ mbData.o2address }}</span>
-                </div>
-            </div>
-            <div :class="activeIndex == 1 ? 'content-box1' : 'content-box'" @click="btnClick({ label: 'CO', dw: '(ppm)' }, 1)">
-                <div class="btn-label">
-                    <span>CO</span>
-                    <span>(ppm)</span>
-                </div>
-                <div class="box-item box-item1">
-                    <span class="text-t">浓度:</span>
-                    <span class="text-v">{{ mbData.co }}</span>
-                </div>
-                <div class="box-item box-item2">
-                    <span class="text-t">时间:</span>
-                    <span class="text-v">{{ mbData.cotime }}</span>
-                </div>
-                <div class="box-item box-item3">
-                    <span class="text-t">位置:</span>
-                    <span class="text-v">{{ mbData.coaddress }}</span>
-                </div>
-            </div>
-            <div :class="activeIndex == 2 ? 'content-box1' : 'content-box'" @click="btnClick({ label: 'CO₂', dw: '(%)' }, 2)">
-                <div class="btn-label">
-                    <span>CO₂</span>
-                    <span>(%)</span>
-                </div>
-                <div class="box-item box-item1">
-                    <span class="text-t">浓度:</span>
-                    <span class="text-v">{{ mbData.co2 }}</span>
-                </div>
-                <div class="box-item box-item2">
-                    <span class="text-t">时间:</span>
-                    <span class="text-v">{{ mbData.co2time }}</span>
-                </div>
-                <div class="box-item box-item3">
-                    <span class="text-t">位置:</span>
-                    <span class="text-v">{{ mbData.co2address }}</span>
-                </div>
-            </div>
-            <div :class="activeIndex == 3 ? 'content-box1' : 'content-box'" @click="btnClick({ label: 'CH₄', dw: '(%)' }, 3)">
-                <div class="btn-label">
-                    <span>CH₄</span>
-                    <span>(%)</span>
-                </div>
-                <div class="box-item box-item1">
-                    <span class="text-t">浓度:</span>
-                    <span class="text-v">{{ mbData.ch4 }}</span>
-                </div>
-                <div class="box-item box-item2">
-                    <span class="text-t">时间:</span>
-                    <span class="text-v">{{ mbData.ch4time }}</span>
-                </div>
-                <div class="box-item box-item3">
-                    <span class="text-t">位置:</span>
-                    <span class="text-v">{{ mbData.ch4address }}</span>
-                </div>
-            </div>
-            <div :class="activeIndex == 4 ? 'content-box1' : 'content-box'" @click="btnClick({ label: 'C₂H₂', dw: '(ppm)' }, 4)">
-                <div class="btn-label">
-                    <span>C₂H₂</span>
-                    <span>(ppm)</span>
-                </div>
-                <div class="box-item box-item1">
-                    <span class="text-t">浓度:</span>
-                    <span class="text-v">{{ mbData.c2h2 }}</span>
-                </div>
-                <div class="box-item box-item2">
-                    <span class="text-t">时间:</span>
-                    <span class="text-v">{{ mbData.c2h2time }}</span>
-                </div>
-                <div class="box-item box-item3">
-                    <span class="text-t">位置:</span>
-                    <span class="text-v">{{ mbData.c2h2address }}</span>
-                </div>
-            </div>
-            <div :class="activeIndex == 5 ? 'content-box1' : 'content-box'" @click="btnClick({ label: 'C₂H₄', dw: '(ppm)' }, 5)">
-                <div class="btn-label">
-                    <span>C₂H₄</span>
-                    <span>(ppm)</span>
-                </div>
-                <div class="box-item box-item1">
-                    <span class="text-t">浓度:</span>
-                    <span class="text-v">{{ mbData.c2h4 }}</span>
-                </div>
-                <div class="box-item box-item2">
-                    <span class="text-t">时间:</span>
-                    <span class="text-v">{{ mbData.c2h4time }}</span>
-                </div>
-                <div class="box-item box-item3">
-                    <span class="text-t">位置:</span>
-                    <span class="text-v">{{ mbData.c2h4address }}</span>
-                </div>
-            </div>
+  <div class="external-mb">
+    <div class="title-b">采空区密闭参数</div>
+    <div class="card-btn">
+      <div :class="activeIndex == 0 ? 'content-box1' : 'content-box'" @click="btnClick({ label: 'O₂', dw: '(%)' }, 0)">
+        <div class="btn-label">
+          <span>O₂</span>
+          <span>(%)</span>
         </div>
-        <div class="echart-box">
-            <div class="title-f">
-                <div class="title-text">
-                    {{ `${type}趋势` }}&nbsp; <span style="color: red">{{ netStatus != 1 ? '(设备未连接)' : '' }}</span>
-                </div>
-            </div>
-            <div class="echarts-box">
-                <echartLine1 :echartDataSg="echartDataSg1" :lengedDataName="echartDataSg1.lengedDataName" />
-            </div>
+        <div class="box-item box-item1">
+          <span class="text-t">浓度:</span>
+          <span class="text-v">{{ mbData.o2 }}</span>
         </div>
+        <div class="box-item box-item2">
+          <span class="text-t">时间:</span>
+          <span class="text-v">{{ mbData.o2time }}</span>
+        </div>
+        <div class="box-item box-item3">
+          <span class="text-t">位置:</span>
+          <span class="text-v">{{ mbData.o2address }}</span>
+        </div>
+      </div>
+      <div :class="activeIndex == 1 ? 'content-box1' : 'content-box'" @click="btnClick({ label: 'CO', dw: '(ppm)' }, 1)">
+        <div class="btn-label">
+          <span>CO</span>
+          <span>(ppm)</span>
+        </div>
+        <div class="box-item box-item1">
+          <span class="text-t">浓度:</span>
+          <span class="text-v">{{ mbData.co }}</span>
+        </div>
+        <div class="box-item box-item2">
+          <span class="text-t">时间:</span>
+          <span class="text-v">{{ mbData.cotime }}</span>
+        </div>
+        <div class="box-item box-item3">
+          <span class="text-t">位置:</span>
+          <span class="text-v">{{ mbData.coaddress }}</span>
+        </div>
+      </div>
+      <div :class="activeIndex == 2 ? 'content-box1' : 'content-box'" @click="btnClick({ label: 'CO₂', dw: '(%)' }, 2)">
+        <div class="btn-label">
+          <span>CO₂</span>
+          <span>(%)</span>
+        </div>
+        <div class="box-item box-item1">
+          <span class="text-t">浓度:</span>
+          <span class="text-v">{{ mbData.co2 }}</span>
+        </div>
+        <div class="box-item box-item2">
+          <span class="text-t">时间:</span>
+          <span class="text-v">{{ mbData.co2time }}</span>
+        </div>
+        <div class="box-item box-item3">
+          <span class="text-t">位置:</span>
+          <span class="text-v">{{ mbData.co2address }}</span>
+        </div>
+      </div>
+      <div :class="activeIndex == 3 ? 'content-box1' : 'content-box'" @click="btnClick({ label: 'CH₄', dw: '(%)' }, 3)">
+        <div class="btn-label">
+          <span>CH₄</span>
+          <span>(%)</span>
+        </div>
+        <div class="box-item box-item1">
+          <span class="text-t">浓度:</span>
+          <span class="text-v">{{ mbData.ch4 }}</span>
+        </div>
+        <div class="box-item box-item2">
+          <span class="text-t">时间:</span>
+          <span class="text-v">{{ mbData.ch4time }}</span>
+        </div>
+        <div class="box-item box-item3">
+          <span class="text-t">位置:</span>
+          <span class="text-v">{{ mbData.ch4address }}</span>
+        </div>
+      </div>
+      <div :class="activeIndex == 4 ? 'content-box1' : 'content-box'" @click="btnClick({ label: 'C₂H₂', dw: '(ppm)' }, 4)">
+        <div class="btn-label">
+          <span>C₂H₂</span>
+          <span>(ppm)</span>
+        </div>
+        <div class="box-item box-item1">
+          <span class="text-t">浓度:</span>
+          <span class="text-v">{{ mbData.c2h2 }}</span>
+        </div>
+        <div class="box-item box-item2">
+          <span class="text-t">时间:</span>
+          <span class="text-v">{{ mbData.c2h2time }}</span>
+        </div>
+        <div class="box-item box-item3">
+          <span class="text-t">位置:</span>
+          <span class="text-v">{{ mbData.c2h2address }}</span>
+        </div>
+      </div>
+      <div :class="activeIndex == 5 ? 'content-box1' : 'content-box'" @click="btnClick({ label: 'C₂H₄', dw: '(ppm)' }, 5)">
+        <div class="btn-label">
+          <span>C₂H₄</span>
+          <span>(ppm)</span>
+        </div>
+        <div class="box-item box-item1">
+          <span class="text-t">浓度:</span>
+          <span class="text-v">{{ mbData.c2h4 }}</span>
+        </div>
+        <div class="box-item box-item2">
+          <span class="text-t">时间:</span>
+          <span class="text-v">{{ mbData.c2h4time }}</span>
+        </div>
+        <div class="box-item box-item3">
+          <span class="text-t">位置:</span>
+          <span class="text-v">{{ mbData.c2h4address }}</span>
+        </div>
+      </div>
+    </div>
+    <div class="echart-box">
+      <div class="title-f">
+        <div class="title-text">
+          {{ `${type}趋势` }}&nbsp; <span style="color: red">{{ netStatus != 1 ? '(设备未连接)' : '' }}</span>
+        </div>
+      </div>
+      <div class="echarts-box">
+        <FiberTempChart
+          :x-axis-data="chartXData"
+          :series-data="chartYData"
+          :max-value="chartMaxValue"
+          :min-value="chartMinValue"
+          title=""
+          :y-axis-name="chartYAxisName"
+          :value-label="chartValueLabel"
+          :value-unit="chartValueUnit"
+          height="100%"
+          compact
+          :mark-symbol-size="32"
+          data-zoom-mode="index"
+          :data-zoom-start="0"
+          :data-zoom-end="10"
+        />
+      </div>
     </div>
+  </div>
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, watch } from 'vue'
-import echartLine1 from './echartLine1.vue';
-
-let props = defineProps({
-    externalTSgData: {
-        type: Array,
-        default: () => {
-            return []
-        }
-    },
-    selectData:{
-        type:String,
-        default:'',
+import { ref, reactive, watch } from 'vue';
+import FiberTempChart from '/@/views/vent/testChart/FiberTempChart.vue';
+
+const props = defineProps({
+  externalTSgData: {
+    type: Array,
+    default: () => {
+      return [];
     },
-    warnLevel:{
-        type:String,
-        default:''
-    }
-})
-
-//束管监测当前密闭参数激活选项
-let activeIndex = ref(0);
-let bundletube = ref<any[]>([])
-//束管监测密闭参数列表
-let mbData = reactive({
-    o2: '',
-    o2time: '',
-    o2address: '',
-    co: '',
-    cotime: '',
-    coaddress: '',
-    co2: '',
-    co2time: '',
-    co2address: '',
-    ch4: '',
-    ch4time: '',
-    ch4address: '',
-    c2h2: '',
-    c2h2time: '',
-    c2h2address: '',
-    c2h4: '',
-    c2h4time: '',
-    c2h4address: ''
-})
-//束管监测当前激活密闭参数类型
-let type = ref('O₂');
-let echartDataSg1 = reactive({
-  xData: [],
-  yData: [],
-  lengedData: 'O₂',
-  lengedDataName: '(%)',
+  },
+  selectData: {
+    type: String,
+    default: '',
+  },
+});
+
+const activeIndex = ref(0);
+const bundletube = ref<any[]>([]);
+const mbData = reactive({
+  o2: '',
+  o2time: '',
+  o2address: '',
+  co: '',
+  cotime: '',
+  coaddress: '',
+  co2: '',
+  co2time: '',
+  co2address: '',
+  ch4: '',
+  ch4time: '',
+  ch4address: '',
+  c2h2: '',
+  c2h2time: '',
+  c2h2address: '',
+  c2h4: '',
+  c2h4time: '',
+  c2h4address: '',
 });
-let echartDataSgList = ref<any[]>([]);
-    let netStatus = ref(0);
 
-//束管监测密闭参数选项切换
+const type = ref('O₂');
+const currentUnit = ref('(%)');
+const echartDataSgList = ref<any[]>([]);
+const netStatus = ref(0);
+
+const chartXData = ref<any[]>([]);
+const chartYData = ref<number[]>([]);
+const chartMaxValue = ref(0);
+const chartMinValue = ref(0);
+const chartYAxisName = ref('浓度(%)');
+const chartValueLabel = ref('浓度');
+const chartValueUnit = ref('%');
+let lastChartSignature = '';
+
+function parseUnit(dw: string) {
+  const text = String(dw || '').replace(/[()()]/g, '').trim();
+  return text || '';
+}
+
+function getSelectedDevice() {
+  if (!bundletube.value.length) return null;
+  if (props.selectData) {
+    return bundletube.value.find((v) => v.strinstallpos == props.selectData) || bundletube.value[0];
+  }
+  return bundletube.value[0];
+}
+
+function fillCardData(dataVal: any) {
+  if (!dataVal?.readData) return;
+  const times = dataVal.readTime ? dataVal.readTime.substring(0, dataVal.readTime.lastIndexOf(':')) || '--' : '--';
+  const address = dataVal.strinstallpos || '--';
+  mbData.o2 = dataVal.readData.o2val || '--';
+  mbData.o2time = times;
+  mbData.o2address = address;
+  mbData.co = dataVal.readData.coval || '--';
+  mbData.cotime = times;
+  mbData.coaddress = address;
+  mbData.co2 = dataVal.readData.co2val || '--';
+  mbData.co2time = times;
+  mbData.co2address = address;
+  mbData.ch4 = dataVal.readData.gasval || '--';
+  mbData.ch4time = times;
+  mbData.ch4address = address;
+  mbData.c2h2 = dataVal.readData.chval || '--';
+  mbData.c2h2time = times;
+  mbData.c2h2address = address;
+  mbData.c2h4 = dataVal.readData.ch2val || '--';
+  mbData.c2h4time = times;
+  mbData.c2h4address = address;
+}
+
+function applyChartData(nextX: any[], nextY: number[], nextMax: number, nextMin: number, title: string, dw: string) {
+  const unit = parseUnit(dw);
+  const signature = JSON.stringify({
+    x: nextX,
+    y: nextY,
+    max: nextMax,
+    min: nextMin,
+    title,
+    dw,
+  });
+  if (signature === lastChartSignature) return;
+  lastChartSignature = signature;
+
+  chartXData.value = nextX;
+  chartYData.value = nextY;
+  chartMaxValue.value = nextMax;
+  chartMinValue.value = nextMin;
+  chartYAxisName.value = unit ? `浓度(${unit})` : '浓度';
+  chartValueLabel.value = '浓度';
+  chartValueUnit.value = unit;
+}
+
+// 束管监测密闭参数选项切换(取值逻辑与原先保持一致)
 function btnClick(item, ind) {
   activeIndex.value = ind;
   type.value = item.label;
-  echartDataSg1.xData.length = 0;
-  echartDataSg1.yData.length = 0;
-  echartDataSg1.lengedData = type.value;
-  echartDataSg1.lengedDataName = item.dw;
+  currentUnit.value = item.dw;
+
+  const dataVal = getSelectedDevice();
+  const nextX: any[] = [];
+  const nextY: number[] = [];
+  let nextMax = 0;
+  let nextMin = 0;
+  const avg = dataVal?.avgParam || {};
 
   switch (type.value) {
     case 'O₂':
       echartDataSgList.value.forEach((el) => {
-        echartDataSg1.xData.push(el.time);
-        echartDataSg1.yData.push(el.o2val);
+        nextX.push(el.time);
+        nextY.push(Number(el.o2val));
       });
+      nextMax = Number(avg.max_o2_value || 0);
+      nextMin = Number(avg.min_o2_value || 0);
       break;
     case 'C₂H₄':
       echartDataSgList.value.forEach((el) => {
-        echartDataSg1.xData.push(el.time);
-        echartDataSg1.yData.push(el.ch2val);
+        nextX.push(el.time);
+        nextY.push(Number(el.ch2val));
       });
+      nextMax = Number(avg.max_c2h4_value || 0);
+      nextMin = Number(avg.min_c2h4_value || 0);
       break;
     case 'CO':
       echartDataSgList.value.forEach((el) => {
-        echartDataSg1.xData.push(el.time);
-        echartDataSg1.yData.push(el.coval);
+        nextX.push(el.time);
+        nextY.push(Number(el.coval));
       });
+      nextMax = Number(avg.max_co_value || 0);
+      nextMin = Number(avg.min_co_value || 0);
       break;
     case 'CH₄':
       echartDataSgList.value.forEach((el) => {
-        echartDataSg1.xData.push(el.time);
-        echartDataSg1.yData.push(el.gasval);
+        nextX.push(el.time);
+        nextY.push(Number(el.gasval));
       });
+      nextMax = Number(avg.max_ch4_value || 0);
+      nextMin = Number(avg.min_ch4_value || 0);
       break;
     case 'CO₂':
       echartDataSgList.value.forEach((el) => {
-        echartDataSg1.xData.push(el.time);
-        echartDataSg1.yData.push(el.co2val);
+        nextX.push(el.time);
+        nextY.push(Number(el.co2val));
       });
+      nextMax = Number(avg.max_co2_value || 0);
+      nextMin = Number(avg.min_co2_value || 0);
       break;
     case 'C₂H₂':
       echartDataSgList.value.forEach((el) => {
-        echartDataSg1.xData.push(el.time);
-        echartDataSg1.yData.push(el.chval);
+        nextX.push(el.time);
+        nextY.push(Number(el.chval));
       });
+      nextMax = Number(avg.max_c2h2_value || 0);
+      nextMin = Number(avg.min_c2h2_value || 0);
       break;
   }
+
+  applyChartData(nextX, nextY, nextMax, nextMin, type.value, item.dw);
 }
 
-watch(() => props.externalTSgData, (newV, oldV) => {
-    echartDataSg1.xData.length = 0;
-    echartDataSg1.yData.length = 0;
-    if (newV.length != 0 && props.selectData) {
-        bundletube.value = newV
-        let dataVal =bundletube.value.filter((v) => v.strinstallpos == props.selectData)[0] 
-        let times = dataVal.readTime.substring(0, dataVal.readTime.lastIndexOf(':')) || '--';
-        let address = dataVal.strinstallpos || '--';
-        mbData.o2 = dataVal.readData.o2val || '--';
-        mbData.o2time = times
-        mbData.o2address = address
-        mbData.co = dataVal.readData.coval || '--';
-        mbData.cotime = times
-        mbData.coaddress = address;
-        mbData.co2 = dataVal.readData.co2val || '--';
-        mbData.co2time = times
-        mbData.co2address = address;
-        mbData.ch4 = dataVal.readData.gasval || '--';
-        mbData.ch4time =times
-        mbData.ch4address = address;
-        mbData.c2h2 = dataVal.readData.chval || '--';
-        mbData.c2h2time = times
-        mbData.c2h2address = address;
-        mbData.c2h4 = dataVal.readData.ch2val || '--';
-        mbData.c2h4time = times
-        mbData.c2h4address = address;
-
-        echartDataSgList.value = dataVal.history;
-        netStatus.value = dataVal['netStatus'];
-        btnClick(
-            {
-                label: type.value,
-                dw: echartDataSg1.lengedDataName,
-            },
-            activeIndex.value
-        );
-    }
-}, { immediate: true })
+function refreshBySelect() {
+  if (!props.externalTSgData || props.externalTSgData.length === 0) return;
+  bundletube.value = props.externalTSgData as any[];
+  const dataVal = getSelectedDevice();
+  if (!dataVal) return;
+
+  fillCardData(dataVal);
+  echartDataSgList.value = dataVal.history || [];
+  netStatus.value = dataVal['netStatus'];
+  btnClick(
+    {
+      label: type.value,
+      dw: currentUnit.value,
+    },
+    activeIndex.value
+  );
+}
+
+watch(
+  () => [props.externalTSgData, props.selectData],
+  () => {
+    refreshBySelect();
+  },
+  { immediate: true, deep: true }
+);
 </script>
 
 <style lang="less" scoped>
 @import '/@/design/theme.less';
 
 @{theme-deepblue} {
-    .external-mb {
-        --image-bj1: url('/@/assets/images/themify/deepblue/fire/bj1.png');
-        --image-max: url('/@/assets/images/themify/deepblue/fire/max.svg');
-        --image-min: url('/@/assets/images/themify/deepblue/fire/min.svg');
-        --image-pj: url('/@/assets/images/themify/deepblue/fire/pj.svg');
-        --image-1: url('/@/assets/images/themify/deepblue/fire/1.png');
-        --image-contetn: url('/@/assets/images/themify/deepblue/fire/contetn.png');
-        --image-2: url('/@/assets/images/themify/deepblue/fire/2.png');
-    }
+  .external-mb {
+    --image-bj1: url('/@/assets/images/themify/deepblue/fire/bj1.png');
+    --image-max: url('/@/assets/images/themify/deepblue/fire/max.svg');
+    --image-min: url('/@/assets/images/themify/deepblue/fire/min.svg');
+    --image-pj: url('/@/assets/images/themify/deepblue/fire/pj.svg');
+    --image-1: url('/@/assets/images/themify/deepblue/fire/1.png');
+    --image-contetn: url('/@/assets/images/themify/deepblue/fire/contetn.png');
+    --image-2: url('/@/assets/images/themify/deepblue/fire/2.png');
+  }
 }
 
 .external-mb {
-    --image-zwnr: url('/@/assets/images/fire/wy-zwnr.png');
-    --image-z: url('/@/assets/images/fire/wy-z.png');
-    --image-zt: url('/@/assets/images/fire/wy-zt.png');
-    --image-zt1: url('/@/assets/images/fire/wy-zt2.png');
-    --image-time: url('/@/assets/images/fire/wy-time.png');
-    --image-time1: url('/@/assets/images/fire/wy-time2.png');
-    --image-title: url('/@/assets/images/fire/wy-title.png');
-    --image-bj2: url('/@/assets/images/fire/wy-bj.png');
-    --image-max: url('/@/assets/images/fire/max.svg');
-    --image-min: url('/@/assets/images/fire/min.svg');
-    --image-pj: url('/@/assets/images/fire/pj.svg');
-    --image-1: url('/@/assets/images/fire/1.png');
-    --image-contetn: url('/@/assets/images/fire/contetn.png');
-    --image-2: url('/@/assets/images/fire/2.png');
-    --border-image-2: linear-gradient(to bottom, transparent, #024688, transparent);
-    position: relative;
-    width: 100%;
-    height: 100%;
-
-    .title-b {
-        height: 30px;
-        line-height: 30px;
-        font-family: 'douyuFont';
-        font-size: 14px;
-        color: #fff;
-    }
+  --image-zwnr: url('/@/assets/images/fire/wy-zwnr.png');
+  --image-z: url('/@/assets/images/fire/wy-z.png');
+  --image-zt: url('/@/assets/images/fire/wy-zt.png');
+  --image-zt1: url('/@/assets/images/fire/wy-zt2.png');
+  --image-time: url('/@/assets/images/fire/wy-time.png');
+  --image-time1: url('/@/assets/images/fire/wy-time2.png');
+  --image-title: url('/@/assets/images/fire/wy-title.png');
+  --image-bj2: url('/@/assets/images/fire/wy-bj.png');
+  --image-max: url('/@/assets/images/fire/max.svg');
+  --image-min: url('/@/assets/images/fire/min.svg');
+  --image-pj: url('/@/assets/images/fire/pj.svg');
+  --image-1: url('/@/assets/images/fire/1.png');
+  --image-contetn: url('/@/assets/images/fire/contetn.png');
+  --image-2: url('/@/assets/images/fire/2.png');
+  --border-image-2: linear-gradient(to bottom, transparent, #024688, transparent);
+  position: relative;
+  width: 100%;
+  height: 100%;
+
+  .title-b {
+    height: 30px;
+    line-height: 30px;
+    font-family: 'douyuFont';
+    font-size: 14px;
+    color: #fff;
+  }
 
-    .card-btn {
-        height: 28%;
-        margin-bottom: 10px;
+  .card-btn {
+    height: 28%;
+    margin-bottom: 10px;
+    display: flex;
+    justify-content: space-between;
+
+    .content-box {
+      position: relative;
+      width: 16%;
+      height: 100%;
+      background: var(--image-1) no-repeat center;
+      background-size: 100% 100%;
+      cursor: pointer;
+
+      .btn-label {
+        position: absolute;
+        left: 50%;
+        top: 0;
+        transform: translate(-50%);
+        font-size: 16px;
+        color: #fff;
+      }
+
+      .box-item {
+        position: absolute;
+        left: 50%;
+        transform: translate(-50%, 0);
+        width: 89%;
+        height: 16%;
+        padding: 0px 10px;
         display: flex;
         justify-content: space-between;
-
-        .content-box {
-            position: relative;
-            width: 16%;
-            height: 100%;
-            background: var(--image-1) no-repeat center;
-            background-size: 100% 100%;
-            cursor: pointer;
-
-            .btn-label {
-                position: absolute;
-                left: 50%;
-                top: 0;
-                transform: translate(-50%);
-                font-size: 16px;
-                color: #fff;
-            }
-
-            .box-item {
-                position: absolute;
-                left: 50%;
-                transform: translate(-50%, 0);
-                width: 89%;
-                height: 16%;
-                padding: 0px 10px;
-                display: flex;
-                justify-content: space-between;
-                align-items: center;
-                background: var(--image-contetn) no-repeat center;
-                background-size: 100% 100%;
-
-                .text-t {
-                    width: 17%;
-                    color: #fff;
-                    font-size: 12px;
-                }
-
-                .text-v {
-                    width: 83%;
-                    font-family: 'douyuFont';
-                    font-size: 10px;
-                    color: var(--vent-table-action-link);
-                    display: flex;
-                    justify-content: flex-end;
-                }
-            }
-
-            .box-item1 {
-                top: 24%;
-            }
-
-            .box-item2 {
-                top: 50%;
-            }
-
-            .box-item3 {
-                top: 75%;
-            }
+        align-items: center;
+        background: var(--image-contetn) no-repeat center;
+        background-size: 100% 100%;
+
+        .text-t {
+          width: 17%;
+          color: #fff;
+          font-size: 12px;
         }
 
-        .content-box1 {
-            position: relative;
-            width: 16%;
-            height: 100%;
-            background: var(--image-2) no-repeat center;
-            background-size: 100% 100%;
-            cursor: pointer;
-
-            .btn-label {
-                position: absolute;
-                left: 50%;
-                top: 0;
-                transform: translate(-50%);
-                font-size: 16px;
-                color: #fff;
-            }
-
-            .box-item {
-                position: absolute;
-                left: 50%;
-                transform: translate(-50%, 0);
-                width: 89%;
-                height: 16%;
-                padding: 0px 10px;
-                display: flex;
-                justify-content: space-between;
-                align-items: center;
-                background: var(--image-contetn) no-repeat center;
-                background-size: 100% 100%;
-
-                .text-t {
-                    width: 17%;
-                    color: #fff;
-                    font-size: 12px;
-                }
-
-                .text-v {
-                    width: 83%;
-                    font-family: 'douyuFont';
-                    font-size: 10px;
-                    color: var(--vent-table-action-link);
-                    display: flex;
-                    justify-content: flex-end;
-                }
-            }
-
-            .box-item1 {
-                top: 19%;
-            }
-
-            .box-item2 {
-                top: 41%;
-            }
-
-            .box-item3 {
-                top: 63%;
-            }
+        .text-v {
+          width: 83%;
+          font-family: 'douyuFont';
+          font-size: 10px;
+          color: var(--vent-table-action-link);
+          display: flex;
+          justify-content: flex-end;
         }
+      }
+
+      .box-item1 {
+        top: 24%;
+      }
+
+      .box-item2 {
+        top: 50%;
+      }
+
+      .box-item3 {
+        top: 75%;
+      }
     }
 
-    .echart-box {
-        height: calc(72% - 41px);
-        border: 1px solid #114aac;
-
-        .title-f {
-            height: 40px;
-            padding: 0px 10px;
-            box-sizing: border-box;
-            display: flex;
-            justify-content: space-between;
-            align-items: center;
-
-            .title-text {
-                font-family: 'douyuFont';
-                font-size: 14px;
-                color: #fff;
-            }
+    .content-box1 {
+      position: relative;
+      width: 16%;
+      height: 100%;
+      background: var(--image-2) no-repeat center;
+      background-size: 100% 100%;
+      cursor: pointer;
+
+      .btn-label {
+        position: absolute;
+        left: 50%;
+        top: 0;
+        transform: translate(-50%);
+        font-size: 16px;
+        color: #fff;
+      }
+
+      .box-item {
+        position: absolute;
+        left: 50%;
+        transform: translate(-50%, 0);
+        width: 89%;
+        height: 16%;
+        padding: 0px 10px;
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        background: var(--image-contetn) no-repeat center;
+        background-size: 100% 100%;
+
+        .text-t {
+          width: 17%;
+          color: #fff;
+          font-size: 12px;
         }
 
-        .echarts-box {
-            height: calc(100% - 40px);
+        .text-v {
+          width: 83%;
+          font-family: 'douyuFont';
+          font-size: 10px;
+          color: var(--vent-table-action-link);
+          display: flex;
+          justify-content: flex-end;
         }
+      }
+
+      .box-item1 {
+        top: 19%;
+      }
+
+      .box-item2 {
+        top: 41%;
+      }
+
+      .box-item3 {
+        top: 63%;
+      }
+    }
+  }
+
+  .echart-box {
+    height: calc(72% - 41px);
+    border: 1px solid #114aac;
+
+    .title-f {
+      height: 40px;
+      padding: 0px 10px;
+      box-sizing: border-box;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+
+      .title-text {
+        font-family: 'douyuFont';
+        font-size: 14px;
+        color: #fff;
+      }
+    }
+
+    .echarts-box {
+      height: calc(100% - 40px);
     }
+  }
 }
-</style>
+</style>

+ 52 - 81
src/views/vent/monitorManager/alarmMonitor/common/external-sgjc.vue

@@ -39,10 +39,10 @@
         </div>
         <div class="pl-10px pr-10px">
             <div class="mb-10px">
-                <AButton class="w-full" type="primary" @click="controlDevice('dianwei', 'zhi')">应急启动</AButton>
+                <AButton class="w-full" type="primary" @click="controlDevice()">应急启动</AButton>
             </div>
             <div>
-                <AButton class="w-full" type="primary" @click="controlDevice('dianwei', 'zhi')">应急关闭</AButton>
+                <AButton class="w-full" type="primary" @click="controlDevice()">应急关闭</AButton>
             </div>
         </div>
     </div>
@@ -80,91 +80,62 @@ let topContent = reactive({
 let $emit=defineEmits(['changeSelect','changeWarnLevel'])
 
 function changeSelect(val) {
-    selectData.value = val;
-    let data = bundletube.value.filter((v) => v.strinstallpos == selectData.value)[0];
-    topContent.time = data.readTime || '--';
-    topContent.warnLevel = data.syswarnLevel_str;
-    topContent.smokeJd = data.syswarnLevel_des;
-
-    // mbList[0].nd = data.readData.o2val || '--';
-    // mbList[1].nd = data.readData.coval || '--';
-    // mbList[2].nd = data.readData.co2val || '--';
-    // mbList[3].nd = data.readData.gasval || '--';
-    // mbList[4].nd = data.readData.chval || '--';
-    // mbList[5].nd = data.readData.ch2val || '--';
-    // mbList.forEach((el) => {
-    //     el.time1 = data ? data.readTime.substring(0, data.readTime.lastIndexOf(':')) : '--';
-    //     el.address = data ? data.strinstallpos : '--';
-    // });
-    // netStatus.value = data['netStatus'];
+  selectData.value = val;
+  const data = bundletube.value.find((v) => v.strinstallpos == selectData.value);
+  if (!data) return;
+  topContent.time = data.readTime || '--';
+  topContent.warnLevel = data.syswarnLevel_str;
+  topContent.smokeJd = data.syswarnLevel_des;
+  $emit('changeSelect', selectData.value);
+  $emit('changeWarnLevel', topContent.warnLevel);
 }
-// 设备控制
-function controlDevice(code, value?) {
-    const passWord = ref('');
-    Modal.confirm({
-        title: '是否确认执行该操作?',
-        maskClosable: true,
-        content: () => {
-            return h(Input, {
-                placeholder: '请输入密码',
-                type: 'password',
-                modelValue: passWord.value,
-                'onUpdate:value'(val) {
-                    passWord.value = val;
-                },
-            });
-        },
-        onOk() {
-            console.log('OK', passWord);
+
+function controlDevice() {
+  const passWord = ref('');
+  Modal.confirm({
+    title: '是否确认执行该操作?',
+    maskClosable: true,
+    content: () => {
+      return h(Input, {
+        placeholder: '请输入密码',
+        type: 'password',
+        modelValue: passWord.value,
+        'onUpdate:value'(val) {
+          passWord.value = val;
         },
-    });
-    // Promise.all(
-    //   [].map(({ deviceID, deviceType }) => {
-    //     return deviceControlApi({
-    //       deviceid: deviceID,
-    //       devicetype: deviceType,
-    //       paramcode: code,
-    //       value,
-    //       // password: passWord || globalConfig?.simulatedPassword,
-    //     });
-    //   })
-    // ).then((res) => {
-    //   // 模拟时开启
-    //   if (res.success) {
-    //     if (globalConfig.History_Type == 'remote') {
-    //       message.success('指令已下发至生产管控平台成功!');
-    //     } else {
-    //       message.success('指令已下发成功!');
-    //     }
-    //   } else {
-    //     message.error(res.message);
-    //   }
-    // });
+      });
+    },
+    onOk() {},
+  });
 }
 
-watch(() => props.externalTSgData, (newV, oldV) => {
-    bundletube.value = newV
-    if (bundletube.value.length != 0) {
-        selectList.value = bundletube.value.map((el) => {
-            return { label: el.strinstallpos, value: el.strinstallpos }
-        });
-        selectData.value = selectData.value ? selectData.value : selectList.value[0].value;
-
-        let dataVal = selectData.value ? bundletube.value.filter((v) => v.strinstallpos == selectData.value)[0] : bundletube.value[0];
-        topContent.temperature = props.temperatureData;
-        topContent.time = dataVal.readTime || '--';
-        topContent.warnLevel = dataVal.syswarnLevel_str;
-        topContent.smokeJd = dataVal.syswarnLevel_des;
-        $emit('changeSelect', selectData.value)
-        $emit('changeWarnLevel',topContent.warnLevel)
+watch(
+  () => props.externalTSgData,
+  (newV) => {
+    bundletube.value = (newV as any[]) || [];
+    if (bundletube.value.length !== 0) {
+      selectList.value = bundletube.value.map((el) => ({
+        label: el.strinstallpos,
+        value: el.strinstallpos,
+      }));
+      selectData.value = selectData.value || selectList.value[0].value;
+      const dataVal =
+        bundletube.value.find((v) => v.strinstallpos == selectData.value) || bundletube.value[0];
+      topContent.temperature = props.temperatureData;
+      topContent.time = dataVal.readTime || '--';
+      topContent.warnLevel = dataVal.syswarnLevel_str;
+      topContent.smokeJd = dataVal.syswarnLevel_des;
+      $emit('changeSelect', selectData.value);
+      $emit('changeWarnLevel', topContent.warnLevel);
     } else {
-        topContent.temperature = '0';
-        // topContent.position = '--';
-        topContent.time = '--';
-        topContent.warnLevel = '--';
-        topContent.smokeJd = '--';
+      topContent.temperature = '0';
+      topContent.time = '--';
+      topContent.warnLevel = '--';
+      topContent.smokeJd = '--';
     }
-}, { immediate: true })
+  },
+  { immediate: true }
+)
 
 </script>
 

+ 70 - 86
src/views/vent/monitorManager/alarmMonitor/common/fireWork.vue

@@ -1,114 +1,98 @@
 <template>
   <div class="fireWork">
-    <!-- 顶部区域 -->
     <div class="work-nav">
-      <internalFireTop :internalFireTopData="internalFireTopData"></internalFireTop>
+      <internalFireTop :internalFireTopData="internalFireTopData" />
     </div>
-    <!-- 中间区域 -->
     <div class="center-echart">
-      <internalFireCenter :internalFireCenterData="internalFireCenterData"></internalFireCenter>
+      <internalFireCenter :internalFireCenterData="internalFireCenterData" />
     </div>
-    <!-- 底部区域 -->
     <div class="bot-content">
-      <internalFireBot :internalFireBotData="internalFireBotData"></internalFireBot>
+      <internalFireBot :internalFireBotData="internalFireBotData" />
     </div>
   </div>
 </template>
 
 <script lang="ts" setup>
-  import { ref, reactive, watch } from 'vue';
-  import internalFireTop from './internal-fire-top.vue';
-  import internalFireCenter from './internal-fire-center.vue';
-  import internalFireBot from './internal-fire-bot.vue';
-  // import BaseTab from '../../../gas/components/tab/baseTab.vue';
+import { ref, watch } from 'vue';
+import internalFireTop from './internal-fire-top.vue';
+import internalFireCenter from './internal-fire-center.vue';
+import internalFireBot from './internal-fire-bot.vue';
 
-  let props = defineProps({
-    listData: Object,
-  });
-  let internalFireTopData = ref<any[]>([]);
-  let internalFireCenterData = ref<any[]>([]);
-  let internalFireBotData = ref<any[]>([]);
+const props = defineProps({
+  listData: Object,
+});
 
-  watch(
-    () => props.listData,
-    (val: any, val1) => {
-      if (JSON.stringify(val) === '{}') return;
-      internalFireTopData.value = val.fiber;
-      internalFireCenterData.value = val.fiber;
-      internalFireBotData.value = val.bundletube;
-    },
-    { deep: true }
-  );
+const internalFireTopData = ref<any[]>([]);
+const internalFireCenterData = ref<any[]>([]);
+const internalFireBotData = ref<any[]>([]);
+
+watch(
+  () => props.listData,
+  (val: any) => {
+    if (!val || JSON.stringify(val) === '{}') return;
+    internalFireTopData.value = val.fiber || [];
+    internalFireCenterData.value = val.fiber || [];
+    internalFireBotData.value = val.bundletube || [];
+  },
+  { deep: true, immediate: true }
+);
 </script>
 
 <style lang="less" scoped>
-  @import '/@/design/theme.less';
-
-  @{theme-deepblue} {
-    .fireWork {
-      --image-bj1: url('/@/assets/images/themify/deepblue/fire/bj1.png');
-      --image-max: url('/@/assets/images/themify/deepblue/fire/max.svg');
-      --image-min: url('/@/assets/images/themify/deepblue/fire/min.svg');
-      --image-pj: url('/@/assets/images/themify/deepblue/fire/pj.svg');
-      --image-bj1: url('/@/assets/images/themify/deepblue/fire/bj1.png');
-      --image-14174: url('/@/assets/images/themify/deepblue/fire/14174.png');
-      --image-contetn: url('/@/assets/images/themify/deepblue/fire/contetn.png');
-    }
-  }
+@import '/@/design/theme.less';
 
+@{theme-deepblue} {
   .fireWork {
-    --image-bj1: url('/@/assets/images/fire/bj1.png');
-    --image-max: url('/@/assets/images/fire/max.svg');
-    --image-min: url('/@/assets/images/fire/min.svg');
-    --image-pj: url('/@/assets/images/fire/pj.svg');
-    --image-bj1: url('/@/assets/images/fire/bj1.png');
-    --image-14174: url('/@/assets/images/fire/14174.png');
-    --image-contetn: url('/@/assets/images/fire/contetn.png');
-    --border-image-2: linear-gradient(to bottom, transparent, #024688, transparent);
-    width: 100%;
-    height: 100%;
-    padding: 20px;
-    box-sizing: border-box;
-
-    .work-nav {
-      height: 15%;
-      width: 100%;
-      margin-bottom: 20px;
-      background: var(--image-bj1) no-repeat center;
-      background-size: 100% 100%;
-    }
+    --image-bj1: url('/@/assets/images/themify/deepblue/fire/bj1.png');
+  }
+}
 
-    .center-echart {
-      width: 100%;
-      height: 32%;
-      padding: 10px;
-      margin-bottom: 20px;
-      box-sizing: border-box;
-      background: var(--image-bj1) no-repeat center;
-      background-size: 100% 100%;
-    }
+.fireWork {
+  --image-bj1: url('/@/assets/images/fire/bj1.png');
+  width: 100%;
+  height: 100%;
+  padding: 20px;
+  box-sizing: border-box;
 
-    .bot-content {
-      position: relative;
-      width: 100%;
-      height: calc(53% - 40px);
-      padding: 10px 10px 0px 10px;
-      box-sizing: border-box;
-      background: var(--image-bj1) no-repeat center;
-      background-size: 100% 100%;
-    }
+  .work-nav {
+    height: 15%;
+    width: 100%;
+    margin-bottom: 20px;
+    background: var(--image-bj1) no-repeat center;
+    background-size: 100% 100%;
   }
 
-  :deep(.zxm-select:not(.zxm-select-customize-input) .zxm-select-selector) {
-    border: 1px solid #3ad8ff77 !important;
-    background-color: #ffffff00 !important;
+  .center-echart {
+    width: 100%;
+    height: 32%;
+    padding: 10px;
+    margin-bottom: 20px;
+    box-sizing: border-box;
+    background: var(--image-bj1) no-repeat center;
+    background-size: 100% 100%;
   }
 
-  :deep(.zxm-select-selection-item) {
-    color: #fff !important;
+  .bot-content {
+    position: relative;
+    width: 100%;
+    height: calc(53% - 40px);
+    padding: 10px 10px 0;
+    box-sizing: border-box;
+    background: var(--image-bj1) no-repeat center;
+    background-size: 100% 100%;
   }
+}
 
-  :deep(.zxm-select-arrow) {
-    color: #fff;
-  }
+:deep(.zxm-select:not(.zxm-select-customize-input) .zxm-select-selector) {
+  border: 1px solid #3ad8ff77 !important;
+  background-color: #ffffff00 !important;
+}
+
+:deep(.zxm-select-selection-item) {
+  color: #fff !important;
+}
+
+:deep(.zxm-select-arrow) {
+  color: #fff;
+}
 </style>

+ 38 - 65
src/views/vent/monitorManager/alarmMonitor/common/gasCcb.vue

@@ -75,75 +75,56 @@
 </template>
 
 <script setup lang="ts">
-  import { onMounted, ref, watch, reactive } from 'vue';
+  import { ref, watch, reactive } from 'vue';
   import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
 
-  let props = defineProps({
+  const props = defineProps({
     gasData: {
       type: Object,
-      default: () => {
-        return {};
-      },
+      default: () => ({}),
     },
   });
-  let typeData = ref<any[]>(['pump_under']);
-  let pumpUnder = reactive({});
-  let pumpOver = reactive({});
+
+  const typeData = ref<any[]>(['pump_under']);
+  const pumpUnder = reactive<any>({ label: '', data: [] });
+  const pumpOver = reactive<any>({ label: '', data: [] });
+
+  function buildPumpList(data: any[], deviceType: string, columnKey: string) {
+    const labelData = getTableHeaderColumns(columnKey);
+    const param = labelData.map((el: any) => ({
+      name: el.title,
+      val: el.dataIndex,
+    }));
+    const filterData = data.find((v) => v.deviceType == deviceType);
+    if (!filterData) return { label: '', data: [] };
+    return {
+      label: filterData.strinstallpos,
+      data: param.map((item) => ({
+        name: item.name,
+        val: filterData.readData[item.val] && filterData.readData[item.val] != '0' ? filterData.readData[item.val] : '-',
+      })),
+    };
+  }
 
   watch(
     () => props.gasData,
-    (newV, oldV) => {
-      console.log(newV, 'ccc---');
-      let data = newV.pump;
-
-      if (data && data.length != 0) {
-        typeData.value = data.map((v) => v.deviceType);
-
-        let list = {
-          label: '',
-          data: [],
-        };
-        if (typeData.value.includes('pump_under')) {
-          let labelData = getTableHeaderColumns('pump_under_monitor');
-          let param = labelData.map((el: any) => {
-            return {
-              name: el.title,
-              val: el.dataIndex,
-            };
-          });
-          let filterData = data.filter((v) => v.deviceType == 'pump_under')[0];
-          list.label = filterData.strinstallpos;
-          list.data = param.map((item) => {
-            return {
-              name: item.name,
-              val: filterData.readData[item.val] && filterData.readData[item.val] != '0' ? filterData.readData[item.val] : '-',
-            };
-          });
-          pumpUnder = Object.assign({}, list);
-        } else if (typeData.value.includes('pump_under_31')) {
-          let labelData = getTableHeaderColumns('pump_under_31_monitor');
-          let param = labelData.map((el: any) => {
-            return {
-              name: el.title,
-              val: el.dataIndex,
-            };
-          });
-          let filterData = data.filter((v) => v.deviceType == 'pump_under_31')[0];
-          list.label = filterData.strinstallpos;
-          list.data = param.map((item) => {
-            return {
-              name: item.name,
-              val: filterData.readData[item.val] && filterData.readData[item.val] != '0' ? filterData.readData[item.val] : '-',
-            };
-          });
-          pumpOver = Object.assign({}, list);
-        }
+    (newV: any) => {
+      const data = newV?.pump;
+      if (!data || data.length === 0) return;
+
+      typeData.value = data.map((v) => v.deviceType);
+      if (typeData.value.includes('pump_under')) {
+        const list = buildPumpList(data, 'pump_under', 'pump_under_monitor');
+        Object.keys(pumpUnder).forEach((key) => delete pumpUnder[key]);
+        Object.assign(pumpUnder, list);
+      } else if (typeData.value.includes('pump_under_31')) {
+        const list = buildPumpList(data, 'pump_under_31', 'pump_under_31_monitor');
+        Object.keys(pumpOver).forEach((key) => delete pumpOver[key]);
+        Object.assign(pumpOver, list);
       }
     },
-    { immediate: true }
+    { immediate: true, deep: true }
   );
-
-  onMounted(() => {});
 </script>
 
 <style lang="less" scoped>
@@ -151,19 +132,11 @@
 
   @{theme-deepblue} {
     .gas-ccb {
-      --image-no-choice: url('/@/assets/images/themify/deepblue/fire/no-choice.png');
-      --image-choice: url('/@/assets/images/themify/deepblue/fire/choice.png');
-      --image-border: url('/@/assets/images/themify/deepblue/fire/border.png');
-      --image-bj1: url('/@/assets/images/themify/deepblue/fire/bj1.png');
       --image-top-area: url('/@/assets/images/themify/deepblue/fire/gas-top.png');
     }
   }
 
   .gas-ccb {
-    --image-no-choice: url('/@/assets/images/fire/no-choice.png');
-    --image-choice: url('/@/assets/images/fire/choice.png');
-    --image-border: url('/@/assets/images/fire/border.png');
-    --image-bj1: url('/@/assets/images/fire/bj1.png');
     --image-top-area: url('/@/assets/images/fire/gas-top.png');
 
     width: 100%;

+ 141 - 192
src/views/vent/monitorManager/alarmMonitor/common/internal-fire-bot.vue

@@ -102,33 +102,45 @@
       </div>
     </div>
     <div class="echart-box">
-      <PredictionCurve v-if="shownChart === 'default'" :chart="curveConfig" />
-      <echartLine1 v-if="shownChart === 'predict'" :echartDataSg="echartDataSg" :maxY="maxY1"
-        :lengedDataName="echartDataSg.lengedDataName" />
+      <FiberTempChart
+        :x-axis-data="chartXData"
+        :series-data="chartYData"
+        :max-value="chartMaxValue"
+        :min-value="chartMinValue"
+        :title="chartTitle"
+        :y-axis-name="chartYAxisName"
+        :value-label="chartValueLabel"
+        :value-unit="chartValueUnit"
+        height="100%"
+        compact
+        :mark-symbol-size="32"
+        data-zoom-mode="index"
+        :data-zoom-start="0"
+        :data-zoom-end="10"
+      />
     </div>
   </div>
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, watch } from 'vue'
-import echartLine1 from './echartLine1.vue';
-import PredictionCurve from './predictionCurve.vue';
+import { ref, reactive, watch } from 'vue';
+import FiberTempChart from '/@/views/vent/testChart/FiberTempChart.vue';
 
-let props = defineProps({
+const props = defineProps({
   internalFireBotData: {
     type: Array,
     default: () => {
-      return []
-    }
-  }
-})
-const shownChart = ref('default');
-let selectData = ref('');//下拉选项数据
-let selectList = ref<any[]>([]);//下拉选项列表
+      return [];
+    },
+  },
+});
 
-let bundletubeData = ref<any[]>([]);
+const selectData = ref('');
+const selectList = ref<any[]>([]);
+const bundletubeData = ref<any[]>([]);
+const echartDataSgList = ref<any[]>([]);
 
-let bunData = reactive({
+const bunData = reactive({
   o2: '--',
   o2time: '--',
   c2h4: '--',
@@ -141,31 +153,32 @@ let bunData = reactive({
   co2time: '--',
   c2h2: '--',
   c2h2time: '--',
-})
-
-//束管图表数据
-let echartDataSgList = ref<any[]>([]);
-//束管监测-图表数据
-let echartDataSg = reactive({
-  xData: [],
-  lengedDataName: '(%)',
-  yData: [],
-  lengedData: 'O₂',
 });
 
-let maxY1 = ref<any>(0);
+const currentGas = ref('O₂');
+const currentUnit = ref('(%)');
 
-/** 预测曲线的配置,数据分别为平均、最大、最小、当前值 */
-const curveConfig = ref<any>({ id: '0', label: '', time: new Date(), data: [0, 0, 0, 0] });
+const chartXData = ref<any[]>([]);
+const chartYData = ref<number[]>([]);
+const chartMaxValue = ref(0);
+const chartMinValue = ref(0);
+const chartTitle = ref('O₂');
+const chartYAxisName = ref('浓度(%)');
+const chartValueLabel = ref('浓度');
+const chartValueUnit = ref('%');
+let lastChartSignature = '';
 
-//下拉选项切换
-function changeSelect(val) {
-  selectData.value = val;
-  let data = bundletubeData.value.filter((v) => v.strinstallpos == selectData.value)[0];
-  let time = data.readTime.substring(0, data.readTime.lastIndexOf(':'));
-  bunData.o2 = data.readData.o2val
+function parseUnit(dw: string) {
+  const text = String(dw || '').replace(/[()()]/g, '').trim();
+  return text || '';
+}
+
+function fillCardData(data: any) {
+  if (!data?.readData) return;
+  const time = data.readTime ? data.readTime.substring(0, data.readTime.lastIndexOf(':')) : '--';
+  bunData.o2 = data.readData.o2val;
   bunData.o2time = time;
-  bunData.c2h4 = data.readData.ch2val
+  bunData.c2h4 = data.readData.ch2val;
   bunData.c2h4time = time;
   bunData.co = data.readData.coval;
   bunData.cotime = time;
@@ -177,193 +190,131 @@ function changeSelect(val) {
   bunData.c2h2time = time;
 }
 
-//束管实时数据选项点击
+function getSelectedDevice() {
+  return bundletubeData.value.find((v) => v.strinstallpos == selectData.value) || bundletubeData.value[0];
+}
+
+function applyChartData(nextX: any[], nextY: number[], nextMax: number, nextMin: number, title: string, dw: string) {
+  const unit = parseUnit(dw);
+  const signature = JSON.stringify({
+    x: nextX,
+    y: nextY,
+    max: nextMax,
+    min: nextMin,
+    title,
+    dw,
+  });
+  if (signature === lastChartSignature) return;
+  lastChartSignature = signature;
+
+  chartXData.value = nextX;
+  chartYData.value = nextY;
+  chartMaxValue.value = nextMax;
+  chartMinValue.value = nextMin;
+  chartTitle.value = title;
+  chartYAxisName.value = unit ? `浓度(${unit})` : '浓度';
+  chartValueLabel.value = '浓度';
+  chartValueUnit.value = unit;
+}
+
+// 下拉选项切换
+function changeSelect(val) {
+  selectData.value = val;
+  const data = getSelectedDevice();
+  if (!data) return;
+  fillCardData(data);
+  echartDataSgList.value = data.history || [];
+  getSgClick(currentGas.value, currentUnit.value);
+}
+
+// 束管实时数据选项点击(取值逻辑与原先保持一致)
 function getSgClick(title, dw) {
-  echartDataSg.xData.length = 0;
-  echartDataSg.yData.length = 0;
-  echartDataSg.lengedData = title;
-  echartDataSg.lengedDataName = dw;
+  currentGas.value = title;
+  currentUnit.value = dw;
+
+  const data = getSelectedDevice();
+  if (!data) return;
+
+  const nextX: any[] = [];
+  const nextY: number[] = [];
+  let nextMax = 0;
+  let nextMin = 0;
+  const avg = data.avgParam || {};
 
-  const data = bundletubeData.value.filter((v) => v.strinstallpos == selectData.value)[0];
   switch (title) {
     case 'O₂':
       echartDataSgList.value.forEach((el) => {
-        echartDataSg.xData.push(el.time);
-        echartDataSg.yData.push(el.o2val);
+        nextX.push(el.time);
+        nextY.push(Number(el.o2val));
       });
-
-      curveConfig.value = {
-        id: 'o2',
-        label: 'O₂',
-        time: echartDataSg.xData,
-        data: [
-          // 氧气预测曲线
-          data.avgParam?.avg_o2_value || 0,
-          data.avgParam?.max_o2_value || 0,
-          data.avgParam?.min_o2_value || 0,
-          // data.readData?.o2val,
-        ],
-        monitorData: echartDataSg.yData,
-      };
-      getmaxY();
+      nextMax = Number(avg.max_o2_value || 0);
+      nextMin = Number(avg.min_o2_value || 0);
       break;
     case 'C₂H₄':
       echartDataSgList.value.forEach((el) => {
-        echartDataSg.xData.push(el.time);
-        echartDataSg.yData.push(el.ch2val);
+        nextX.push(el.time);
+        nextY.push(Number(el.ch2val));
       });
-      curveConfig.value = {
-        id: 'ch2',
-        label: 'C₂H₄',
-        time: echartDataSg.xData,
-        data: [
-          // 预测曲线
-          data.avgParam?.avg_c2h4_value || 0,
-          data.avgParam?.max_c2h4_value || 0,
-          data.avgParam?.min_c2h4_value || 0,
-          // data.readData?.ch2val,
-        ],
-        monitorData: echartDataSg.yData,
-      };
-      getmaxY();
+      nextMax = Number(avg.max_c2h4_value || 0);
+      nextMin = Number(avg.min_c2h4_value || 0);
       break;
     case 'CO':
       echartDataSgList.value.forEach((el) => {
-        echartDataSg.xData.push(el.time);
-        echartDataSg.yData.push(el.coval);
+        nextX.push(el.time);
+        nextY.push(Number(el.coval));
       });
-      curveConfig.value = {
-        id: 'co',
-        label: 'CO',
-        time: echartDataSg.xData,
-        data: [
-          // 预测曲线
-          data.avgParam?.avg_co_value || 0,
-          data.avgParam?.max_co_value || 0,
-          data.avgParam?.min_co_value || 0,
-          // data.readData?.coval,
-        ],
-        monitorData: echartDataSg.yData,
-      };
-      getmaxY();
+      nextMax = Number(avg.max_co_value || 0);
+      nextMin = Number(avg.min_co_value || 0);
       break;
     case 'CH₄':
       echartDataSgList.value.forEach((el) => {
-        echartDataSg.xData.push(el.time);
-        echartDataSg.yData.push(el.gasval);
+        nextX.push(el.time);
+        nextY.push(Number(el.gasval));
       });
-      curveConfig.value = {
-        id: 'ch4',
-        label: 'CH₄',
-        time: echartDataSg.xData,
-        data: [
-          // 预测曲线
-          data.avgParam?.avg_ch4_value || 0,
-          data.avgParam?.max_ch4_value || 0,
-          data.avgParam?.min_ch4_value || 0,
-          // data.readData?.chval,
-        ],
-        monitorData: echartDataSg.yData,
-      };
-      getmaxY();
+      nextMax = Number(avg.max_ch4_value || 0);
+      nextMin = Number(avg.min_ch4_value || 0);
       break;
     case 'CO₂':
       echartDataSgList.value.forEach((el) => {
-        echartDataSg.xData.push(el.time);
-        echartDataSg.yData.push(el.co2val);
+        nextX.push(el.time);
+        nextY.push(Number(el.co2val));
       });
-      curveConfig.value = {
-        id: 'co2',
-        label: 'CO₂',
-        time: echartDataSg.xData,
-        data: [
-          // 预测曲线
-          data.avgParam?.avg_co2_value || 0,
-          data.avgParam?.max_co2_value || 0,
-          data.avgParam?.min_co2_value || 0,
-          // data.readData?.co2val,
-        ],
-        monitorData: echartDataSg.yData,
-      };
-      getmaxY();
+      nextMax = Number(avg.max_co2_value || 0);
+      nextMin = Number(avg.min_co2_value || 0);
       break;
     case 'C₂H₂':
       echartDataSgList.value.forEach((el) => {
-        echartDataSg.xData.push(el.time);
-        echartDataSg.yData.push(el.chval);
+        nextX.push(el.time);
+        nextY.push(Number(el.chval));
       });
-      curveConfig.value = {
-        id: 'gas',
-        label: 'C₂H₂',
-        time: echartDataSg.xData,
-        data: [
-          // 预测曲线
-          data.avgParam?.avg_c2h2_value || 0,
-          data.avgParam?.max_c2h2_value || 0,
-          data.avgParam?.min_c2h2_value || 0,
-          // data.readData?.gasval,
-        ],
-        monitorData: echartDataSg.yData,
-      };
-      getmaxY();
+      nextMax = Number(avg.max_c2h2_value || 0);
+      nextMin = Number(avg.min_c2h2_value || 0);
       break;
   }
-}
 
-function getmaxY() {
-  maxY1.value = echartDataSg.yData.reduce((acr, cur) => {
-    return acr > cur ? acr : cur;
-  });
-  maxY1.value =
-    maxY1.value.toString().indexOf('.') == -1 ? maxY1.value.toString() : maxY1.value.toString().substring(0, maxY1.value.toString().indexOf('.'));
-  if (maxY1.value.length < 2 && Number(maxY1.value) < 1) {
-    maxY1.value = 1;
-  } else if (maxY1.value.length < 2 && Number(maxY1.value) >= 1) {
-    maxY1.value = 10;
-  } else if (maxY1.value.length < 3) {
-    maxY1.value = (Number(maxY1.value[0]) + 1) * 10;
-  } else if (maxY1.value.length < 4) {
-    maxY1.value = (Number(maxY1.value[0]) + 1) * 100;
-  } else if (maxY1.value.length < 5) {
-    maxY1.value = (Number(maxY1.value[0]) + 1) * 1000;
-  } else if (maxY1.value.length < 6) {
-    maxY1.value = (Number(maxY1.value[0]) + 1) * 10000;
-  }
+  applyChartData(nextX, nextY, nextMax, nextMin, title, dw);
 }
 
-watch(() => props.internalFireBotData, (newV, oldV) => {
-  echartDataSg.xData.length = 0;
-  echartDataSg.yData.length = 0;
-  if (newV.length != 0) {
-    bundletubeData.value = newV;
-    //下拉选项列表
+watch(
+  () => props.internalFireBotData,
+  (newV) => {
+    if (!newV || newV.length === 0) return;
+
+    bundletubeData.value = newV as any[];
     selectList.value = bundletubeData.value.map((el) => {
       return { label: el.strinstallpos, value: el.strinstallpos };
     });
-    //默认选中
-    selectData.value = selectData.value ? selectData.value : selectList.value[0].value;
-    let choiceData = selectData.value ? bundletubeData.value.filter((v) => v.strinstallpos == selectData.value)[0] : bundletubeData.value[0];
-
-    let time = choiceData.readTime.substring(0, choiceData.readTime.lastIndexOf(':'));
-    bunData.o2 = choiceData.readData.o2val
-    bunData.o2time = time;
-    bunData.c2h4 = choiceData.readData.ch2val
-    bunData.c2h4time = time;
-    bunData.co = choiceData.readData.coval;
-    bunData.cotime = time;
-    bunData.ch4 = choiceData.readData.gasval;
-    bunData.ch4time = time;
-    bunData.co2 = choiceData.readData.co2val;
-    bunData.co2time = time;
-    bunData.c2h2 = choiceData.readData.chval;
-    bunData.c2h2time = time;
-
-    echartDataSgList.value = choiceData.history;
-
-    getSgClick(echartDataSg.lengedData, echartDataSg.lengedDataName);
-    getmaxY();
-  }
-}, { immediate: true })
+    selectData.value = selectData.value ? selectData.value : selectList.value[0]?.value;
+
+    const choiceData = getSelectedDevice();
+    if (!choiceData) return;
+
+    fillCardData(choiceData);
+    echartDataSgList.value = choiceData.history || [];
+    getSgClick(currentGas.value, currentUnit.value);
+  },
+  { immediate: true, deep: true }
+);
 </script>
 
 <style lang="less" scoped>
@@ -402,8 +353,6 @@ watch(() => props.internalFireBotData, (newV, oldV) => {
     margin-bottom: 10px;
 
     .text {
-      // height: 30px;
-      // line-height: 30px;
       font-family: 'douyuFont';
       font-size: 14px;
       color: #fff;
@@ -488,4 +437,4 @@ watch(() => props.internalFireBotData, (newV, oldV) => {
     height: calc(100% - 50px);
   }
 }
-</style>
+</style>

+ 22 - 59
src/views/vent/monitorManager/alarmMonitor/common/internal-fire-bot1.vue

@@ -125,9 +125,7 @@
                     </div>
                 </div>
                 <div class="echarts-box">
-                    <PredictionCurve v-if="shownChart === 'default'" :chart="curveConfig" />
-                    <echartLine1 v-if="shownChart === 'predict'" :echartDataSg="echartDataSg1"
-                        :lengedDataName="echartDataSg1.lengedDataName" :maxY="maxY" :minY="minY" />
+                    <PredictionCurve :chart="curveConfig" />
                 </div>
             </div>
             <div class="right-echartbox">
@@ -139,9 +137,7 @@
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, watch } from 'vue'
-import { getMaxY, getMinY } from '../common.data'
-import echartLine1 from './echartLine1.vue';
+import { ref, reactive, watch } from 'vue';
 import warnZb from './warnZb.vue';
 import PredictionCurve from './predictionCurve.vue';
 
@@ -194,19 +190,15 @@ let echartDataSg1 = reactive({
     lengedData: 'O₂',
     lengedDataName: '(%)',
 });
-let echartDataSgList = ref<any[]>([]);
-//设备连接状态
-let netStatus = ref(0);
-const shownChart = ref('default');
+const echartDataSgList = ref<any[]>([]);
+const netStatus = ref(0);
 /** 预测曲线的配置,数据分别为平均、最大、最小、当前值 */
 const curveConfig = ref<any>({ id: '0', label: '', time: new Date(), data: [0, 0, 0, 0] });
-let maxY = ref<any>(0);
-let minY = ref<any>(0)
-    let widthV = ref('75%');
-  let heightV = ref('80%');
-  let coordDw = ref<any[]>([31, 62, 110]);
-  let widthCanvas = ref(562);
-  let heightCanvas = ref(316);
+const widthV = ref('75%');
+const heightV = ref('80%');
+const coordDw = ref<any[]>([31, 62, 110]);
+const widthCanvas = ref(562);
+const heightCanvas = ref(316);
 
 //密闭参数选项切换
 function btnClick(item, ind) {
@@ -237,7 +229,6 @@ function btnClick(item, ind) {
                 ],
                 monitorData: echartDataSg1.yData,
             };
-            getmax();
             break;
         case 'C₂H₄':
             echartDataSgList.value.forEach((el) => {
@@ -257,7 +248,6 @@ function btnClick(item, ind) {
                 ],
                 monitorData: echartDataSg1.yData,
             };
-            getmax();
             break;
         case 'CO':
             echartDataSgList.value.forEach((el) => {
@@ -277,7 +267,6 @@ function btnClick(item, ind) {
                 ],
                 monitorData: echartDataSg1.yData,
             };
-            getmax();
             break;
         case 'CH₄':
             echartDataSgList.value.forEach((el) => {
@@ -297,7 +286,6 @@ function btnClick(item, ind) {
                 ],
                 monitorData: echartDataSg1.yData,
             };
-            getmax();
             break;
         case 'CO₂':
             echartDataSgList.value.forEach((el) => {
@@ -317,7 +305,6 @@ function btnClick(item, ind) {
                 ],
                 monitorData: echartDataSg1.yData,
             };
-            getmax();
             break;
         case 'C₂H₂':
             echartDataSgList.value.forEach((el) => {
@@ -337,59 +324,36 @@ function btnClick(item, ind) {
                 ],
                 monitorData: echartDataSg1.yData,
             };
-            getmax();
             break;
     }
 }
-function getmax() {
-    getMaxY(echartDataSg1.yData)
-    getMinY(echartDataSg1.yData)
-    // maxY.value = echartDataSg1.yData.reduce((acr, cur) => {
-    //   return acr > cur ? acr : cur;
-    // });
-    // maxY.value =
-    //   maxY.value.toString().indexOf('.') == -1 ? maxY.value.toString() : maxY.value.toString().substring(0, maxY.value.toString().indexOf('.'));
-    // if (maxY.value.length < 2 && Number(maxY.value) < 1) {
-    //   maxY.value = 1;
-    // } else if (maxY.value.length < 2 && Number(maxY.value) >= 1) {
-    //   maxY.value = 10;
-    // } else if (maxY.value.length < 3) {
-    //   maxY.value = (Number(maxY.value[0]) + 1) * 10;
-    // } else if (maxY.value.length < 4) {
-    //   maxY.value = (Number(maxY.value[0]) + 1) * 100;
-    // } else if (maxY.value.length < 5) {
-    //   maxY.value = (Number(maxY.value[0]) + 1) * 1000;
-    // } else if (maxY.value.length < 6) {
-    //   maxY.value = (Number(maxY.value[0]) + 1) * 10000;
-    // }
-}
 
-watch(() => props.internalFireBotData, (newV, oldV) => {
+watch(() => props.internalFireBotData, (newV) => {
     echartDataSg1.xData.length = 0;
     echartDataSg1.yData.length = 0;
     if (newV.length != 0 && props.selectData) {
-        bundletube.value = newV
-     
-        let dataVal =bundletube.value.filter((v) => v.strinstallpos == props.selectData)[0] 
-        let times = dataVal.readTime.substring(0, dataVal.readTime.lastIndexOf(':')) || '--';
-        let address = dataVal.strinstallpos || '--';
+        bundletube.value = newV as any[];
+        const dataVal = bundletube.value.find((v) => v.strinstallpos == props.selectData);
+        if (!dataVal) return;
+        const times = dataVal.readTime.substring(0, dataVal.readTime.lastIndexOf(':')) || '--';
+        const address = dataVal.strinstallpos || '--';
         bundleD.o2 = dataVal.readData.o2val || '--';
-        bundleD.o2time = times
-        bundleD.o2address = address
+        bundleD.o2time = times;
+        bundleD.o2address = address;
         bundleD.co = dataVal.readData.coval || '--';
-        bundleD.cotime = times
+        bundleD.cotime = times;
         bundleD.coaddress = address;
         bundleD.co2 = dataVal.readData.co2val || '--';
-        bundleD.co2time = times
+        bundleD.co2time = times;
         bundleD.co2address = address;
         bundleD.ch4 = dataVal.readData.gasval || '--';
-        bundleD.ch4time =times
+        bundleD.ch4time = times;
         bundleD.ch4address = address;
         bundleD.c2h2 = dataVal.readData.chval || '--';
-        bundleD.c2h2time = times
+        bundleD.c2h2time = times;
         bundleD.c2h2address = address;
         bundleD.c2h4 = dataVal.readData.ch2val || '--';
-        bundleD.c2h4time = times
+        bundleD.c2h4time = times;
         bundleD.c2h4address = address;
 
         echartDataSgList.value = dataVal.history;
@@ -401,7 +365,6 @@ watch(() => props.internalFireBotData, (newV, oldV) => {
             },
             activeIndex.value
         );
-        getmax();
     }
 }, { immediate: true })
 

+ 88 - 73
src/views/vent/monitorManager/alarmMonitor/common/internal-fire-center.vue

@@ -1,93 +1,108 @@
 <template>
-    <div class="internal-fire-center">
-        <div class="nav-title">
-            <div class="title">光纤测温系统温度实时监测</div>
-        </div>
-        <div class="echart-box">
-            <echartLine :echartDataGq="echartDataGq" :maxY="maxY" :echartDw="echartDw" />
-        </div>
+  <div class="internal-fire-center">
+    <div class="nav-title">
+      <div class="title">光纤测温系统温度实时监测</div>
     </div>
+    <div class="echart-box">
+      <FiberTempChart
+        :x-axis-data="xAxisData"
+        :series-data="seriesData"
+        :max-value="maxValue"
+        :min-value="minValue"
+        title=""
+        height="100%"
+        compact
+        :mark-symbol-size="36"
+        data-zoom-mode="index"
+        :data-zoom-start="0"
+        :data-zoom-end="20"
+      />
+    </div>
+  </div>
 </template>
 
 <script setup lang="ts">
-import { ref, reactive,watch } from 'vue'
-import echartLine from './echartLine.vue';
-
-let props=defineProps({
-    internalFireCenterData:{
-        type:Array,
-        default:()=>{
-            return []
-        }
-    }
-})
+import { ref, watch } from 'vue';
+import FiberTempChart from '/@/views/vent/testChart/FiberTempChart.vue';
 
-let maxY = ref(100);
-let echartDw = ref('(­°C)');
-//光钎测温-图表数据
-let echartDataGq = reactive<any>({
-  curData: {
-    lengedData: '实时温度',
-    data: [],
-  },
-  maxData: {
-    lengedData: '最大温度',
-    data: [],
+const props = defineProps({
+  internalFireCenterData: {
+    type: Array,
+    default: () => {
+      return [];
+    },
   },
-  minData: {
-    lengedData: '最小温度',
-    data: [],
-  },
-  avgData: {
-    lengedData: '平均温度',
-    data: [],
-  },
-  xData: [],
 });
 
-watch(()=>props.internalFireCenterData,(newV,oldV)=>{
-    echartDataGq.xData.length = 0;
-    echartDataGq.curData.data.length = 0;
-    echartDataGq.maxData.data.length = 0;
-    echartDataGq.minData.data.length = 0;
-    echartDataGq.avgData.data.length = 0;
-    if(newV.length!=0){
-        const fiber: any = newV[0];
-        const arr: any[] = JSON.parse(fiber.readData.fibreTemperature);
+const xAxisData = ref<any[]>([]);
+const seriesData = ref<number[]>([]);
+const maxValue = ref(60);
+const minValue = ref(20);
+let lastSignature = '';
+
+watch(
+  () => props.internalFireCenterData,
+  (newV) => {
+    const nextX: any[] = [];
+    const nextSeries: number[] = [];
+    let nextMax = 60;
+    let nextMin = 20;
+
+    if (newV && newV.length !== 0) {
+      const fiber: any = newV[0];
+      const readData = fiber?.readData || {};
+      const fmax = Number(readData.fmax);
+      const fmin = Number(readData.fmin);
+      if (!Number.isNaN(fmax)) nextMax = fmax;
+      if (!Number.isNaN(fmin)) nextMin = fmin;
+
+      try {
+        const arr: any[] = JSON.parse(readData.fibreTemperature || '[]');
         arr.forEach((el) => {
-        echartDataGq.xData.push(el.pos);
-        echartDataGq.curData.data.push(el.value);
-        echartDataGq.maxData.data.push(fiber.avgParam?.max_temperature_value || 0);
-        echartDataGq.minData.data.push(fiber.avgParam?.min_temperature_value || 0);
-        echartDataGq.avgData.data.push(fiber.avgParam?.avg_temperature_value || 0);
-      });
+          nextX.push(el.pos);
+          nextSeries.push(Number(el.value));
+        });
+      } catch (e) {
+        console.warn('fibreTemperature parse error', e);
+      }
     }
-},{immediate:true})
+
+    // 定时器重复推送相同数据时不触发图表更新,避免闪烁
+    const signature = JSON.stringify({ x: nextX, s: nextSeries, max: nextMax, min: nextMin });
+    if (signature === lastSignature) return;
+    lastSignature = signature;
+
+    xAxisData.value = nextX;
+    seriesData.value = nextSeries;
+    maxValue.value = nextMax;
+    minValue.value = nextMin;
+  },
+  { immediate: true, deep: true }
+);
 </script>
 
 <style lang="less" scoped>
 .internal-fire-center {
-    position: relative;
-    width: 100%;
-    height: 100%;
+  position: relative;
+  width: 100%;
+  height: 100%;
 
-    .nav-title {
-        height: 30px;
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
+  .nav-title {
+    height: 30px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
 
-        .title {
-            font-family: 'douyuFont';
-            font-size: 14px;
-            color: #fff;
-            // color: var(--vent-table-action-link);
-        }
+    .title {
+      font-family: 'douyuFont';
+      font-size: 14px;
+      color: #fff;
     }
+  }
 
-    .echart-box {
-        width: 100%;
-        height: calc(100% - 30px);
-    }
+  .echart-box {
+    width: 100%;
+    height: calc(100% - 30px);
+  }
 }
-</style>
+</style>

+ 24 - 22
src/views/vent/monitorManager/alarmMonitor/common/internal-fire-top.vue

@@ -24,33 +24,35 @@
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, watch } from 'vue'
+import { watch } from 'vue';
 import { topList } from '../common.data';
 import imgUrl from '/@/assets/images/fire/pie.png';
 
-let props = defineProps({
-    internalFireTopData: {
-        type: Array,
-        default: () => {
-            return []
-        }
-    }
-})
-
-watch(() => props.internalFireTopData, (newV, oldV) => {
-    if (newV.length != 0) {
-        const fiber: any = newV[0];
-        topList[0].value = fiber.readData.fmax;
-        topList[1].value = fiber.readData.fmin;
-        topList[2].value = fiber.readData.favg;
-        topList[3].text = fiber.warnFlag ? '报警' : '正常';
+const props = defineProps({
+  internalFireTopData: {
+    type: Array,
+    default: () => [],
+  },
+});
+
+watch(
+  () => props.internalFireTopData,
+  (newV) => {
+    if (newV && newV.length !== 0) {
+      const fiber: any = newV[0];
+      topList[0].value = fiber.readData?.fmax ?? '--';
+      topList[1].value = fiber.readData?.fmin ?? '--';
+      topList[2].value = fiber.readData?.favg ?? '--';
+      topList[3].text = fiber.warnFlag ? '报警' : '正常';
     } else {
-        topList[0].value = '--';
-        topList[1].value = '--';
-        topList[2].value = '--';
-        topList[3].text = '正常';
+      topList[0].value = '--';
+      topList[1].value = '--';
+      topList[2].value = '--';
+      topList[3].text = '正常';
     }
-}, { immediate: true })
+  },
+  { immediate: true }
+);
 </script>
 
 <style lang="less" scoped>

+ 19 - 21
src/views/vent/monitorManager/alarmMonitor/common/mainWell.vue

@@ -10,7 +10,6 @@
         :externalTSgData="externalTSgData"
         :temperatureData="temperatureData"
         @changeSelect="changeSelect"
-        @changeWarnLevel="changeWarnLevel"
       ></externalSgjc>
     </div>
 
@@ -30,13 +29,13 @@
 
     <!-- 束管监测  -->
     <div class="content-s" v-if="bundletubeData.bundletube.length != 0 && strType != 'sys_coalseam'">
-      <externalMb :externalTSgData="externalTSgData" :selectData="selectData" :warnLevel="warnLevel"></externalMb>
+      <externalMb :externalTSgData="externalTSgData" :selectData="selectData"></externalMb>
     </div>
   </div>
 </template>
 
 <script lang="ts" setup>
-  import { ref, computed, reactive, watch, h } from 'vue';
+  import { ref, reactive, watch } from 'vue';
   import externalGxcw from './external-gqcw.vue';
   import externalSgjc from './external-sgjc.vue';
   import externalThreeC from './external-threec.vue';
@@ -44,34 +43,33 @@
   import externalGxEchart from './external-gx-echart.vue';
   import externalMb from './external-mb.vue';
 
-  let props = defineProps({
+  const props = defineProps({
     listData: Object,
     strType: String,
   });
-  let bundletubeData = reactive({});
-  let externalTData = ref<any[]>([]); //top-光钎
-  let externalTSgData = ref<any[]>([]); //top-束管
-  let temperatureData = ref(''); //top-束管-温度
-  let selectData = ref('');
-  let warnLevel = ref('');
+
+  const bundletubeData = reactive<any>({
+    bundletube: [],
+    fiber: [],
+    temperature: [],
+  });
+  const externalTData = ref<any[]>([]);
+  const externalTSgData = ref<any[]>([]);
+  const temperatureData = ref('');
+  const selectData = ref('');
 
   function changeSelect(data) {
     selectData.value = data;
   }
-  function changeWarnLevel(data) {
-    warnLevel.value = data;
-  }
 
   watch(
     () => props.listData,
-    (val) => {
-      console.log(val, 'val---------------');
-      if (JSON.stringify(val) === '{}') return;
-      // props.listData = val;
-      bundletubeData = Object.assign({}, val);
-      externalTData.value = val.fiber;
-      externalTSgData.value = val.bundletube;
-      temperatureData.value = val.temperature[0] ? val.temperature[0].readData.temperature : '--';
+    (val: any) => {
+      if (!val || JSON.stringify(val) === '{}') return;
+      Object.assign(bundletubeData, val);
+      externalTData.value = val.fiber || [];
+      externalTSgData.value = val.bundletube || [];
+      temperatureData.value = val.temperature?.[0]?.readData?.temperature ?? '--';
     },
     { immediate: true, deep: true }
   );

+ 0 - 252
src/views/vent/monitorManager/alarmMonitor/common/measurePoint copy.vue

@@ -1,252 +0,0 @@
-<template>
-  <div class="content">
-    <div v-if="shown === 'default'" class="content-item">
-      <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>
-        <div class="item-r">
-          <div class="content-r" v-for="el in item.listR" :key="el.id">
-            <span>{{ `${el.label} : ` }}</span>
-            <span
-              :class="{
-                'status-f': el.label.includes('状态') && el.value == 1,
-                'status-l': el.label.includes('状态') && el.value == 0,
-              }"
-            >
-              {{ el.label.includes('状态') ? (el.value == 1 ? '异常' : el.value == 0 ? '正常' : el.value) : 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}`" class="chart-content">
-        <div class="text-center">
-          {{ item.label }}
-        </div>
-        <PredictionCurve :style="{ width: chartWidth || '474px' }" style="height: 300px; margin: 15px" :chart="item" />
-      </div>
-    </div>
-  </div>
-</template>
-<script setup lang="ts">
-  import { ref } from 'vue';
-  import BaseTab from '../../../gas/components/tab/baseTab.vue';
-  import PredictionCurve from './predictionCurve.vue';
-
-  // well i know this is trash but the time is reaching
-  defineProps<{
-    cards: { label: string; value: any; listR: { id: number; label: string; dw: string; value: any }[] }[];
-    charts: {
-      label: string;
-      time: Date;
-      data: [number, number, number, number];
-    }[];
-    title: string;
-    timeout?: number;
-    chartWidth?: string;
-  }>();
-
-  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';
-
-  @{theme-deepblue} {
-    .content {
-      --image-bot-area: url('/@/assets/images/themify/deepblue/fire/bot-area.png');
-      --image-bot-area1: url('/@/assets/images/themify/deepblue/fire/bot-area1.png');
-    }
-  }
-  .content {
-    --image-bot-area: url('/@/assets/images/fire/bot-area.png');
-    --image-bot-area1: url('/@/assets/images/fire/bot-area1.png');
-    height: 100%;
-    color: var(--vent-font-color);
-
-    .title {
-      height: 30px;
-      margin-bottom: 10px;
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-
-      .text {
-        font-family: 'douyuFont';
-        font-size: 14px;
-      }
-    }
-
-    .content-item {
-      display: flex;
-      // justify-content: flex-start;
-      align-items: flex-start;
-      flex-wrap: wrap;
-      height: calc(100% - 50px);
-      overflow-y: auto;
-
-      .card-content {
-        position: relative;
-        width: 30%;
-        height: 128px;
-        margin: 0px 15px 15px 15px;
-        background: var(--image-bot-area) no-repeat center;
-        background-size: 100% 100%;
-
-        .item-l {
-          position: absolute;
-          left: 32px;
-          top: 50%;
-          transform: translate(0, -50%);
-          width: 89px;
-          height: 98px;
-          background: var(--image-bot-area1) no-repeat center;
-
-          .label-l {
-            position: absolute;
-            left: 50%;
-            top: 7px;
-            color: var(--vent-font-color);
-            font-size: 14px;
-            transform: translate(-50%, 0);
-          }
-
-          .value-l {
-            position: absolute;
-            left: 50%;
-            top: 50px;
-            transform: translate(-50%, 0);
-            font-family: 'douyuFont';
-            font-size: 14px;
-            color: var(--vent-table-action-link);
-          }
-        }
-
-        .item-r {
-          position: absolute;
-          left: 132px;
-          top: 50%;
-          transform: translate(0, -50%);
-          height: 128px;
-          padding: 5px 0px;
-          display: flex;
-          flex-direction: column;
-          justify-content: space-around;
-          box-sizing: border-box;
-
-          .content-r {
-            display: flex;
-
-            span {
-              font-size: 14px;
-              color: var(--vent-font-color);
-
-              &:first-child {
-                display: inline-block;
-                width: 68px;
-              }
-
-              &:last-child {
-                display: inline-block;
-                width: calc(100% - 68px);
-              }
-            }
-
-            .status-f {
-              color: #ff0000;
-            }
-
-            .status-l {
-              color: var(--vent-table-action-link);
-            }
-          }
-        }
-      }
-    }
-
-    .chart-item {
-      display: flex;
-      justify-content: flex-start;
-      align-items: flex-start;
-      flex-wrap: wrap;
-      height: calc(100% - 50px);
-      overflow-y: auto;
-
-      .chart-content {
-        // border: 1px solid var(--vent-base-border);
-        box-shadow: inset 0px 0px 10px 1px var(--vent-modal-box-shadow);
-        padding: 10px 0;
-        margin: 0 5px 5px 5px;
-      }
-    }
-  }
-</style>

+ 14 - 19
src/views/vent/monitorManager/alarmMonitor/common/top-area.vue

@@ -53,22 +53,19 @@
   import { ventTunColumns } from '../alarm.data';
   import MonitorTable from '../../comment/MonitorTable.vue';
   import echartLine from '../common/echartLine.vue';
-  let props = defineProps({
+
+  const props = defineProps({
     activeIndex: {
       type: Number,
       default: 0,
     },
     statusData: {
       type: Array,
-      default: () => {
-        return [];
-      },
+      default: () => [],
     },
     echartData: {
       type: Object,
-      default: () => {
-        return {};
-      },
+      default: () => ({}),
     },
     maxY: {
       type: Number,
@@ -80,31 +77,29 @@
     },
     ventTunDataSource: {
       type: Array,
-      default: () => {
-        return [];
-      },
+      default: () => [],
     },
   });
 
-  let statusD = ref<any[]>([]);
-  let echartD = reactive({});
-  let echartDw = ref('(m³/min)');
+  const statusD = ref<any[]>([]);
+  const echartD = reactive<any>({});
+  const echartDw = ref('(m³/min)');
 
   watch(
     () => props.statusData,
-    (newV, oldV) => {
-      statusD.value = newV;
+    (newV) => {
+      statusD.value = (newV as any[]) || [];
     },
     { immediate: true }
   );
 
   watch(
     () => props.echartData,
-    (newE, oldE) => {
-      console.log(newE, '999');
-      echartD = Object.assign({}, newE);
+    (newE) => {
+      Object.keys(echartD).forEach((key) => delete echartD[key]);
+      Object.assign(echartD, newE || {});
     },
-    { immediate: true }
+    { immediate: true, deep: true }
   );
 </script>
 

+ 159 - 259
src/views/vent/monitorManager/alarmMonitor/warn/dustWarn.vue

@@ -13,7 +13,7 @@
       >
       <div class="alarm-menu">
         <div class="card-btn">
-          <div :class="activeIndex1 == ind ? 'btn1' : 'btn'" v-for="(item, ind) in menuList" :key="ind" @click="cardClick(ind, item)">
+          <div :class="activeIndex1 == ind ? 'btn1' : 'btn'" v-for="(item, ind) in menuList" :key="ind" @click="cardClick(ind)">
             <div class="text">{{ item.name }}</div>
             <div class="warn">{{ item.warn }}</div>
           </div>
@@ -54,30 +54,23 @@
 
 <script setup lang="ts">
   import { ref, reactive, onMounted, onUnmounted } from 'vue';
-  import { sysTypeWarnList, sysWarn, getDevice } from '../common.api';
+  import { sysTypeWarnList, getDevice } from '../common.api';
   import echartLine from '../common/echartLine.vue';
   import { useSystemSelect } from '/@/hooks/vent/useSystemSelect';
   import { useRouter } from 'vue-router';
   import CustomHeader from '/@/components/vent/customHeader.vue';
   import { usePermission } from '/@/hooks/web/usePermission';
-  import { useGlobSetting } from '/@/hooks/setting';
   import MeasurePoint from '../common/measurePoint.vue';
   import { getMaxY, getMinY } from '../common.data';
 
-  const glob = useGlobSetting();
   const { hasPermission } = usePermission();
-  const { options, optionValue, getSelectRow, getSysDataSource } = useSystemSelect('sys_surface_caimei'); // 参数为场景类型(设备类型管理中可以查询到)
-  //左侧数据列表
-  let menuList = ref<any[]>([]);
-  //当前左侧激活菜单的索引
-  let activeIndex1 = ref(0);
-  //顶部区域激活选项
-  let activeIndex = ref(0);
-  //顶部区域数据
-  let topAreaList = reactive<any[]>([]);
-  let choiceData = reactive<any[]>([]);
-  //粉尘图表数据
-  let echartDataFc = reactive<any>({
+  const { options, optionValue, getSelectRow } = useSystemSelect('sys_surface_caimei');
+  const menuList = ref<any[]>([]);
+  const activeIndex1 = ref(0);
+  const activeIndex = ref(0);
+  const topAreaList = reactive<any[]>([]);
+  let choiceData: any[] = [];
+  const echartDataFc = reactive<any>({
     maxData: {
       lengedData: '实时值(mg/m³)',
       data: [],
@@ -92,10 +85,10 @@
     },
     xData: [],
   });
-  let maxY = ref<any>(0);
-  let minY = ref<any>(0);
-  let echartDw = ref('(mg/m³)');
-  let gridV = reactive({
+  const maxY = ref<any>(0);
+  const minY = ref<any>(0);
+  const echartDw = ref('(mg/m³)');
+  const gridV = reactive({
     top: '12%',
     left: '2%',
     bottom: '5%',
@@ -104,259 +97,193 @@
   });
   const cardListTf = ref<any[]>([]);
   const chartListTf = ref<any[]>([]);
-  let router = useRouter();
-  let echartNow = ref<any[]>([]);
-  let echartYc = reactive<any[]>([]);
+  const router = useRouter();
+  const echartNow = ref<any[]>([]);
+  const echartYc = reactive<any[]>([]);
   let flag = ref(true);
 
-  // https获取监测数据
   let timer: null | NodeJS.Timeout = null;
-  function getMonitor(flag?) {
+
+  function clearPollTimer() {
+    if (timer) {
+      clearTimeout(timer);
+      timer = null;
+    }
+  }
+
+  function clearChartSeries() {
+    echartDataFc.maxData.data.length = 0;
+    echartDataFc.minData.data.length = 0;
+    echartDataFc.aveValue.data.length = 0;
+    echartDataFc.xData.length = 0;
+  }
+
+  function parseExpectInfo(index: number) {
+    const raw = choiceData[index]?.readData?.expectInfo;
+    if (!raw) return null;
+    try {
+      return typeof raw === 'string' ? JSON.parse(raw) : raw;
+    } catch (e) {
+      return null;
+    }
+  }
+
+  function fillChartByIndex(index: number, resetNowList = false) {
+    const expectInfo = parseExpectInfo(index);
+    if (!expectInfo) return;
+
+    if (resetNowList || flag.value) {
+      echartNow.value = expectInfo['list'] || [];
+      flag.value = false;
+    }
+
+    echartYc.push({
+      time: expectInfo['nowTime'],
+      value: expectInfo['nowVal'],
+    });
+
+    const setData = [...echartNow.value, ...echartYc].sort(
+      (a, b) => Date.parse(String(a.time)) - Date.parse(String(b.time))
+    );
+
+    clearChartSeries();
+    const aveVal = expectInfo['aveVal'];
+    const warnVal = expectInfo['fmin'] ? expectInfo['fmin'] : 0;
+    setData.forEach((el) => {
+      if (el.value && el.value != '0') {
+        echartDataFc.xData.push(el.time);
+        echartDataFc.maxData.data.push(el.value);
+        echartDataFc.minData.data.push(aveVal);
+        echartDataFc.aveValue.data.push(warnVal);
+      }
+    });
+
+    const echartD = [echartDataFc.maxData.data, echartDataFc.minData.data];
+    maxY.value = getMaxY(echartD);
+    minY.value = getMinY(echartD);
+  }
+
+  function getMonitor(immediate?) {
+    clearPollTimer();
     timer = setTimeout(
       () => {
         getMenuList();
         getWindDeviceList();
-        if (timer) {
-          timer = null;
-        }
+        timer = null;
         getMonitor(false);
       },
-      flag ? 0 : 1000
+      immediate ? 0 : 1000
     );
   }
-  //返回首页
+
   function getBack() {
     router.push('/monitorChannel/monitor-alarm-home');
   }
-  //菜单选项切换
-  function cardClick(ind, item) {
-    clearTimeout(timer);
+
+  function cardClick(ind) {
+    clearPollTimer();
     activeIndex1.value = ind;
     getMonitor(true);
   }
-  //顶部区域选项切换
+
   function topAreaClick(index) {
     activeIndex.value = index;
-    echartDataFc.maxData.data.length = 0;
-    echartDataFc.minData.data.length = 0;
-    echartDataFc.aveValue.data.length = 0;
-    echartDataFc.xData.length = 0;
+    clearChartSeries();
     echartYc.length = 0;
     flag.value = true;
-    if (flag.value) {
-      echartNow.value = JSON.parse(choiceData[index].readData.expectInfo)['list'];
-      flag.value = false;
-    }
-    echartYc.push({
-      time: JSON.parse(choiceData[index].readData.expectInfo)['nowTime'],
-      value: JSON.parse(choiceData[index].readData.expectInfo)['nowVal'],
-    });
-    let setData = [...echartNow.value, ...echartYc].sort((a, b) => Date.parse(new Date(a.time)) - Date.parse(new Date(b.time)));
-    setData.forEach((el) => {
-      if (el.value && el.value != '0') {
-        echartDataFc.xData.push(el.time);
-        echartDataFc.maxData.data.push(el.value);
-        echartDataFc.minData.data.push(JSON.parse(choiceData[index].readData.expectInfo)['aveVal']);
-        echartDataFc.aveValue.data.push(
-          JSON.parse(choiceData[activeIndex.value].readData.expectInfo)['fmin']
-            ? JSON.parse(choiceData[activeIndex.value].readData.expectInfo)['fmin']
-            : 0
-        );
-      }
-    });
+    fillChartByIndex(index, true);
   }
-  //获取左侧菜单列表
+
   async function getMenuList() {
-    let res = await sysTypeWarnList({ type: 'dust' });
-    if (res.length != 0) {
-      const menuListTemp: any[] = [];
-      res.forEach((el) => {
-        menuListTemp.push({
-          name: el.systemname,
-          warn: el.warnDes,
-          deviceID: el.id,
-          strtype: el.strtype,
-          detail: el.detail,
-        });
-      });
-      menuList.value = menuListTemp;
-      getDetailList(menuList.value[activeIndex1.value].detail);
-    }
+    const res = await sysTypeWarnList({ type: 'dust' });
+    if (!res || res.length === 0) return;
+
+    menuList.value = res.map((el) => ({
+      name: el.systemname,
+      warn: el.warnDes,
+      deviceID: el.id,
+      strtype: el.strtype,
+      detail: el.detail,
+    }));
+    getDetailList(menuList.value[activeIndex1.value]?.detail);
   }
-  //获取右侧详情列表数据
+
   function getDetailList(param) {
     topAreaList.length = 0;
-    if (JSON.stringify(param) != '{}') {
-      param.dust.forEach((el) => {
-        topAreaList.push({
-          title: el.strinstallpos,
-          content: [
-            { ids: 0, label: '温度(°C)', value: el.readData.temperature || '--' },
-            { ids: 1, label: '粉尘浓度(mg/m³)', value: el.readData.dustval || '--' },
-            { ids: 2, label: '喷雾水压(mPa)', value: el.readData.waterPressure || '--' },
-            { ids: 3, label: '喷雾状态', value: el.readData.atomizingState || '--' },
-          ],
-        });
+    if (!param || JSON.stringify(param) === '{}' || !param.dust) return;
+
+    param.dust.forEach((el) => {
+      topAreaList.push({
+        title: el.strinstallpos,
+        content: [
+          { ids: 0, label: '温度(°C)', value: el.readData.temperature || '--' },
+          { ids: 1, label: '粉尘浓度(mg/m³)', value: el.readData.dustval || '--' },
+          { ids: 2, label: '喷雾水压(mPa)', value: el.readData.waterPressure || '--' },
+          { ids: 3, label: '喷雾状态', value: el.readData.atomizingState || '--' },
+        ],
       });
-      choiceData = param.dust;
+    });
+    choiceData = param.dust;
 
-      if (choiceData[activeIndex.value]) {
-        if (flag.value) {
-          echartNow.value = JSON.parse(choiceData[activeIndex.value].readData.expectInfo)['list'];
-          flag.value = false;
-        }
-        echartYc.push({
-          time: JSON.parse(choiceData[activeIndex.value].readData.expectInfo)['nowTime'],
-          value: JSON.parse(choiceData[activeIndex.value].readData.expectInfo)['nowVal'],
-        });
-        let setData = [...echartNow.value, ...echartYc].sort((a, b) => Date.parse(new Date(a.time)) - Date.parse(new Date(b.time)));
-        echartDataFc.maxData.data.length = 0;
-        echartDataFc.minData.data.length = 0;
-        echartDataFc.aveValue.data.length = 0;
-        echartDataFc.xData.length = 0;
-        setData.forEach((el) => {
-          if (el.value && el.value != '0') {
-            echartDataFc.xData.push(el.time);
-            echartDataFc.maxData.data.push(el.value);
-            echartDataFc.minData.data.push(JSON.parse(choiceData[activeIndex.value].readData.expectInfo)['aveVal']);
-            echartDataFc.aveValue.data.push(
-              JSON.parse(choiceData[activeIndex.value].readData.expectInfo)['fmin']
-                ? JSON.parse(choiceData[activeIndex.value].readData.expectInfo)['fmin']
-                : 0
-            );
-          }
-        });
-        let echartD = [echartDataFc.maxData.data, echartDataFc.minData.data];
-        maxY.value = getMaxY(echartD);
-        minY.value = getMinY(echartD);
-        // maxY.value = echartDataFc.maxData.data.reduce((acr, cur) => {
-        //   return acr > cur ? acr : cur;
-        // });
-        // maxY.value =
-        //   maxY.value.toString().indexOf('.') == -1 ? maxY.value.toString() : maxY.value.toString().substring(0, maxY.value.toString().indexOf('.'));
-        // if (maxY.value.length < 2 && Number(maxY.value) < 1) {
-        //   maxY.value = 1;
-        // } else if (maxY.value.length < 2 && Number(maxY.value) >= 1) {
-        //   maxY.value = 10;
-        // } else if (maxY.value.length < 3) {
-        //   maxY.value = (Number(maxY.value[0]) + 1) * 10;
-        // } else if (maxY.value.length < 4) {
-        //   maxY.value = (Number(maxY.value[0]) + 1) * 100;
-        // } else if (maxY.value.length < 5) {
-        //   maxY.value = (Number(maxY.value[0]) + 1) * 1000;
-        // } else if (maxY.value.length < 6) {
-        //   maxY.value = (Number(maxY.value[0]) + 1) * 10000;
-        // }
-      } else {
-        activeIndex.value = 0;
-        if (flag.value) {
-          echartNow.value = JSON.parse(choiceData[activeIndex.value].readData.expectInfo)['list'];
-          flag.value = false;
-        }
-        echartYc.push({
-          time: JSON.parse(choiceData[activeIndex.value].readData.expectInfo)['nowTime'],
-          value: JSON.parse(choiceData[activeIndex.value].readData.expectInfo)['nowVal'],
-        });
-        let setData = [...echartNow.value, ...echartYc].sort((a, b) => Date.parse(new Date(a.time)) - Date.parse(new Date(b.time)));
-        echartDataFc.maxData.data.length = 0;
-        echartDataFc.minData.data.length = 0;
-        echartDataFc.aveValue.data.length = 0;
-        echartDataFc.xData.length = 0;
-        setData.forEach((el) => {
-          if (el.value && el.value != '0') {
-            echartDataFc.xData.push(el.time);
-            echartDataFc.maxData.data.push(el.value);
-            echartDataFc.minData.data.push(JSON.parse(choiceData[activeIndex.value].readData.expectInfo)['aveVal']);
-            echartDataFc.aveValue.data.push(
-              JSON.parse(choiceData[activeIndex.value].readData.expectInfo)['fmin']
-                ? JSON.parse(choiceData[activeIndex.value].readData.expectInfo)['fmin']
-                : 0
-            );
-          }
-        });
-        let echartD = [echartDataFc.maxData.data, echartDataFc.minData.data];
-        maxY.value = getMaxY(echartD);
-        minY.value = getMinY(echartD);
-        // maxY.value = echartDataFc.maxData.data.reduce((acr, cur) => {
-        //   return acr > cur ? acr : cur;
-        // });
-        // maxY.value =
-        //   maxY.value.toString().indexOf('.') == -1 ? maxY.value.toString() : maxY.value.toString().substring(0, maxY.value.toString().indexOf('.'));
-        // if (maxY.value.length < 2) {
-        //   maxY.value = 10;
-        // } else if (maxY.value.length < 3) {
-        //   maxY.value = (Number(maxY.value[0]) + 1) * 10;
-        // } else if (maxY.value.length < 4) {
-        //   maxY.value = (Number(maxY.value[0]) + 1) * 100;
-        // } else if (maxY.value.length < 5) {
-        //   maxY.value = (Number(maxY.value[0]) + 1) * 1000;
-        // } else if (maxY.value.length < 6) {
-        //   maxY.value = (Number(maxY.value[0]) + 1) * 10000;
-        // }
-      }
+    if (!choiceData[activeIndex.value]) {
+      activeIndex.value = 0;
     }
+    if (!choiceData[activeIndex.value]) return;
+    fillChartByIndex(activeIndex.value);
   }
 
-  //获取粉尘监控测点信息
   async function getWindDeviceList() {
-    // cardListTf.length = 0;
     const cardListTfTemp: any[] = [];
     const chartListTfTemp: any[] = [];
-    let res = await getDevice({ devicetype: 'dusting', pagetype: 'normal' });
-    if (res && res.msgTxt[0]) {
-      let list = res.msgTxt[0].datalist || [];
-      if (list.length > 0) {
-        list.forEach((el: any) => {
-          const readData = el.readData;
-          el = Object.assign(el, readData);
-          cardListTfTemp.push({
-            label: '通信状态',
-            value: el.netStatus == '0' ? '断开' : '连接',
-            listR: [
-              { id: 0, label: '安装位置', dw: '', value: el.strinstallpos || '-' },
-              { id: 1, label: '粉尘浓度', dw: '(mg/m³)', value: el.dustval || '-' },
-              {
-                id: 2,
-                label: '巷道湿度',
-                dw: el.humidity && Number(el.humidity) < 1 ? '(RH)' : el.humidity && Number(el.humidity) > 1 ? '(%RH)' : '',
-                value: el.humidity || '-',
-              },
-              { id: 4, label: '巷道温度', dw: el.humidity ? '(℃)' : '', value: el.temperature || '-' },
-              {
-                id: 3,
-                label: '是否报警',
-                dw: '',
-                value: el.warnFlag == '0' ? '正常' : el.warnFlag == 1 ? '报警' : el.warnFlag == 2 ? '断开' : '未监测',
-              },
-            ],
-          });
-
-          // 初始化预测曲线配置,分别为x轴时间、平均、最大、最小、实时
-          const avgParam = el.avgParam || {
-            avg_dusting_value: 0,
-            max_dusting_value: 0,
-            min_dusting_value: 0,
-          };
-          chartListTfTemp.push({
-            label: el.strinstallpos,
-            time: new Date(),
-            data: [avgParam.avg_dusting_value, avgParam.max_dusting_value, avgParam.min_dusting_value, el.readData.dustval],
-          });
-        });
-      }
-    }
+    const res = await getDevice({ devicetype: 'dusting', pagetype: 'normal' });
+    const list = res?.msgTxt?.[0]?.datalist || [];
+    list.forEach((el: any) => {
+      const readData = el.readData || {};
+      Object.assign(el, readData);
+      cardListTfTemp.push({
+        label: '通信状态',
+        value: el.netStatus == '0' ? '断开' : '连接',
+        listR: [
+          { id: 0, label: '安装位置', dw: '', value: el.strinstallpos || '-' },
+          { id: 1, label: '粉尘浓度', dw: '(mg/m³)', value: el.dustval || '-' },
+          {
+            id: 2,
+            label: '巷道湿度',
+            dw: el.humidity && Number(el.humidity) < 1 ? '(RH)' : el.humidity && Number(el.humidity) > 1 ? '(%RH)' : '',
+            value: el.humidity || '-',
+          },
+          { id: 4, label: '巷道温度', dw: el.humidity ? '(℃)' : '', value: el.temperature || '-' },
+          {
+            id: 3,
+            label: '是否报警',
+            dw: '',
+            value: el.warnFlag == '0' ? '正常' : el.warnFlag == 1 ? '报警' : el.warnFlag == 2 ? '断开' : '未监测',
+          },
+        ],
+      });
+
+      const avgParam = el.avgParam || {};
+      chartListTfTemp.push({
+        label: el.strinstallpos,
+        time: new Date(),
+        data: [
+          avgParam.avg_dusting_value || 0,
+          avgParam.max_dusting_value || 0,
+          avgParam.min_dusting_value || 0,
+          readData.dustval,
+        ],
+      });
+    });
     cardListTf.value = cardListTfTemp;
     chartListTf.value = chartListTfTemp;
   }
+
   onMounted(() => {
-    getMenuList();
     getMonitor(true);
   });
+
   onUnmounted(() => {
-    if (timer) {
-      clearTimeout(timer);
-      timer = undefined;
-    }
+    clearPollTimer();
   });
 </script>
 
@@ -371,7 +298,6 @@
       --image-dust-choice: url('/@/assets/images/themify/deepblue/fire/dust-choice.png');
       --image-dust-content: url('/@/assets/images/themify/deepblue/fire/dust-content.png');
       --image-dust-choice1: url('/@/assets/images/themify/deepblue/fire/dust-choice1.png');
-      --image-dust-content: url('/@/assets/images/themify/deepblue/fire/dust-content.png');
       --image-bj1: url('/@/assets/images/themify/deepblue/fire/bj1.png');
     }
   }
@@ -383,7 +309,6 @@
     --image-dust-choice: url('/@/assets/images/fire/dust-choice.png');
     --image-dust-content: url('/@/assets/images/fire/dust-content.png');
     --image-dust-choice1: url('/@/assets/images/fire/dust-choice1.png');
-    --image-dust-content: url('/@/assets/images/fire/dust-content.png');
     --image-bj1: url('/@/assets/images/fire/bj1.png');
     width: 100%;
     height: 100%;
@@ -490,7 +415,6 @@
           height: 100%;
           display: flex;
           flex-direction: column;
-          // justify-content: space-around;
           align-items: flex-start;
           overflow-y: auto;
           overflow-x: hidden;
@@ -627,30 +551,6 @@
             height: calc(100% - 40px);
           }
         }
-
-        .content-right1 {
-          width: 100%;
-          height: 100%;
-
-          .title-t {
-            height: 30px;
-            margin-bottom: 10px;
-            display: flex;
-            justify-content: space-between;
-            align-items: center;
-
-            .text-t {
-              font-family: 'douyuFont';
-              font-size: 14px;
-              color: #fff;
-            }
-          }
-
-          .echart-boxd {
-            width: 100%;
-            height: calc(100% - 40px);
-          }
-        }
       }
     }
 

+ 119 - 165
src/views/vent/monitorManager/alarmMonitor/warn/fireWarn.vue

@@ -27,219 +27,176 @@
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, onMounted, onUnmounted, defineAsyncComponent } from 'vue';
+import { ref, reactive, onMounted, onUnmounted } from 'vue';
 import { typeMenuList, componentName } from '../common.data';
-import { sysTypeWarnList, sysWarn } from '../common.api';
+import { sysTypeWarnList } from '../common.api';
 import { useSystemSelect } from '/@/hooks/vent/useSystemSelect';
 import { useGlobSetting } from '/@/hooks/setting';
 import { useRouter } from 'vue-router';
 import CustomHeader from '/@/components/vent/customHeader.vue';
 import { usePermission } from '/@/hooks/web/usePermission';
 
-let loading = ref(false); //加载状态
+const loading = ref(false);
 const { hasPermission } = usePermission();
-const { options, optionValue, getSelectRow, getSysDataSource } = useSystemSelect('sys_surface_caimei'); // 参数为场景类型(设备类型管理中可以查询到)
-//当前加载组件
-let currentLoad = ref('');
-//内外因火灾激活索引
-let activeIndex = ref(0);
-//当前激活菜单的索引
-let activeIndex1 = ref(0);
-let menuList = ref<any[]>([]); //左侧菜单列表
-let menuList1 = reactive({
-  external: [],
-  internal: [],
-  info: [],
+const { options, optionValue, getSelectRow } = useSystemSelect('sys_surface_caimei');
+const currentLoad = ref('');
+const activeIndex = ref(0);
+const activeIndex1 = ref(0);
+const menuList = ref<any[]>([]);
+const menuList1 = reactive({
+  external: [] as any[],
+  internal: [] as any[],
+  info: [] as any[],
 });
-//详情数据
-let listData = reactive({
+const listData = reactive({
   common: {},
-  bundletube: [],
-  fiber: [],
-  fire: [],
-  co: [],
-  smoke: [],
-  spray: [],
-  temperature: [],
-}); //详情数据
-let strType = ref(''); //火灾外因-区别工作面和煤层
-let router = useRouter();
-let tableLists = ref<any[]>([]);
-
-// https获取监测数据
+  bundletube: [] as any[],
+  fiber: [] as any[],
+  fire: [] as any[],
+  co: [] as any[],
+  smoke: [] as any[],
+  spray: [] as any[],
+  temperature: [] as any[],
+});
+const strType = ref('');
+const router = useRouter();
+const tableLists = ref<any[]>([]);
+
 let timer: null | NodeJS.Timeout = null;
+
+function clearPollTimer() {
+  if (timer) {
+    clearTimeout(timer);
+    timer = null;
+  }
+}
+
 function getMonitor(flag?) {
   timer = setTimeout(
     async () => {
       await getMenuList();
-      if (timer) {
-        timer = null;
-      }
+      timer = null;
       getMonitor(false);
     },
     flag ? 0 : 1500
   );
 }
 
-//返回首页
 function getBack() {
   router.push('/monitorChannel/monitor-alarm-home');
 }
 
-//获取左侧菜单列表
 async function getMenuList() {
-  let res = await sysTypeWarnList({ type: 'fire' });
-  if (res.length != 0) {
-     menuList1.external = res.external
-    // menuList1.external = res.external.filter((v) => v.strtype != 'sys_surface_caimei');
-    menuList1.internal = res.internal;
-    menuList1.info = res.info;
-    if (!activeIndex.value && menuList1.internal && menuList1.internal.length > 0) {
-      menuList.value = menuList1.internal.map((el: any) => {
-        return {
-          name: el.systemname,
-          warn: el.warnDes,
-          type: 'on',
-          deviceID: el.id,
-          strtype: el.strtype,
-          detail: el.detail,
-        }
-      });
-      getDetailList(menuList.value[activeIndex1.value].detail);
-    } else if (activeIndex.value == 1 && menuList1.external && menuList1.external.length > 0) {
-      menuList.value = menuList1.external.map((el: any) => {
-        return {
-          name: el.systemname,
-          warn: el.warnDes,
-          type: 'out',
-          deviceID: el.id,
-          strtype: el.strtype,
-          detail: el.detail,
-        }
-      });
-      strType.value = menuList.value[activeIndex1.value].strtype;
-      getDetailList(menuList.value[activeIndex1.value].detail);
-    } else {
-      menuList.value = menuList1.info.map((el: any) => {
-        return {
-          name: el.sysname,
-          // warn: '正常',
-          deviceID: el.sysid,
-          strtype: '',
-          detail: el.list,
-        }
-      });
-      getDetailList(menuList.value[activeIndex1.value].detail);
-     
-    }
+  const res = await sysTypeWarnList({ type: 'fire' });
+  if (!res || res.length === 0) return;
+
+  menuList1.external = res.external || [];
+  menuList1.internal = res.internal || [];
+  menuList1.info = res.info || [];
+
+  if (!activeIndex.value && menuList1.internal.length > 0) {
+    menuList.value = menuList1.internal.map((el: any) => ({
+      name: el.systemname,
+      warn: el.warnDes,
+      type: 'on',
+      deviceID: el.id,
+      strtype: el.strtype,
+      detail: el.detail,
+    }));
+    getDetailList(menuList.value[activeIndex1.value]?.detail);
+  } else if (activeIndex.value === 1 && menuList1.external.length > 0) {
+    menuList.value = menuList1.external.map((el: any) => ({
+      name: el.systemname,
+      warn: el.warnDes,
+      type: 'out',
+      deviceID: el.id,
+      strtype: el.strtype,
+      detail: el.detail,
+    }));
+    strType.value = menuList.value[activeIndex1.value]?.strtype || '';
+    getDetailList(menuList.value[activeIndex1.value]?.detail);
+  } else if (activeIndex.value === 2 && menuList1.info.length > 0) {
+    menuList.value = menuList1.info.map((el: any) => ({
+      name: el.sysname,
+      deviceID: el.sysid,
+      strtype: '',
+      detail: el.list,
+    }));
+    getDetailList(menuList.value[activeIndex1.value]?.detail);
+  } else {
+    menuList.value = [];
   }
 }
-//获取右侧详情弹窗数据
+
 function getDetailList(param) {
-  if (activeIndex.value != 2) {
-    listData.bundletube = param.bundletube;
-    listData.fiber = param.fiber;
-    listData.fire = param.fire;
-    listData.co = param.co;
-    listData.smoke = param.smoke;
-    listData.spray = param.spray;
-    listData.temperature = param.temperature;
+  if (!param) return;
+  if (activeIndex.value !== 2) {
+    listData.bundletube = param.bundletube || [];
+    listData.fiber = param.fiber || [];
+    listData.fire = param.fire || [];
+    listData.co = param.co || [];
+    listData.smoke = param.smoke || [];
+    listData.spray = param.spray || [];
+    listData.temperature = param.temperature || [];
     loadZj();
   } else {
     tableLists.value = param;
     loadZb();
   }
 }
-//内外因火灾、预警指标选项切换
+
+function resetAndReload(extra?: () => void) {
+  loading.value = true;
+  setTimeout(() => {
+    clearPollTimer();
+    activeIndex1.value = 0;
+    currentLoad.value = '';
+    extra?.();
+    getMonitor(true);
+    loading.value = false;
+  }, 1000);
+}
+
 function fireMenuToggle(ind) {
   activeIndex.value = ind;
-   menuList.value=[]
-  switch (ind) {
-    case 0:
-      loading.value = true;
-      setTimeout(() => {
-        clearTimeout(timer);
-        activeIndex1.value = 0;
-        currentLoad.value = '';
-        getClearList();
-        getMonitor();
-        loading.value = false;
-      }, 1000);
-      break;
-    case 1:
-      loading.value = true;
-      setTimeout(() => {
-        clearTimeout(timer);
-        activeIndex1.value = 0;
-        currentLoad.value = '';
-        getClearList();
-        getMonitor();
-        loading.value = false;
-      }, 1000);
-      break;
-    case 2:
-      loading.value = true;
-      setTimeout(() => {
-        clearTimeout(timer);
-        activeIndex1.value = 0;
-        currentLoad.value = '';
-        getMonitor();
-        loading.value = false;
-      }, 1000);
-      break;
-  }
+  menuList.value = [];
+  resetAndReload(() => {
+    if (ind !== 2) getClearList();
+  });
 }
-//加载预警指标组件
+
 function loadZb() {
   const { sysOrgCode } = useGlobSetting();
-  switch (sysOrgCode) {
-    case 'sdmtjtbdmk': // 宝德
-      currentLoad.value = 'warnFireBd';
-      return currentLoad.value;
-    case 'sdmtjtbetmk': // 布尔台
-      currentLoad.value = 'warnFireBrt';
-      return currentLoad.value;
-    default:
-      currentLoad.value = 'warnFireBrt';
-      return currentLoad.value;
-  }
+  currentLoad.value = sysOrgCode === 'sdmtjtbdmk' ? 'warnFireBd' : 'warnFireBrt';
 }
-//菜单选项切换
+
 function cardClick(ind, item) {
-  if (activeIndex.value != 2) {
-    loading.value = true;
-    setTimeout(() => {
-      clearTimeout(timer);
-      activeIndex1.value = ind;
+  loading.value = true;
+  setTimeout(() => {
+    clearPollTimer();
+    activeIndex1.value = ind;
+    if (activeIndex.value !== 2) {
       getClearList();
       strType.value = item.strtype;
       currentLoad.value = '';
-      getMonitor();
-      loading.value = false;
-    }, 1000);
-  } else {
-    loading.value = true;
-    setTimeout(() => {
-      clearTimeout(timer);
-      activeIndex1.value = ind;
-      getMonitor();
-      loading.value = false;
-    }, 1000);
-  }
+    }
+    getMonitor(true);
+    loading.value = false;
+  }, 1000);
 }
-//加载组件
+
 function loadZj() {
-  if (!activeIndex.value && listData.fiber.length != 0 && listData.bundletube.length != 0) {
+  if (!activeIndex.value && listData.fiber.length !== 0 && listData.bundletube.length !== 0) {
     currentLoad.value = 'fireWork';
-  } else if (!activeIndex.value && listData.bundletube.length != 0) {
+  } else if (!activeIndex.value && listData.bundletube.length !== 0) {
     currentLoad.value = 'closeWall';
-  } else if (activeIndex.value && activeIndex.value != 2) {
+  } else if (activeIndex.value && activeIndex.value !== 2) {
     currentLoad.value = 'mainWell';
   } else {
     currentLoad.value = '';
   }
 }
-//清空数据
+
 function getClearList() {
   listData.common = {};
   listData.bundletube.length = 0;
@@ -252,14 +209,11 @@ function getClearList() {
 }
 
 onMounted(() => {
-  getMenuList();
-  getMonitor();
+  getMonitor(true);
 });
+
 onUnmounted(() => {
-  if (timer) {
-    clearTimeout(timer);
-    timer = undefined;
-  }
+  clearPollTimer();
 });
 </script>
 

+ 376 - 502
src/views/vent/monitorManager/alarmMonitor/warn/gasWarn.vue

@@ -1,20 +1,34 @@
 <template>
   <customHeader :options="options" @change="getSelectRow" :optionValue="optionValue"> 瓦斯监测预警 </customHeader>
   <div class="gasWarn">
-    <a-button v-if="!hasPermission('gasWarn:return')" preIcon="ant-design:rollback-outlined" type="text" size="small"
-      style="position: absolute; left: 15px; top: 15px; color: #fff" @click="getBack">
+    <a-button
+      v-if="!hasPermission('gasWarn:return')"
+      preIcon="ant-design:rollback-outlined"
+      type="text"
+      size="small"
+      style="position: absolute; left: 15px; top: 15px; color: #fff"
+      @click="getBack"
+    >
       返回
     </a-button>
     <div class="alarm-menu">
       <div class="type-btn">
-        <div :class="activeIndex == index ? 'btn1' : 'btn'" v-for="(item, index) in typeMenuListGas" :key="index"
-          @click="btnClick(index)">
+        <div
+          :class="activeIndex == index ? 'btn1' : 'btn'"
+          v-for="(item, index) in typeMenuListGas"
+          :key="index"
+          @click="btnClick(index)"
+        >
           {{ item.name }}
         </div>
       </div>
       <div class="card-btn">
-        <div :class="activeIndex1 == ind ? 'btn1' : 'btn'" v-for="(item, ind) in menuList" :key="ind"
-          @click="cardClick(ind, item)">
+        <div
+          :class="activeIndex1 == ind ? 'btn1' : 'btn'"
+          v-for="(item, ind) in menuList"
+          :key="ind"
+          @click="cardClick(ind, item)"
+        >
           <div class="text">{{ item.name }}</div>
           <div class="warn">{{ item.warn }}</div>
         </div>
@@ -22,7 +36,6 @@
     </div>
     <div class="gas-content">
       <div style="width: 100%; height: 100%" v-if="isShow == 'yjjc'">
-
         <div class="top-area" v-if="isShowTop">
           <div class="title-t">
             <div class="text-t">瓦斯抽采泵信息</div>
@@ -31,7 +44,6 @@
             <gasCcb :gasData="gasData" />
           </div>
         </div>
-
         <div :class="isShowTop ? 'bot-area' : 'bot-area1'">
           <MeasurePoint title="安全监控测点信息" :timeout="1000" :cards="cardListWs" :charts="chartListWs" />
         </div>
@@ -43,129 +55,149 @@
         <gasParamter />
       </div>
       <div style="width: 100%; height: 100%" v-else-if="isShow == 'gzzd'">
-        <faultDiagnose :timeData="gzTime" :topData="topData" :xAxisPropType="xAxisPropType"
-          :hisEchartData="hisEchartData" :echartData="echartData" @getSearchHis="getlistdaysData1" />
+        <faultDiagnose
+          :timeData="gzTime"
+          :topData="topData"
+          :xAxisPropType="xAxisPropType"
+          :hisEchartData="hisEchartData"
+          :echartData="echartData"
+          @getSearchHis="getlistdaysData1"
+        />
       </div>
     </div>
   </div>
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, onMounted, onUnmounted, computed } from 'vue';
-import { sysTypeWarnList, sysWarn, getDevice, listdays, bjlist, getHistoryData } from '../common.api';
-import { useSystemSelect } from '/@/hooks/vent/useSystemSelect';
-import { useRouter } from 'vue-router';
-import CustomHeader from '/@/components/vent/customHeader.vue';
-import warnTargetGas from '../common/warnTargetGas.vue';
-import PipeWarn from '../common/PipeWarn.vue';
-import gasParamter from '../common/gasParamter.vue';
-import faultDiagnose from '../common/faultDiagnose.vue';
-import { getMonitorComponent, getMonitorFlag } from '../common.data';
-import { usePermission } from '/@/hooks/web/usePermission';
-import MeasurePoint from '../common/measurePoint.vue';
-import gasCcb from '../common/gasCcb.vue';
-import dayjs from 'dayjs';
-
-let typeMenuListGas = getMonitorComponent();
-let isflag = getMonitorFlag();
-const { hasPermission } = usePermission();
-const { options, optionValue, getSelectRow, getSysDataSource } = useSystemSelect('sys_surface_caimei'); // 参数为场景类型(设备类型管理中可以查询到)
-//当前左侧激活菜单的索引
-let activeIndex1 = ref(0);
-//左侧数据列表
-let menuList = reactive<any[]>([]);
-//瓦斯顶部区域
-let gasData = reactive({});
-//瓦斯监控列表数据
-let cardListWs = reactive<any[]>([]);
-const chartListWs = reactive<any[]>([]);
-let router = useRouter();
-//监测/指标激活索引
-let activeIndex = ref(0);
-let isShow = ref('yjjc');
-//故障诊断开始时间
-let gzTime = ref('');
-//故障诊断顶部区域数据
-let topData = ref<any[]>([]);
-//根据诊断类型判断调用哪个历史数据接口
-let zdType = ref('');
-let historySearch = reactive({
-  ttime_begin: '',
-  ttime_end: '',
-});
-//实时历史图表
-let xAxisPropType = ref('');
-let hisEchartData = ref<any[]>([]);
-//报警历史图表
-let echartData = reactive<any>({
-  maxData: {
-    lengedData: '',
-    data: [],
-  },
-  minData: {
-    lengedData: '',
-    data: [],
-  },
-  xData: [],
-});
-let isShowTop = ref(true)
-
-// https获取监测数据
-let timer: null | NodeJS.Timeout = null;
-function getMonitor(flag?) {
-  timer = setTimeout(
-    async () => {
-      await getMenuList();
-      if (timer) {
-        timer = null;
-      }
-      getMonitor(false);
+  import { ref, reactive, onMounted, onUnmounted } from 'vue';
+  import { sysTypeWarnList, getDevice, listdays, bjlist, getHistoryData } from '../common.api';
+  import { useSystemSelect } from '/@/hooks/vent/useSystemSelect';
+  import { useRouter } from 'vue-router';
+  import CustomHeader from '/@/components/vent/customHeader.vue';
+  import warnTargetGas from '../common/warnTargetGas.vue';
+  import gasParamter from '../common/gasParamter.vue';
+  import faultDiagnose from '../common/faultDiagnose.vue';
+  import { getMonitorComponent, getMonitorFlag } from '../common.data';
+  import { usePermission } from '/@/hooks/web/usePermission';
+  import MeasurePoint from '../common/measurePoint.vue';
+  import gasCcb from '../common/gasCcb.vue';
+  import dayjs from 'dayjs';
+
+  const typeMenuListGas = getMonitorComponent();
+  const isflag = getMonitorFlag();
+  const { hasPermission } = usePermission();
+  const { options, optionValue, getSelectRow } = useSystemSelect('sys_surface_caimei');
+  const activeIndex1 = ref(0);
+  const menuList = reactive<any[]>([]);
+  const gasData = reactive<any>({});
+  const cardListWs = reactive<any[]>([]);
+  const chartListWs = reactive<any[]>([]);
+  const router = useRouter();
+  const activeIndex = ref(0);
+  const isShow = ref('yjjc');
+  const gzTime = ref('');
+  const topData = ref<any[]>([]);
+  const zdType = ref('');
+  const historySearch = reactive({
+    ttime_begin: '',
+    ttime_end: '',
+  });
+  const xAxisPropType = ref('');
+  const hisEchartData = ref<any[]>([]);
+  const echartData = reactive<any>({
+    maxData: {
+      lengedData: '',
+      data: [],
     },
-    flag ? 0 : 1000
-  );
-}
-
-// https获取监测数据
-let timer1: null | NodeJS.Timeout = null;
-function getMonitor1(flag?) {
-  timer1 = setTimeout(
-    async () => {
-      await getBjlist();
-      if (timer1) {
-        timer1 = null;
-      }
-      getMonitor1(false);
+    minData: {
+      lengedData: '',
+      data: [],
     },
-    flag ? 0 : 1000
-  );
-}
-
-//返回首页
-function getBack() {
-  router.push('/monitorChannel/monitor-alarm-home');
-}
-
-//获取右侧详情数据列表
-function getDetailList(param) {
-  // listData.common = res;
-  cardListWs.length = 0;
-  chartListWs.length = 0;
-  if (JSON.stringify(param) != '{}') {
+    xData: [],
+  });
+  const isShowTop = ref(true);
+
+  let timer: null | NodeJS.Timeout = null;
+  let timer1: null | NodeJS.Timeout = null;
+
+  function clearPollTimer() {
+    if (timer) {
+      clearTimeout(timer);
+      timer = null;
+    }
+  }
+
+  function clearAlarmTimer() {
+    if (timer1) {
+      clearTimeout(timer1);
+      timer1 = null;
+    }
+  }
+
+  function clearAllTimers() {
+    clearPollTimer();
+    clearAlarmTimer();
+  }
+
+  function getMonitor(flag?) {
+    clearPollTimer();
+    timer = setTimeout(
+      async () => {
+        await getMenuList();
+        timer = null;
+        getMonitor(false);
+      },
+      flag ? 0 : 1000
+    );
+  }
+
+  function getMonitor1(flag?) {
+    clearAlarmTimer();
+    timer1 = setTimeout(
+      async () => {
+        await getBjlist();
+        timer1 = null;
+        getMonitor1(false);
+      },
+      flag ? 0 : 1000
+    );
+  }
+
+  function getBack() {
+    router.push('/monitorChannel/monitor-alarm-home');
+  }
+
+  function formatWarnLevel(level) {
+    const map = {
+      '101': '低风险',
+      '102': '一般风险',
+      '103': '较大风险',
+      '104': '重大风险',
+      '201': '报警',
+      '10000': '数据超限',
+      '1001': '网络中断',
+    };
+    return map[level] || '正常';
+  }
+
+  function getDetailList(param) {
+    cardListWs.length = 0;
+    chartListWs.length = 0;
+    if (!param || JSON.stringify(param) === '{}' || !param.gas) return;
+
     param.gas.forEach((el) => {
-      el.strinstallpos = el.strinstallpos.indexOf('&') == -1 ? el.strinstallpos : el.strinstallpos.substring(0, el.strinstallpos.indexOf('&'));
+      el.strinstallpos =
+        el.strinstallpos.indexOf('&') == -1 ? el.strinstallpos : el.strinstallpos.substring(0, el.strinstallpos.indexOf('&'));
       cardListWs.push({
         label: '甲烷',
         value: el.readData.gasC + '%' || '--',
-        // value: 0,
         listR: [
           { id: 0, label: '测点类型', dw: '', value: '瓦斯' },
           { id: 1, label: '测点位置', dw: '', value: el.strinstallpos || '--' },
-          // { id: 2, label: '数据时间', value: el.readData.datetime || '--' },
           { id: 2, label: '数据时间', dw: '', value: el.readTime || '--' },
           { id: 3, label: '测点状态', dw: '', value: el.warnFlag },
         ],
       });
-      // 初始化预测曲线配置,分别为x轴时间、平均、最大、最小、实时
       const avgParam = el.avgParam || {
         avg_gas_value: 0,
         max_gas_value: 0,
@@ -177,14 +209,12 @@ function getDetailList(param) {
         data: [avgParam.avg_gas_value, avgParam.max_gas_value, avgParam.min_gas_value, el.readData.gasC],
       });
     });
-
   }
-}
 
-//获取左侧菜单列表
-async function getMenuList() {
-  let res = await sysTypeWarnList({ type: 'gas' });
-  if (res.length != 0) {
+  async function getMenuList() {
+    const res = await sysTypeWarnList({ type: 'gas' });
+    if (!res || res.length === 0) return;
+
     menuList.length = 0;
     res.forEach((el) => {
       menuList.push({
@@ -195,16 +225,18 @@ async function getMenuList() {
         detail: el.detail,
       });
     });
-    gasData = Object.assign({}, menuList[activeIndex1.value].detail);
-    isShowTop.value = gasData.pump.length != 0 ? true : false
-    getDetailList(menuList[activeIndex1.value].detail);
+
+    const detail = menuList[activeIndex1.value]?.detail || {};
+    Object.keys(gasData).forEach((key) => delete gasData[key]);
+    Object.assign(gasData, detail);
+    isShowTop.value = !!(gasData.pump && gasData.pump.length);
+    getDetailList(detail);
   }
-}
-//寸草塔二矿左侧菜单
-async function getBjlist() {
-  let res = await bjlist({ devicetype: 'gasmonitor*', pageNo: 1, pageSize: 100, isok: '0' });
-  console.log(res, '寸草塔二矿左侧菜单');
-  if (res && res.records.length != 0) {
+
+  async function getBjlist() {
+    const res = await bjlist({ devicetype: 'gasmonitor*', pageNo: 1, pageSize: 100, isok: '0' });
+    if (!res?.records?.length) return;
+
     menuList.length = 0;
     res.records.forEach((el) => {
       menuList.push({
@@ -212,32 +244,31 @@ async function getBjlist() {
         warn: '故障',
         deviceID: el.deviceid,
         time: el.createTime,
-        // strtype: el.strtype,
-        // detail: el.detail
       });
     });
+
     gzTime.value = menuList[activeIndex1.value].time;
-    let index = gzTime.value.indexOf(' ');
-    let specificTime = dayjs(`${gzTime.value.substring(0, index)}T${gzTime.value.substring(index + 1)}`);
+    const index = gzTime.value.indexOf(' ');
+    const specificTime = dayjs(`${gzTime.value.substring(0, index)}T${gzTime.value.substring(index + 1)}`);
     if (!historySearch.ttime_begin && !historySearch.ttime_end) {
       historySearch.ttime_begin = specificTime.subtract(30, 'minute').format('YYYY-MM-DD HH:mm:ss');
       historySearch.ttime_end = specificTime.add(30, 'minute').format('YYYY-MM-DD HH:mm:ss');
     }
-    //获取实时数据-报警历史
-    getDeviceList(menuList[activeIndex1.value].deviceID);
-    //获取历史数据
-    getlistdaysData(menuList[activeIndex1.value].deviceID, historySearch);
+
+    const deviceID = menuList[activeIndex1.value].deviceID;
+    getDeviceList(deviceID);
+    getlistdaysData(deviceID, historySearch);
   }
-}
 
-//获取实时数据-寸草塔二矿-报警历史
-async function getDeviceList(param) {
-  let res = await getDevice({ ids: param, devicetype: 'gasmonitor' });
-  if (res && res.msgTxt.length != 0) {
+  async function getDeviceList(param) {
+    const res = await getDevice({ ids: param, devicetype: 'gasmonitor' });
+    if (!res?.msgTxt?.length) return;
+
     echartData.maxData.data.length = 0;
     echartData.minData.data.length = 0;
     echartData.xData.length = 0;
-    let data = res.msgTxt[0].datalist[0];
+
+    const data = res.msgTxt[0].datalist[0];
     topData.value = [
       {
         id: 0,
@@ -265,22 +296,7 @@ async function getDeviceList(param) {
         label: '报警状态',
         imgSrc: true,
         icon: 'alarm-warning',
-        value:
-          data.warnLevel == '101'
-            ? '低风险'
-            : data.warnLevel == '102'
-              ? '一般风险'
-              : data.warnLevel == '103'
-                ? '较大风险'
-                : data.warnLevel == '104'
-                  ? '重大风险'
-                  : data.warnLevel == '201'
-                    ? '报警'
-                    : data.warnLevel == '10000'
-                      ? '数据超限'
-                      : data.warnLevel == '1001'
-                        ? '网络中断'
-                        : '正常',
+        value: formatWarnLevel(data.warnLevel),
       },
       {
         id: 4,
@@ -290,414 +306,272 @@ async function getDeviceList(param) {
         value: data.netStatus == '0' ? '断开' : '连接',
       },
     ];
+
     zdType.value = data.stationtype || '';
-    let list = JSON.parse(data.readData.gasGlFaultDia);
+    const list = JSON.parse(data.readData.gasGlFaultDia);
     echartData.maxData.data = [list.y1 || 0, list.y2 || 0];
     echartData.minData.data = [list.y3 || 0, list.y4 || 0];
-    echartData.xData = [...new Set([list.x1, list.x2, list.x3, list.x4])].sort((a, b) => a - b);
+    echartData.xData = [...new Set([list.x1, list.x2, list.x3, list.x4])].sort((a: any, b: any) => a - b);
   }
-}
-//获取历史数据-寸草塔二矿
-async function getlistdaysData(Ids, param) {
-  if (zdType.value != 'redis') {
-    let res = await listdays({ strtype: 'gasmonitor_normal', gdeviceid: Ids, ...param });
-    console.log(res, '获取历史数据-寸草塔二矿');
-    xAxisPropType.value = 'ttime';
-    let data = res.datalist.records;
-    if (data.length != 0) {
+
+  async function getlistdaysData(Ids, param) {
+    if (zdType.value != 'redis') {
+      const res = await listdays({ strtype: 'gasmonitor_normal', gdeviceid: Ids, ...param });
+      xAxisPropType.value = 'ttime';
+      const data = res?.datalist?.records || [];
       data.forEach((el) => {
         Object.assign(el, el.readData);
       });
-    }
-    hisEchartData.value = data;
-    console.log(hisEchartData.value, '  hisEchartData.value');
-  } else {
-    let res = await getHistoryData({ pageNum: 1, pageSize: 100, deviceId: Ids, isEmployee: true, ...param });
-    console.log(res, '获取历史数据-寸草塔二矿');
-    xAxisPropType.value = 'time';
-    hisEchartData.value = res['records'];
-  }
-}
-async function getlistdaysData1(param) {
-  historySearch.ttime_begin = param.ttime_begin;
-  historySearch.ttime_end = param.ttime_end;
-  let res = await listdays({ strtype: 'gasmonitor_normal', gdeviceid: menuList[activeIndex1.value].deviceID, ...historySearch });
-  console.log(res, '获取历史数据-寸草塔二矿');
-
-  if (zdType.value != 'redis') {
-    let res = await listdays({ strtype: 'gasmonitor_normal', gdeviceid: menuList[activeIndex1.value].deviceID, ...historySearch });
-    console.log(res, '获取历史数据-寸草塔二矿');
-    xAxisPropType.value = 'ttime';
-    let data = res.datalist.records;
-    if (data.length != 0) {
-      data.forEach((el) => {
-        Object.assign(el, el.readData);
+      hisEchartData.value = data;
+    } else {
+      const res = await getHistoryData({
+        pageNum: 1,
+        pageSize: 100,
+        deviceId: Ids,
+        isEmployee: true,
+        ...param,
       });
+      xAxisPropType.value = 'time';
+      hisEchartData.value = res?.records || [];
     }
-    hisEchartData.value = data;
-  } else {
-    let res = await getHistoryData({ pageNum: 1, pageSize: 100, deviceId: menuList[activeIndex1.value].deviceID, isEmployee: true, ...param });
-    console.log(res, '获取历史数据-寸草塔二矿');
-    xAxisPropType.value = 'time';
-    hisEchartData.value = res['records'];
   }
-}
-
-//监测/预警指标选项切换
-function btnClick(ind) {
-  activeIndex.value = ind;
-  clearTimeout(timer);
-  clearTimeout(timer1)
-  switch (ind) {
-    case 0:
-      activeIndex1.value = 0;
+
+  async function getlistdaysData1(param) {
+    historySearch.ttime_begin = param.ttime_begin;
+    historySearch.ttime_end = param.ttime_end;
+    const deviceID = menuList[activeIndex1.value].deviceID;
+    await getlistdaysData(deviceID, { ...historySearch, ...param });
+  }
+
+  function btnClick(ind) {
+    activeIndex.value = ind;
+    clearAllTimers();
+    activeIndex1.value = 0;
+
+    if (ind === 0) {
       isShow.value = 'yjjc';
       getMonitor(true);
-      break;
-    case 1:
+    } else if (ind === 1) {
       if (isflag == '2') {
-        activeIndex1.value = 0;
         isShow.value = 'yjzb';
       } else if (isflag == '1') {
-        activeIndex1.value = 0;
         isShow.value = 'gzzd';
         getMonitor1(true);
       } else {
-        activeIndex1.value = 0;
         isShow.value = '';
       }
-      break;
-    case 2:
-      activeIndex1.value = 0;
+    } else if (ind === 2) {
       isShow.value = 'wscs';
-      break;
+    }
   }
-}
-
-//菜单选项切换
-function cardClick(ind, item) {
-  clearTimeout(timer);
-  clearTimeout(timer1)
-  activeIndex1.value = ind;
-  gzTime.value = item.time;
-  chartListWs.length = 0;
-  if (isflag != '1') {
-    getMonitor(true);
-  } else {
-    getMonitor1(true);
+
+  function cardClick(ind, item) {
+    clearAllTimers();
+    activeIndex1.value = ind;
+    gzTime.value = item.time;
+    chartListWs.length = 0;
+    if (isflag != '1') {
+      getMonitor(true);
+    } else {
+      getMonitor1(true);
+    }
   }
 
-}
+  onMounted(() => {
+    getMonitor(true);
+  });
 
-onMounted(() => {
-  getMenuList();
-  getMonitor(true);
-});
-onUnmounted(() => {
-  if (timer) {
-    clearTimeout(timer);
-    timer = undefined;
-  }
-  if (timer1) {
-    clearTimeout(timer1);
-    timer1 = undefined;
-  }
-});
+  onUnmounted(() => {
+    clearAllTimers();
+  });
 </script>
 
 <style lang="less" scoped>
-@import '/@/design/theme.less';
+  @import '/@/design/theme.less';
+
+  @{theme-deepblue} {
+    .gasWarn {
+      --image-no-choice: url('/@/assets/images/themify/deepblue/fire/no-choice.png');
+      --image-choice: url('/@/assets/images/themify/deepblue/fire/choice.png');
+      --image-border: url('/@/assets/images/themify/deepblue/fire/border.png');
+      --image-bj1: url('/@/assets/images/themify/deepblue/fire/bj1.png');
+    }
+  }
 
-@{theme-deepblue} {
   .gasWarn {
-    --image-no-choice: url('/@/assets/images/themify/deepblue/fire/no-choice.png');
-    --image-choice: url('/@/assets/images/themify/deepblue/fire/choice.png');
-    --image-border: url('/@/assets/images/themify/deepblue/fire/border.png');
-    --image-bj1: url('/@/assets/images/themify/deepblue/fire/bj1.png');
-    --image-top-area: url('/@/assets/images/themify/deepblue/fire/top-area.png');
-  }
-}
-
-.gasWarn {
-  --image-no-choice: url('/@/assets/images/fire/no-choice.png');
-  --image-choice: url('/@/assets/images/fire/choice.png');
-  --image-border: url('/@/assets/images/fire/border.png');
-  --image-bj1: url('/@/assets/images/fire/bj1.png');
-  --image-top-area: url('/@/assets/images/fire/top-area.png');
-  width: 100%;
-  height: 100%;
-  padding: 80px 10px 15px 10px;
-  box-sizing: border-box;
-  display: flex;
-  justify-content: space-between;
-
-  .alarm-menu {
+    --image-no-choice: url('/@/assets/images/fire/no-choice.png');
+    --image-choice: url('/@/assets/images/fire/choice.png');
+    --image-border: url('/@/assets/images/fire/border.png');
+    --image-bj1: url('/@/assets/images/fire/bj1.png');
+    width: 100%;
     height: 100%;
-    width: 15%;
-
-    .type-btn {
-      width: 100%;
-      height: 28px;
-      line-height: 28px;
-      border: 1px solid var(--vent-warn-tab-border);
-      margin-bottom: 20px;
-      border-radius: 5px;
-      box-sizing: border-box;
-      display: flex;
-      justify-content: space-between;
-
-      .btn {
-        width: 33.33%;
-        height: 100%;
-        font-size: 14px;
-        text-align: center;
-        color: #fff;
-        cursor: pointer;
-      }
+    padding: 80px 10px 15px 10px;
+    box-sizing: border-box;
+    display: flex;
+    justify-content: space-between;
 
-      .btn1 {
-        width: 33.33%;
-        height: 100%;
-        font-size: 14px;
-        color: #fff;
-        text-align: center;
-        border-radius: 2px;
-        background: var(--vent-warn-tab-bg-actived);
-        cursor: pointer;
-      }
-    }
+    .alarm-menu {
+      height: 100%;
+      width: 15%;
 
-    .card-btn {
-      width: 100%;
-      height: calc(100% - 48px);
-      overflow-y: auto;
-
-      .btn {
-        position: relative;
-        width: 81%;
-        height: 14%;
-        margin-bottom: 10%;
-        font-family: 'douyuFont';
-        background: var(--image-no-choice) no-repeat;
-        background-size: 100% 100%;
-        cursor: pointer;
-
-        .text {
-          width: 80%;
-          position: absolute;
-          left: 50%;
-          top: 28px;
-          font-size: 16px;
-          color: var(--vent-table-action-link);
-          text-align: center;
-          transform: translate(-50%, 0);
-        }
+      .type-btn {
+        width: 100%;
+        height: 28px;
+        line-height: 28px;
+        border: 1px solid var(--vent-warn-tab-border);
+        margin-bottom: 20px;
+        border-radius: 5px;
+        box-sizing: border-box;
+        display: flex;
+        justify-content: space-between;
 
-        .warn {
-          width: 100%;
-          position: absolute;
-          left: 50%;
-          bottom: 14px;
+        .btn {
+          width: 33.33%;
+          height: 100%;
           font-size: 14px;
-          color: #fff;
           text-align: center;
-          transform: translate(-50%, 0);
-        }
-      }
-
-      .btn1 {
-        position: relative;
-        width: 100%;
-        height: 14%;
-        margin-bottom: 10%;
-        font-family: 'douyuFont';
-        background: var(--image-choice) no-repeat;
-        background-size: 100% 100%;
-        cursor: pointer;
-
-        .text {
-          width: 80%;
-          position: absolute;
-          left: 50%;
-          top: 28px;
-          font-size: 16px;
-          color: var(--vent-table-action-link);
-          text-align: center;
-          transform: translate(-62%, 0);
+          color: #fff;
+          cursor: pointer;
         }
 
-        .warn {
-          width: 100%;
-          position: absolute;
-          left: 50%;
-          bottom: 14px;
+        .btn1 {
+          width: 33.33%;
+          height: 100%;
           font-size: 14px;
           color: #fff;
           text-align: center;
-          transform: translate(-60%, 0);
+          border-radius: 2px;
+          background: var(--vent-warn-tab-bg-actived);
+          cursor: pointer;
         }
       }
-    }
-  }
 
-  .gas-content {
-    position: relative;
-    width: calc(85% - 10px);
-    height: 100%;
-    margin-left: 10px;
-    padding: 15px;
-    background: var(--image-border) no-repeat;
-    background-size: 100% 100%;
-    box-sizing: border-box;
+      .card-btn {
+        width: 100%;
+        height: calc(100% - 48px);
+        overflow-y: auto;
 
-    .top-area {
-      height: 356px;
-      margin-bottom: 10px;
-      padding: 10px;
-      background: var(--image-bj1) no-repeat center;
-      background-size: 100% 100%;
-      box-sizing: border-box;
+        .btn {
+          position: relative;
+          width: 81%;
+          height: 14%;
+          margin-bottom: 10%;
+          font-family: 'douyuFont';
+          background: var(--image-no-choice) no-repeat;
+          background-size: 100% 100%;
+          cursor: pointer;
+
+          .text {
+            width: 80%;
+            position: absolute;
+            left: 50%;
+            top: 28px;
+            font-size: 16px;
+            color: var(--vent-table-action-link);
+            text-align: center;
+            transform: translate(-50%, 0);
+          }
 
-      .title-t {
-        height: 30px;
-        margin-bottom: 10px;
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
+          .warn {
+            width: 100%;
+            position: absolute;
+            left: 50%;
+            bottom: 14px;
+            font-size: 14px;
+            color: #fff;
+            text-align: center;
+            transform: translate(-50%, 0);
+          }
+        }
 
-        .text-t {
+        .btn1 {
+          position: relative;
+          width: 100%;
+          height: 14%;
+          margin-bottom: 10%;
           font-family: 'douyuFont';
-          font-size: 14px;
-          color: #fff;
-        }
-      }
+          background: var(--image-choice) no-repeat;
+          background-size: 100% 100%;
+          cursor: pointer;
+
+          .text {
+            width: 80%;
+            position: absolute;
+            left: 50%;
+            top: 28px;
+            font-size: 16px;
+            color: var(--vent-table-action-link);
+            text-align: center;
+            transform: translate(-62%, 0);
+          }
 
-      .content-t {
-        width: 100%;
-        height: 276px;
+          .warn {
+            width: 100%;
+            position: absolute;
+            left: 50%;
+            bottom: 14px;
+            font-size: 14px;
+            color: #fff;
+            text-align: center;
+            transform: translate(-60%, 0);
+          }
+        }
       }
     }
 
-    .bot-area {
-      height: calc(100% - 356px);
-      padding: 10px;
-      background: var(--image-bj1) no-repeat center;
-      background-size: 100% 100%;
-      box-sizing: border-box;
-    }
-
-    .bot-area1 {
+    .gas-content {
+      position: relative;
+      width: calc(85% - 10px);
       height: 100%;
-      padding: 10px 15px 0px 15px;
-      background: var(--image-bj1) no-repeat center;
+      margin-left: 10px;
+      padding: 15px;
+      background: var(--image-border) no-repeat;
       background-size: 100% 100%;
       box-sizing: border-box;
 
-      .title-b {
-        height: 30px;
+      .top-area {
+        height: 356px;
         margin-bottom: 10px;
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
+        padding: 10px;
+        background: var(--image-bj1) no-repeat center;
+        background-size: 100% 100%;
+        box-sizing: border-box;
 
-        .text-b {
-          font-family: 'douyuFont';
-          font-size: 14px;
-          color: #fff;
+        .title-t {
+          height: 30px;
+          margin-bottom: 10px;
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+
+          .text-t {
+            font-family: 'douyuFont';
+            font-size: 14px;
+            color: #fff;
+          }
+        }
+
+        .content-t {
+          width: 100%;
+          height: 276px;
         }
       }
 
-      .content-b {
-        width: 100%;
-        height: calc(100% - 40px);
-        overflow-y: auto;
+      .bot-area {
+        height: calc(100% - 356px);
+        padding: 10px;
+        background: var(--image-bj1) no-repeat center;
+        background-size: 100% 100%;
+        box-sizing: border-box;
+      }
 
-        .content-b-item {
-          display: flex;
-          justify-content: flex-start;
-          align-items: flex-start;
-          flex-wrap: wrap;
-
-          .card-b {
-            position: relative;
-            width: 30%;
-            height: 128px;
-            margin: 0px 15px 15px 15px;
-            background: var(--image-bot-area) no-repeat center;
-            background-size: 100% 100%;
-
-            .item-l {
-              position: absolute;
-              left: 32px;
-              top: 50%;
-              transform: translate(0, -50%);
-              width: 89px;
-              height: 98px;
-              background: var(--image-bot-area1) no-repeat center;
-
-              .label-l {
-                position: absolute;
-                left: 50%;
-                top: 7px;
-                font-size: 14px;
-                color: #fff;
-                transform: translate(-50%, 0);
-              }
-
-              .value-l {
-                position: absolute;
-                left: 50%;
-                top: 50px;
-                transform: translate(-50%, 0);
-                font-family: 'douyuFont';
-                font-size: 14px;
-                color: var(--vent-table-action-link);
-              }
-            }
-
-            .item-r {
-              position: absolute;
-              left: 132px;
-              top: 50%;
-              transform: translate(0, -50%);
-              height: 128px;
-              padding: 5px 0px;
-              display: flex;
-              flex-direction: column;
-              justify-content: space-around;
-              box-sizing: border-box;
-
-              .content-r {
-                display: flex;
-
-                span {
-                  font-size: 14px;
-                  color: #fff;
-
-                  &:first-child {
-                    display: inline-block;
-                    width: 68px;
-                  }
-
-                  &:last-child {
-                    display: inline-block;
-                    width: calc(100% - 68px);
-                  }
-                }
-
-                .status-f {
-                  color: #ff0000;
-                }
-
-                .status-l {
-                  color: var(--vent-table-action-link);
-                }
-              }
-            }
-          }
-        }
+      .bot-area1 {
+        height: 100%;
+        padding: 10px 15px 0;
+        background: var(--image-bj1) no-repeat center;
+        background-size: 100% 100%;
+        box-sizing: border-box;
       }
     }
   }
-}
 </style>

+ 174 - 210
src/views/vent/monitorManager/alarmMonitor/warn/ventilateWarn.vue

@@ -57,40 +57,34 @@
 </template>
 
 <script setup lang="ts">
-  import { ref, reactive, onMounted, onUnmounted, computed } from 'vue';
+  import { ref, reactive, onMounted, onUnmounted } from 'vue';
   import { useSystemSelect } from '/@/hooks/vent/useSystemSelect';
   import { usePermission } from '/@/hooks/web/usePermission';
   import { useGlobSetting } from '/@/hooks/setting';
   import { useRouter } from 'vue-router';
-  import { sysTypeWarnList, sysWarn, getDevice } from '../common.api';
+  import { sysTypeWarnList, getDevice } from '../common.api';
   import { ventilateTopList, typeMenuListTf, getMaxY, getMinY } from '../common.data';
   import CustomHeader from '/@/components/vent/customHeader.vue';
   import MeasurePoint from '../common/measurePoint.vue';
   import { realTimeNetCal, modalParam } from '../alarm.api';
   import TopArea from '../common/top-area.vue';
 
-  //巷道阻力分析数据
-  let hdData = reactive({
+  const hdData = reactive({
     maxLevel: '',
-    address: '',
   });
-  //通风选项激活索引
-  let activeIndex = ref(0);
-  let monitor = ref(true);
-  let toggleData = reactive<any>({});
+  const activeIndex = ref(0);
+  const monitor = ref(true);
+  let toggleData: any = {};
   const { hasPermission } = usePermission();
-  const { options, optionValue, getSelectRow, getSysDataSource } = useSystemSelect('sys_surface_caimei'); // 参数为场景类型(设备类型管理中可以查询到)
-  let router = useRouter();
-  //左侧数据列表
-  let menuList = reactive<any[]>([]);
-  const ventTunDataSource = ref([]);
-  //当前左侧激活菜单的索引
-  let activeIndex1 = ref(0);
-  let maxY = ref<any>(0);
-  let minY = ref<any>(0);
+  const { options, optionValue, getSelectRow } = useSystemSelect('sys_surface_caimei');
+  const router = useRouter();
+  const menuList = reactive<any[]>([]);
+  const ventTunDataSource = ref<any[]>([]);
+  const activeIndex1 = ref(0);
+  const maxY = ref<any>(0);
+  const minY = ref<any>(0);
   const loading = ref(false);
 
-  //通风图表数据
   const echartDataFc1 = reactive<any>({
     maxData: {
       lengedData: '进风量',
@@ -106,244 +100,227 @@
     },
     xData: [],
   });
-  let cardListTf = ref<any[]>([]);
+  const cardListTf = ref<any[]>([]);
   const chartListTf = ref<any[]>([]);
-  let showToggle = ref('report');
+  const showToggle = ref('report');
 
-  // https获取监测数据
   let timer: null | NodeJS.Timeout = null;
+  let timer1: null | NodeJS.Timeout = null;
+
+  function clearPollTimer() {
+    if (timer) {
+      clearTimeout(timer);
+      timer = null;
+    }
+  }
+
+  function clearNetTimer() {
+    if (timer1) {
+      clearTimeout(timer1);
+      timer1 = null;
+    }
+  }
+
+  function clearChartData() {
+    echartDataFc1.maxData.data.length = 0;
+    echartDataFc1.minData.data.length = 0;
+    echartDataFc1.aveValue.data.length = 0;
+    echartDataFc1.xData.length = 0;
+  }
+
+  function fillHistoryChart(list: any[], useReport: boolean) {
+    if (!list || !list.length) return;
+    const needValue = ventilateTopList[2].value;
+    const hasNeed = needValue && needValue != '--';
+    list.forEach((v) => {
+      if (useReport) {
+        echartDataFc1.maxData.data.push(parseFloat(v.faceIntM3));
+        echartDataFc1.minData.data.push(parseFloat(v.faceRetM3));
+        echartDataFc1.aveValue.data.push(0);
+      } else {
+        echartDataFc1.maxData.data.push(parseFloat(v.jin));
+        echartDataFc1.minData.data.push(parseFloat(v.hui));
+        echartDataFc1.aveValue.data.push(hasNeed ? needValue : 0);
+      }
+      echartDataFc1.xData.push(v.time);
+    });
+  }
+
+  function updateYAxisRange() {
+    const echartD = [echartDataFc1.maxData.data, echartDataFc1.minData.data];
+    maxY.value = getMaxY(echartD);
+    minY.value = getMinY(echartD);
+  }
+
   function getMonitor(flag?) {
+    clearPollTimer();
     timer = setTimeout(
       async () => {
-        //获取左侧菜单数据
         await getMenuList();
         await getWindDeviceList();
+        timer = null;
         getMonitor(false);
       },
       flag ? 0 : 1500
     );
   }
-  //获取巷道阻力分析数据
-  let timer1: null | NodeJS.Timeout = null;
+
   function getMonitor1(flag?) {
+    clearNetTimer();
     timer1 = setTimeout(
       async () => {
         await getRealTimeNetData();
+        timer1 = null;
         getMonitor1(false);
       },
       flag ? 0 : 30000
     );
   }
 
-  //返回首页
   function getBack() {
     router.push('/monitorChannel/monitor-alarm-home');
   }
-  //点击切换实时\报表数据
-  let handlerToggle = () => {
+
+  function handlerToggle() {
     monitor.value = !monitor.value;
-    echartDataFc1.maxData.data.length = 0;
-    echartDataFc1.minData.data.length = 0;
-    echartDataFc1.aveValue.data.length = 0;
-    echartDataFc1.xData.length = 0;
+    clearChartData();
     getData();
-  };
-  //实时报表数据
+  }
+
   function getData() {
     ventilateTopList[0].value = monitor.value ? toggleData.faceIntM3 : toggleData.jin;
     ventilateTopList[1].value = monitor.value ? toggleData.faceRetM3 : toggleData.hui;
     if (monitor.value) {
-      toggleData.history_report.forEach((v) => {
-        echartDataFc1.maxData.data.push(parseFloat(v.faceIntM3));
-        echartDataFc1.minData.data.push(parseFloat(v.faceRetM3));
-        echartDataFc1.aveValue.data.push(0);
-        echartDataFc1.xData.push(v.time);
-      });
+      fillHistoryChart(toggleData.history_report, true);
     } else {
-      toggleData.history.forEach((v) => {
-        echartDataFc1.maxData.data.push(parseFloat(v.jin));
-        echartDataFc1.minData.data.push(parseFloat(v.hui));
-        if (ventilateTopList[2].value && ventilateTopList[2].value != '--') {
-          echartDataFc1.aveValue.data.push(ventilateTopList[2].value);
-        } else {
-          echartDataFc1.aveValue.data.push(0);
-        }
-        echartDataFc1.xData.push(v.time);
-      });
+      fillHistoryChart(toggleData.history, false);
     }
   }
-  //获取左侧数据列表
+
   async function getMenuList() {
-    let res = await sysTypeWarnList({ type: 'vent' });
-    if (res.length != 0) {
-      menuList.length = 0;
-      res.forEach((el) => {
-        menuList.push({
-          name: el.deviceName,
-          warn: el.warnDes.indexOf('预警') != -1 ? '风量不足' : el.warnDes,
-          deviceID: el.deviceID,
-          strtype: el.deviceType,
-          detail: el.detail,
-        });
+    const res = await sysTypeWarnList({ type: 'vent' });
+    if (!res || res.length === 0) return;
+    menuList.length = 0;
+    res.forEach((el) => {
+      menuList.push({
+        name: el.deviceName,
+        warn: el.warnDes.indexOf('预警') != -1 ? '风量不足' : el.warnDes,
+        deviceID: el.deviceID,
+        strtype: el.deviceType,
+        detail: el.detail,
       });
-      //获取右侧详情数据
-      getDetailList(menuList[activeIndex1.value].detail);
-    }
+    });
+    getDetailList(menuList[activeIndex1.value]?.detail);
   }
 
-  //获取右侧详情数据
   function getDetailList(param) {
-    echartDataFc1.maxData.data.length = 0;
-    echartDataFc1.minData.data.length = 0;
-    echartDataFc1.aveValue.data.length = 0;
-    echartDataFc1.xData.length = 0;
-    if (JSON.stringify(param) != '{}') {
-      toggleData = Object.assign({}, param);
-      ventilateTopList[2].value = param.xufengliang || '--';
-      ventilateTopList[3].text = param.warnFlag ? param.warnDes : '正常';
-      if (showToggle.value == 'monitor') {
-        ventilateTopList[0].value = param.jin;
-        ventilateTopList[1].value = param.hui;
-        if (param.history.length != 0) {
-          param.history.forEach((v) => {
-            echartDataFc1.maxData.data.push(parseFloat(v.jin));
-            echartDataFc1.minData.data.push(parseFloat(v.hui));
-            if (ventilateTopList[2].value && ventilateTopList[2].value != '--') {
-              echartDataFc1.aveValue.data.push(ventilateTopList[2].value);
-            } else {
-              echartDataFc1.aveValue.data.push(0);
-            }
-            echartDataFc1.xData.push(v.time);
-          });
-        }
-      } else if (showToggle.value == 'report') {
-        ventilateTopList[0].value = param.faceIntM3;
-        ventilateTopList[1].value = param.faceRetM3;
-        param.history_report.forEach((v) => {
-          echartDataFc1.maxData.data.push(parseFloat(v.faceIntM3));
-          echartDataFc1.minData.data.push(parseFloat(v.faceRetM3));
-          echartDataFc1.aveValue.data.push(0);
-          echartDataFc1.xData.push(v.time);
-        });
-      } else {
-        getData();
-      }
-
-      let echartD = [echartDataFc1.maxData.data, echartDataFc1.minData.data];
-      maxY.value = getMaxY(echartD);
-      minY.value = getMinY(echartD);
+    clearChartData();
+    if (!param || JSON.stringify(param) === '{}') return;
+
+    toggleData = Object.assign({}, param);
+    ventilateTopList[2].value = param.xufengliang || '--';
+    ventilateTopList[3].text = param.warnFlag ? param.warnDes : '正常';
+
+    if (showToggle.value == 'monitor') {
+      ventilateTopList[0].value = param.jin;
+      ventilateTopList[1].value = param.hui;
+      fillHistoryChart(param.history, false);
+    } else if (showToggle.value == 'report') {
+      ventilateTopList[0].value = param.faceIntM3;
+      ventilateTopList[1].value = param.faceRetM3;
+      fillHistoryChart(param.history_report, true);
+    } else {
+      getData();
     }
+
+    updateYAxisRange();
   }
 
-  //通风选项切换
   function btnClick(ind) {
     activeIndex.value = ind;
-    switch (ind) {
-      case 0:
-        if (timer1) clearTimeout(timer1);
-        activeIndex1.value = 0;
-        getMenuList();
-        break;
-      case 1:
-        if (timer) clearTimeout(timer);
-        activeIndex1.value = 0;
-        menuList.length = 0;
-        getRealTimeNetData();
-        getMonitor1();
-        break;
+    activeIndex1.value = 0;
+    if (ind === 0) {
+      clearNetTimer();
+      getMenuList();
+    } else if (ind === 1) {
+      clearPollTimer();
+      menuList.length = 0;
+      getRealTimeNetData();
+      getMonitor1(true);
     }
   }
 
-  //菜单选项切换
-  function cardClick(ind, item) {
-    clearTimeout(timer);
-    if (!activeIndex.value && !loading.value) {
-      activeIndex1.value = ind;
-      loading.value = true;
-      setTimeout(() => {
-        getMonitor();
-        loading.value = false;
-      }, 2000);
-    }
+  function cardClick(ind) {
+    if (activeIndex.value || loading.value) return;
+    clearPollTimer();
+    activeIndex1.value = ind;
+    loading.value = true;
+    setTimeout(() => {
+      getMonitor(true);
+      loading.value = false;
+    }, 2000);
   }
 
-  //获取通风监控测点信息
   async function getWindDeviceList() {
     const cardTfList: any[] = [];
     const chartTfList: any[] = [];
-    let res = await getDevice({ devicetype: 'windrect', pagetype: 'normal' });
-    if (res && res.msgTxt[0]) {
-      let list = res.msgTxt[0].datalist || [];
-      if (list.length > 0) {
-        list.forEach((el: any) => {
-          const readData = el.readData;
-          el = Object.assign(el, readData);
-          cardTfList.push({
-            label: '通信状态',
-            value: el.netStatus == '0' ? '断开' : '连接',
-            listR: [
-              { id: 0, label: '安装位置', dw: '', value: el.strinstallpos },
-              { id: 1, label: '风量', dw: 'm³/min', value: el.m3 || '--' },
-              { id: 2, label: '风速', dw: 'm/s', value: el.va || '--' },
-              { id: 4, label: '时间', dw: '', value: el.readTime },
-              {
-                id: 3,
-                label: '是否报警',
-                dw: '',
-                value: el.warnFlag == '0' ? '正常' : el.warnFlag == 1 ? '报警' : el.warnFlag == 2 ? '断开' : '未监测',
-              },
-            ],
-          });
-          // 初始化预测曲线配置,分别为x轴时间、平均、最大、最小、实时
-          const avgParam = el.avgParam || {
-            avg_vent_value: 0,
-            max_vent_value: 0,
-            min_vent_value: 0,
-          };
-          chartTfList.push({
-            label: el.strinstallpos,
-            time: new Date(),
-            data: [avgParam.avg_m3_value, avgParam.max_m3_value, avgParam.min_m3_value, el.readData.m3],
-          });
-        });
-      }
-      cardListTf.value = cardTfList;
-      chartListTf.value = chartTfList;
-    }
+    const res = await getDevice({ devicetype: 'windrect', pagetype: 'normal' });
+    const list = res?.msgTxt?.[0]?.datalist || [];
+    list.forEach((el: any) => {
+      const readData = el.readData || {};
+      Object.assign(el, readData);
+      cardTfList.push({
+        label: '通信状态',
+        value: el.netStatus == '0' ? '断开' : '连接',
+        listR: [
+          { id: 0, label: '安装位置', dw: '', value: el.strinstallpos },
+          { id: 1, label: '风量', dw: 'm³/min', value: el.m3 || '--' },
+          { id: 2, label: '风速', dw: 'm/s', value: el.va || '--' },
+          { id: 4, label: '时间', dw: '', value: el.readTime },
+          {
+            id: 3,
+            label: '是否报警',
+            dw: '',
+            value: el.warnFlag == '0' ? '正常' : el.warnFlag == 1 ? '报警' : el.warnFlag == 2 ? '断开' : '未监测',
+          },
+        ],
+      });
+      const avgParam = el.avgParam || {};
+      chartTfList.push({
+        label: el.strinstallpos,
+        time: new Date(),
+        data: [avgParam.avg_m3_value || 0, avgParam.max_m3_value || 0, avgParam.min_m3_value || 0, readData.m3],
+      });
+    });
+    cardListTf.value = cardTfList;
+    chartListTf.value = chartTfList;
   }
+
   async function getRealTimeNetData() {
     const modalData = await modalParam({});
-    if (modalData && modalData.param && modalData.param.records.length && modalData.param.records.length > 0) {
-      const res = await realTimeNetCal({ modelID: modalData.param.records[0]['defaultmodelid'] });
-      if (res && res['result']) ventTunDataSource.value = res['result']['tuns'];
-      let data = [];
-      ventTunDataSource.value.forEach((el) => {
-        if (el['dHTotal'] && el['oldHTotal']) {
-          el['leveld'] = ((el['dHTotal'] - el['oldHTotal']) / el['oldHTotal']) * 100;
-          data.push(el['leveld']);
-        } else {
-          data = [];
-        }
-      });
-      hdData.maxLevel = '正常';
-    }
+    const records = modalData?.param?.records;
+    if (!records?.length) return;
+
+    const res = await realTimeNetCal({ modelID: records[0]['defaultmodelid'] });
+    const tuns = res?.result?.tuns || [];
+    ventTunDataSource.value = tuns;
+    tuns.forEach((el) => {
+      if (el['dHTotal'] && el['oldHTotal']) {
+        el['leveld'] = ((el['dHTotal'] - el['oldHTotal']) / el['oldHTotal']) * 100;
+      }
+    });
+    hdData.maxLevel = '正常';
   }
 
-  onMounted(async () => {
-    const { sysOrgCode, sysDataType } = useGlobSetting();
+  onMounted(() => {
+    const { sysDataType } = useGlobSetting();
     showToggle.value = sysDataType || 'report';
-    await getMenuList();
-    await getMonitor();
+    getMonitor(true);
   });
+
   onUnmounted(() => {
-    if (timer) {
-      clearTimeout(timer);
-      timer = undefined;
-    }
-    if (timer1) {
-      clearTimeout(timer1);
-      timer1 = undefined;
-    }
+    clearPollTimer();
+    clearNetTimer();
   });
 </script>
 
@@ -356,9 +333,6 @@
       --image-no-choice: url('/@/assets/images/themify/deepblue/fire/no-choice.png');
       --image-choice: url('/@/assets/images/themify/deepblue/fire/choice.png');
       --image-bj1: url('/@/assets/images/themify/deepblue/fire/bj1.png');
-      --image-jinfengliang: url('/@/assets/images/themify/deepblue/fire/jinfengliang.png');
-      --image-huifengliang: url('/@/assets/images/themify/deepblue/fire/huifengliang.png');
-      --image-xufengliang: url('/@/assets/images/themify/deepblue/fire/xufengliang.png');
     }
   }
 
@@ -367,12 +341,7 @@
     --image-no-choice: url('/@/assets/images/fire/no-choice.png');
     --image-choice: url('/@/assets/images/fire/choice.png');
     --image-bj1: url('/@/assets/images/fire/bj1.png');
-    --image-jinfengliang: url('/@/assets/images/fire/jinfengliang.png');
-    --image-huifengliang: url('/@/assets/images/fire/huifengliang.png');
-    --image-xufengliang: url('/@/assets/images/fire/xufengliang.png');
-    --border-image-1: linear-gradient(to bottom, #2d74a0, #2d74a0, #2d74a0);
-    --border-image-2: linear-gradient(to bottom, transparent, #024688, transparent);
-    position: reactive;
+    position: relative;
     width: 100%;
     height: 100%;
     padding: 80px 10px 15px 10px;
@@ -541,11 +510,6 @@
       }
     }
 
-    .tun-box {
-      width: 600px;
-      height: 300px;
-    }
-
     .ventilate-bottom {
       height: calc(50% - 15px);
       background: var(--image-border) no-repeat center;

+ 488 - 178
src/views/vent/testChart/FiberTempChart.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="fiber-temp-chart-wrap">
+  <div class="fiber-temp-chart-wrap" :class="{ compact }">
     <div class="chart-header">
       <div class="chart-title">{{ title }}</div>
       <div class="chart-header-desc">
@@ -20,8 +20,8 @@
 <script setup>
 import { ref, watch, onMounted, onBeforeUnmount, nextTick } from 'vue';
 import * as echarts from 'echarts';
-import firePng from '@/assets/images/fire.png';
-import warningSVG from '@/assets/images/warning.svg';
+import firePng from '/@/assets/images/fire.png';
+import warningSVG from '/@/assets/images/warning.svg';
 
 const props = defineProps({
   xAxisData: {
@@ -48,29 +48,196 @@ const props = defineProps({
     type: String,
     default: '光纤测温',
   },
+  compact: {
+    type: Boolean,
+    default: false,
+  },
+  markSymbolSize: {
+    type: Number,
+    default: 48,
+  },
+  // 纵轴名称、数值文案(束管浓度等可复用)
+  yAxisName: {
+    type: String,
+    default: '温度℃',
+  },
+  valueLabel: {
+    type: String,
+    default: '温度',
+  },
+  valueUnit: {
+    type: String,
+    default: '℃',
+  },
+  // dataZoom 默认窗口起始/结束;配合 dataZoomMode 使用
+  dataZoomStart: {
+    type: Number,
+    default: 0,
+  },
+  dataZoomEnd: {
+    type: Number,
+    default: undefined,
+  },
+  // percent: start/end 为 0-100 百分比;index: start/end 为测点下标(如 0-20 表示前 21 个点)
+  dataZoomMode: {
+    type: String,
+    default: 'percent',
+  },
 });
 
 const emit = defineEmits(['chart-click']);
 
 const chartDomRef = ref(null);
 let chartInstance = null;
+let optionReady = false;
+let lastDataKey = '';
+let resizeBound = false;
+let lastAxisLength = 0;
+let defaultZoomApplied = false;
+
+function isAlarmValue(val, minValue, maxValue) {
+  if (val === null || val === undefined || Number.isNaN(Number(val))) return false;
+  return val < minValue || val >= maxValue;
+}
+
+function getDataKey() {
+  return JSON.stringify({
+    x: props.xAxisData,
+    s: props.seriesData,
+    min: props.minValue,
+    max: props.maxValue,
+    ms: props.markSymbolSize,
+    c: props.compact,
+    yn: props.yAxisName,
+    vl: props.valueLabel,
+    vu: props.valueUnit,
+  });
+}
 
 function disposeChart() {
   if (chartInstance) {
+    chartInstance.off('click');
     chartInstance.dispose();
     chartInstance = null;
   }
+  optionReady = false;
+  lastDataKey = '';
+  lastAxisLength = 0;
+  defaultZoomApplied = false;
+}
+
+function pickZoomNumber(val, fallback) {
+  const raw = Array.isArray(val) ? val[0] : val;
+  const num = Number(raw);
+  return Number.isFinite(num) ? num : fallback;
+}
+
+function resolveDefaultZoom(xAxisData) {
+  const axisLength = xAxisData.length;
+  const mode = props.dataZoomMode === 'index' ? 'index' : 'percent';
+  const startRaw = Number(props.dataZoomStart);
+  const endRaw = Number(props.dataZoomEnd);
+
+  if (mode === 'index') {
+    if (!axisLength) {
+      return { mode, start: 0, end: 100, startValue: undefined, endValue: undefined };
+    }
+    const startIndex = Number.isFinite(startRaw) ? Math.max(0, Math.floor(startRaw)) : 0;
+    const endIndex = Number.isFinite(endRaw)
+      ? Math.min(axisLength - 1, Math.max(startIndex, Math.floor(endRaw)))
+      : Math.min(axisLength - 1, startIndex + 19);
+    return {
+      mode,
+      start: (startIndex / Math.max(axisLength - 1, 1)) * 100,
+      end: (endIndex / Math.max(axisLength - 1, 1)) * 100,
+      startValue: xAxisData[startIndex],
+      endValue: xAxisData[endIndex],
+    };
+  }
+
+  const start = Number.isFinite(startRaw) ? startRaw : 0;
+  let end;
+  if (Number.isFinite(endRaw)) {
+    end = endRaw;
+  } else if (axisLength <= 20) {
+    end = 100;
+  } else {
+    end = Math.min(100, Math.max(1, Math.round((20 / axisLength) * 100)));
+  }
+  return { mode, start, end, startValue: undefined, endValue: undefined };
+}
+
+function buildDataZoomOption(compact, zoom, preserve) {
+  const start = preserve?.start ?? zoom.start;
+  const end = preserve?.end ?? zoom.end;
+  const base = {
+    start,
+    end,
+    filterMode: 'filter',
+  };
+  // index 模式优先用类目值锁定窗口,避免百分比被 inside 缩放冲掉
+  if (zoom.mode === 'index' && zoom.startValue !== undefined && zoom.endValue !== undefined && !preserve) {
+    base.startValue = zoom.startValue;
+    base.endValue = zoom.endValue;
+  } else if (preserve?.startValue !== undefined && preserve?.endValue !== undefined) {
+    base.startValue = preserve.startValue;
+    base.endValue = preserve.endValue;
+  }
+
+  return [
+    {
+      type: 'slider',
+      show: true,
+      height: compact ? 16 : 20,
+      bottom: 6,
+      backgroundColor: '#152c47',
+      fillerColor: '#2ef3ef66',
+      handleStyle: { color: '#2ef3ef' },
+      textStyle: { color: '#ffffff' },
+      borderColor: 'rgba(46,243,239,0.3)',
+      zoomLock: false,
+      ...base,
+    },
+    {
+      type: 'inside',
+      ...base,
+    },
+  ];
+}
+
+function applyZoomAction(zoom, preserve) {
+  if (!chartInstance) return;
+  const payload = {
+    type: 'dataZoom',
+  };
+  if (preserve) {
+    payload.start = preserve.start;
+    payload.end = preserve.end;
+  } else if (zoom.mode === 'index' && zoom.startValue !== undefined && zoom.endValue !== undefined) {
+    payload.startValue = zoom.startValue;
+    payload.endValue = zoom.endValue;
+  } else {
+    payload.start = zoom.start;
+    payload.end = zoom.end;
+  }
+  // slider + inside 都强制同步到同一窗口
+  chartInstance.dispatchAction({ ...payload, dataZoomIndex: 0 });
+  chartInstance.dispatchAction({ ...payload, dataZoomIndex: 1 });
 }
 
 function initChart() {
   if (!chartDomRef.value) return;
-  disposeChart();
-  chartInstance = echarts.init(chartDomRef.value);
-  renderOption();
-  chartInstance.on('click', (params) => {
-    emit('chart-click', params);
-  });
-  window.addEventListener('resize', handleResize);
+  if (!chartInstance) {
+    chartInstance = echarts.init(chartDomRef.value);
+    chartInstance.on('click', (params) => {
+      emit('chart-click', params);
+    });
+  }
+  if (!resizeBound) {
+    window.addEventListener('resize', handleResize);
+    resizeBound = true;
+  }
+  renderOption(true);
 }
 
 function handleResize() {
@@ -79,13 +246,16 @@ function handleResize() {
 
 function getMarkPointData() {
   const markPoints = [];
-  const { seriesData, minValue, maxValue } = props;
+  const { seriesData, minValue, maxValue, markSymbolSize } = props;
+  const size = markSymbolSize || 48;
   seriesData.forEach((val, idx) => {
-    if (val < minValue || val >= maxValue) {
+    if (isAlarmValue(val, minValue, maxValue)) {
+      const offsetY = Math.max(8, size * 0.35);
       markPoints.push({
-        coord: [idx, val + 15],
+        coord: [idx, val],
         symbol: `image://${val < minValue ? warningSVG : firePng}`,
-        symbolSize: [60, 60],
+        symbolSize: [size, size],
+        symbolOffset: [0, -offsetY],
         tooltip: {
           formatter: `<div style="color:#ff4422;font-weight:bold">异常确认<br/>立即排查</div>`,
         },
@@ -100,203 +270,325 @@ function getAlarmContinuousData(data, minValue, maxValue) {
   const result = [];
   const n = data.length;
 
-  const isAlarm = (val) => val < minValue || val >= maxValue;
-
   for (let i = 0; i < n; i++) {
     const val = data[i];
-    if (isAlarm(val)) {
-      // 当前点是报警点,保留原值
+    if (isAlarmValue(val, minValue, maxValue)) {
       result.push(val);
     } else {
-      // 检查相邻点是否有报警点,如果有则保留当前值作为边界
-      const prevAlarm = i > 0 && isAlarm(data[i - 1]);
-      const nextAlarm = i < n - 1 && isAlarm(data[i + 1]);
-
-      if (prevAlarm || nextAlarm) {
-        // 使用实际边界值,与正常折线在切换点保持连续
-        result.push(val);
-      } else {
-        result.push(null);
-      }
+      const prevAlarm = i > 0 && isAlarmValue(data[i - 1], minValue, maxValue);
+      const nextAlarm = i < n - 1 && isAlarmValue(data[i + 1], minValue, maxValue);
+      result.push(prevAlarm || nextAlarm ? val : null);
     }
   }
   return result;
 }
 
-function getAlarmPointData(data, minValue, maxValue) {
-  return data.map((val) => (val < minValue || val >= maxValue ? val : null));
+function getYAxisMax(seriesData, minValue, maxValue) {
+  const nums = seriesData.map((v) => Number(v)).filter((v) => !Number.isNaN(v));
+  const dataMax = nums.length ? Math.max(...nums) : 0;
+  const dataMin = nums.length ? Math.min(...nums) : 0;
+  const base = Math.max(
+    dataMax,
+    Math.abs(dataMin),
+    Number(maxValue) || 0,
+    Math.abs(Number(minValue) || 0),
+    0.1
+  );
+  const padded = base * 1.2;
+  if (padded <= 1) return Math.ceil(padded * 10) / 10 || 1;
+  if (padded <= 10) return Math.ceil(padded);
+  if (padded <= 100) return Math.ceil(padded / 5) * 5;
+  return Math.ceil(padded / 10) * 10;
 }
 
-function renderOption() {
-  if (!chartInstance) return;
-  const { xAxisData, seriesData, minValue, maxValue } = props;
+// 始终从 props 读取,避免首次空数据初始化后 formatter 闭包旧数组导致 tooltip 空白
+function formatTooltip(params) {
+  const list = Array.isArray(params) ? params : [params];
+  const dataIndex = list.find((item) => item && item.dataIndex !== undefined)?.dataIndex;
+  if (dataIndex === undefined) return '';
+
+  const xLabel = props.xAxisData?.[dataIndex];
+  const val = props.seriesData?.[dataIndex];
+  if (val === undefined || val === null || Number.isNaN(Number(val))) return '';
+
+  const alarm = isAlarmValue(val, props.minValue, props.maxValue);
+  const unit = props.valueUnit || '';
+  return `<div style="font-weight:bold;${alarm ? 'color:#ff8800' : 'color:#35d9e5'}">
+    ${xLabel ?? ''}<br/>
+    ${props.valueLabel || '数值'}:${val}${unit}${alarm ? ' 超限' : ''}
+  </div>`;
+}
 
-  // 报警填充数据:包含实际边界点,使报警区域连续
+function getTooltipOption() {
+  return {
+    show: true,
+    trigger: 'axis',
+    triggerOn: 'mousemove|click',
+    // 挂到 body,避免父容器 overflow 裁剪;echarts6 使用 appendTo
+    appendToBody: true,
+    appendTo: typeof document !== 'undefined' ? document.body : undefined,
+    confine: false,
+    backgroundColor: 'rgba(0,20,40,0.85)',
+    borderColor: '#2ef3ef',
+    borderWidth: 1,
+    padding: [8, 12],
+    textStyle: { color: '#fff', fontSize: 13 },
+    axisPointer: {
+      type: 'line',
+      lineStyle: { color: 'rgba(46,243,239,0.45)' },
+    },
+    formatter: formatTooltip,
+  };
+}
+
+function buildSeriesPayload(seriesData, minValue, maxValue, compact) {
   const alarmFillData = getAlarmContinuousData(seriesData, minValue, maxValue);
+  const normalFillData = seriesData.map((val) => (isAlarmValue(val, minValue, maxValue) ? null : val));
+  const normalLineData = seriesData.map((val) => (isAlarmValue(val, minValue, maxValue) ? null : val));
+  const markPointData = getMarkPointData();
 
-  // 报警折线数据:只保留超过上限或低于下限的点
-  const alarmLineData = getAlarmPointData(seriesData, minValue, maxValue);
+  return [
+    {
+      name: '正常填充',
+      type: 'line',
+      smooth: true,
+      data: normalFillData,
+      symbol: 'none',
+      connectNulls: false,
+      lineStyle: { width: 0 },
+      tooltip: { show: false },
+      areaStyle: {
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          { offset: 0, color: 'rgba(53,217,229,0.35)' },
+          { offset: 1, color: 'rgba(53,217,229,0.05)' },
+        ]),
+      },
+      z: 1,
+      animationDurationUpdate: 0,
+    },
+    {
+      name: '报警填充',
+      type: 'line',
+      smooth: true,
+      data: alarmFillData,
+      symbol: 'none',
+      connectNulls: false,
+      lineStyle: { width: 0 },
+      tooltip: { show: false },
+      areaStyle: {
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          { offset: 0, color: 'rgba(255,136,0,0.5)' },
+          { offset: 1, color: 'rgba(255,136,0,0.05)' },
+        ]),
+      },
+      z: 2,
+      animationDurationUpdate: 0,
+    },
+    {
+      name: '正常测温',
+      type: 'line',
+      smooth: true,
+      data: normalLineData,
+      symbol: 'circle',
+      symbolSize: compact ? 6 : 8,
+      connectNulls: false,
+      lineStyle: { width: 3, color: '#35d9e5' },
+      itemStyle: { color: '#35d9e5' },
+      z: 3,
+      animationDurationUpdate: 0,
+    },
+    {
+      name: '报警测温',
+      type: 'line',
+      smooth: true,
+      data: alarmFillData,
+      symbol: 'circle',
+      symbolSize: (_value, params) => {
+        const val = seriesData[params.dataIndex];
+        return isAlarmValue(val, minValue, maxValue) ? (compact ? 8 : 10) : 0;
+      },
+      connectNulls: false,
+      lineStyle: { width: 3, color: '#ff8800' },
+      itemStyle: { color: '#ff8800' },
+      markPoint: {
+        data: markPointData,
+        animation: false,
+      },
+      markLine: {
+        silent: true,
+        symbol: ['none', 'arrow'],
+        symbolSize: 8,
+        animation: false,
+        data: [
+          {
+            yAxis: minValue,
+            label: {
+              show: true,
+              position: 'end',
+              formatter: '下限阈值',
+              color: '#39d98a',
+              fontSize: compact ? 11 : 12,
+            },
+            lineStyle: { type: 'dashed', width: 2, color: '#39d98a' },
+          },
+          {
+            yAxis: maxValue,
+            label: {
+              show: true,
+              position: 'end',
+              formatter: '上限阈值',
+              color: '#ff2222',
+              fontSize: compact ? 11 : 12,
+            },
+            lineStyle: { type: 'dashed', width: 2, color: '#ff2222' },
+          },
+        ],
+      },
+      z: 4,
+      animationDurationUpdate: 0,
+    },
+  ];
+}
+
+function renderOption(force = false) {
+  if (!chartInstance) return;
+
+  const dataKey = getDataKey();
+  if (!force && dataKey === lastDataKey) return;
+  lastDataKey = dataKey;
 
-  // 正常填充数据:仅保留上下限之间的值,报警值设为 null
-  const normalFillData = seriesData.map((val) => (val >= minValue && val < maxValue ? val : null));
+  const { xAxisData, seriesData, minValue, maxValue, compact } = props;
+  const yMax = getYAxisMax(seriesData, minValue, maxValue);
+  const series = buildSeriesPayload(seriesData, minValue, maxValue, compact);
+  const axisLength = xAxisData.length;
+  const defaultZoom = resolveDefaultZoom(xAxisData);
 
-  // 正常折线数据:只保留上下限之间的点
-  const normalLineData = seriesData.map((val) => (val >= minValue && val < maxValue ? val : null));
+  // 增量更新:只改数据;首次有数据或空数据→有数据时应用默认缩放,之后保留用户拖动的窗口
+  if (optionReady) {
+    const needResetZoom = !defaultZoomApplied || (lastAxisLength === 0 && axisLength > 0);
+    let preserve = null;
+
+    if (!needResetZoom) {
+      try {
+        const currentZoom = chartInstance.getOption()?.dataZoom?.[0];
+        if (currentZoom) {
+          preserve = {
+            start: pickZoomNumber(currentZoom.start, defaultZoom.start),
+            end: pickZoomNumber(currentZoom.end, defaultZoom.end),
+            startValue: Array.isArray(currentZoom.startValue) ? currentZoom.startValue[0] : currentZoom.startValue,
+            endValue: Array.isArray(currentZoom.endValue) ? currentZoom.endValue[0] : currentZoom.endValue,
+          };
+        }
+      } catch (e) {
+        // ignore
+      }
+    }
+
+    chartInstance.setOption(
+      {
+        tooltip: getTooltipOption(),
+        xAxis: { data: [...xAxisData] },
+        yAxis: { max: yMax, name: props.yAxisName || '温度℃' },
+        dataZoom: buildDataZoomOption(compact, defaultZoom, preserve),
+        series: series.map((item) => ({
+          name: item.name,
+          data: item.data,
+          symbolSize: item.symbolSize,
+          markPoint: item.markPoint,
+          markLine: item.markLine,
+        })),
+      },
+      {
+        notMerge: false,
+        lazyUpdate: true,
+      }
+    );
+
+    if (needResetZoom && axisLength > 0) {
+      nextTick(() => applyZoomAction(defaultZoom));
+    }
+
+    lastAxisLength = axisLength;
+    if (axisLength > 0) defaultZoomApplied = true;
+    return;
+  }
 
   const option = {
     backgroundColor: 'transparent',
+    animation: false,
+    animationDurationUpdate: 0,
     title: { show: false },
-    tooltip: {
-      trigger: 'axis',
-      backgroundColor: 'rgba(0,20,40,0.85)',
-      borderColor: '#2ef3ef',
-      textStyle: { color: '#fff' },
-      formatter: function (params) {
-        const dataIndex = params[0]?.dataIndex;
-        if (dataIndex !== undefined && seriesData[dataIndex] !== undefined) {
-          const val = seriesData[dataIndex];
-          const isAlarm = val < minValue || val >= maxValue;
-          return `<div style="font-weight:bold;${isAlarm ? 'color:#ff8800' : 'color:#35d9e5'}">
-            ${xAxisData[dataIndex] || ''}<br/>
-            温度:${val}℃${isAlarm ? ' 超限' : ''}
-          </div>`;
-        }
-        return '';
-      },
-    },
+    tooltip: getTooltipOption(),
     legend: { show: false },
     grid: {
-      left: '4%',
-      right: '3%',
-      top: '18%',
+      left: '3%',
+      right: '4%',
+      top: compact ? 26 : 32,
       bottom: '18%',
+      containLabel: true,
     },
     xAxis: {
       type: 'category',
-      data: xAxisData,
+      data: [...xAxisData],
+      boundaryGap: false,
       axisLine: { lineStyle: { color: '#2ef3ef' } },
-      axisLabel: { color: '#ffffff', fontSize: 14 },
+      axisLabel: {
+        color: '#ffffff',
+        fontSize: compact ? 11 : 14,
+        hideOverlap: true,
+      },
       splitLine: { show: true, lineStyle: { color: 'rgba(46,243,239,0.15)' } },
     },
     yAxis: {
       type: 'value',
-      name: '温度℃',
-      nameTextStyle: { color: '#fff' },
+      name: props.yAxisName || '温度℃',
+      nameLocation: 'end',
+      nameGap: 8,
+      nameTextStyle: {
+        color: '#fff',
+        fontSize: compact ? 12 : 14,
+        align: 'left',
+        padding: [0, 0, 0, 0],
+      },
       min: 0,
-      max: 130,
+      max: yMax,
       axisLine: { lineStyle: { color: '#2ef3ef' } },
-      axisLabel: { color: '#ffffff' },
+      axisLabel: { color: '#ffffff', fontSize: compact ? 11 : 12 },
       splitLine: { lineStyle: { color: 'rgba(46,243,239,0.15)' } },
     },
-    dataZoom: [
-      {
-        type: 'slider',
-        show: true,
-        height: 20,
-        bottom: 8,
-        backgroundColor: '#152c47',
-        fillerColor: '#2ef3ef66',
-        handleStyle: { color: '#2ef3ef' },
-        textStyle: { color: '#ffffff' },
-        start: 0,
-        end: 30,
-        zoomLock: false,
-      },
-      { type: 'inside' },
-    ],
-    series: [
-      // 正常填充(青色)
-      {
-        name: '正常填充',
-        type: 'line',
-        smooth: true,
-        data: normalFillData,
-        symbol: 'none',
-        connectNulls: false,
-        lineStyle: { width: 0 },
-        tooltip: { show: false },
-        areaStyle: {
-          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-            { offset: 0, color: 'rgba(53,217,229,0.35)' },
-            { offset: 1, color: 'rgba(53,217,229,0.05)' },
-          ]),
-        },
-        z: 1,
-      },
-      // 报警填充(橙色)- 包含边界点,形成连续填充
-      {
-        name: '报警填充',
-        type: 'line',
-        smooth: true,
-        data: alarmFillData,
-        symbol: 'none',
-        connectNulls: false,
-        lineStyle: { width: 0 },
-        tooltip: { show: false },
-        areaStyle: {
-          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-            { offset: 0, color: 'rgba(255,136,0,0.5)' },
-            { offset: 1, color: 'rgba(255,136,0,0.05)' },
-          ]),
-        },
-        z: 2,
-      },
-      // 正常折线(青色)
-      {
-        name: '正常测温',
-        type: 'line',
-        smooth: true,
-        data: normalLineData,
-        symbol: 'circle',
-        symbolSize: 8,
-        connectNulls: false,
-        lineStyle: { width: 3, color: '#35d9e5' },
-        itemStyle: { color: '#35d9e5' },
-        z: 3,
-      },
-      // 报警折线(橙色)- 包含边界点,形成连续折线
-      {
-        name: '报警测温',
-        type: 'line',
-        smooth: true,
-        data: alarmLineData,
-        symbol: 'circle',
-        symbolSize: 10,
-        connectNulls: false,
-        lineStyle: { width: 3, color: '#ff8800' },
-        itemStyle: {
-          color: function (params) {
-            const val = params.data;
-            // 边界点(等于阈值)不显示圆点
-            if (val === minValue || val === maxValue) return 'transparent';
-            return '#ff8800';
-          },
-        },
-        markPoint: {
-          data: getMarkPointData(),
-          offset: [0, -100],
-        },
-        markLine: {
-          silent: true,
-          lineStyle: { type: 'dashed', width: 2, color: '#ff2222' },
-          label: { show: true, position: 'end', fontSize: 12, color: '#ff2222' },
-          data: [
-            { yAxis: minValue, label: { formatter: '下限阈值' } },
-            { yAxis: maxValue, label: { formatter: '上限阈值' } },
-          ],
-        },
-        z: 4,
-      },
-    ],
+    dataZoom: buildDataZoomOption(compact, defaultZoom, null),
+    series,
   };
 
-  chartInstance.setOption(option, true);
+  chartInstance.setOption(option, { notMerge: true, lazyUpdate: false });
+  optionReady = true;
+  lastAxisLength = axisLength;
+  if (axisLength > 0) {
+    defaultZoomApplied = true;
+    nextTick(() => applyZoomAction(defaultZoom));
+  }
 }
 
 watch(
-  () => [props.xAxisData, props.seriesData, props.minValue, props.maxValue],
+  () => [
+    props.xAxisData,
+    props.seriesData,
+    props.minValue,
+    props.maxValue,
+    props.markSymbolSize,
+    props.compact,
+    props.yAxisName,
+    props.valueLabel,
+    props.valueUnit,
+  ],
   () => {
-    nextTick(() => renderOption());
+    nextTick(() => {
+      if (!chartInstance) {
+        initChart();
+        return;
+      }
+      renderOption(false);
+    });
   },
   { deep: true }
 );
@@ -307,7 +599,10 @@ onMounted(() => {
 
 onBeforeUnmount(() => {
   disposeChart();
-  window.removeEventListener('resize', handleResize);
+  if (resizeBound) {
+    window.removeEventListener('resize', handleResize);
+    resizeBound = false;
+  }
 });
 </script>
 
@@ -322,16 +617,17 @@ onBeforeUnmount(() => {
   display: flex;
   justify-content: space-between;
   align-items: center;
-  padding: 10px 16px;
+  padding: 6px 12px 0;
+  flex-shrink: 0;
 }
 .chart-title {
   color: #ffffff;
-  font-size: 24px;
+  font-size: 20px;
   font-weight: bold;
 }
 .chart-header-desc {
   display: flex;
-  gap: 32px;
+  gap: 24px;
   align-items: center;
 }
 .desc-item {
@@ -340,8 +636,8 @@ onBeforeUnmount(() => {
   gap: 8px;
 }
 .color-block {
-  width: 32px;
-  height: 12px;
+  width: 28px;
+  height: 10px;
   border-radius: 2px;
 }
 .color-block.normal {
@@ -352,10 +648,24 @@ onBeforeUnmount(() => {
 }
 .text {
   color: #ffffff;
-  font-size: 16px;
+  font-size: 14px;
 }
 .chart-container {
   flex: 1;
   width: 100%;
+  min-height: 0;
+}
+.fiber-temp-chart-wrap.compact .chart-title {
+  font-size: 14px;
+}
+.fiber-temp-chart-wrap.compact .text {
+  font-size: 12px;
+}
+.fiber-temp-chart-wrap.compact .chart-header-desc {
+  gap: 16px;
+}
+.fiber-temp-chart-wrap.compact .color-block {
+  width: 22px;
+  height: 8px;
 }
-</style>
+</style>