riku
2025-07-04 d6e6f8b5b31e132e4597eb531168d3e88f3bda72
src/views/realtimemode/RealtimeMode.vue
@@ -1,33 +1,77 @@
<template>
  <div class="p-events-none m-t-2">
    <el-row justify="center" align="middle" class="top-wrap"> </el-row>
    <el-row class="m-t-2">
      <FactorRadio
        :device-type="deviceType"
        @change="(e) => (factorType = e)"
      ></FactorRadio>
    <el-row justify="center" align="middle" class="top-wrap">
      <DeviceChange @change="onDeviceChange"></DeviceChange>
      <el-button
        type="primary"
        class="p-events-auto el-button-custom"
        @click="pauseTask"
      >
        {{ pause ? '继续' : '暂停' }}
      </el-button>
    </el-row>
    <el-row class="m-t-2">
      <FactorLegend
        class="m-t-2"
        :factor="factorDatas.factor[factorType]"
      ></FactorLegend>
      <FactorRadio :device-type="deviceType" v-model="factorType"></FactorRadio>
    </el-row>
    <el-row class="m-t-2" justify="start">
      <DashBoard :factor-datas="factorDatas"></DashBoard>
    <el-row class="m-t-2">
      <el-col span="1">
        <FactorLegend :factor="factorDatas.factor[factorType]"></FactorLegend>
      </el-col>
      <el-col span="1"> </el-col>
    </el-row>
    <!-- <DashBoard class="dash-board" :factor-datas="factorDatas"></DashBoard> -->
    <RealTimeTrend
      class="real-time-trend"
      :factor-datas="factorDatas"
      :device-type="deviceType"
    ></RealTimeTrend>
    <SourceTrace
      class="source-trace"
      v-model:factorType="factorType"
      :deviceCode="deviceCode"
    ></SourceTrace>
    <!-- <PollutedClueItem></PollutedClueItem> -->
  </div>
</template>
<script>
import moment from 'moment';
import mapUtil from '@/utils/map/util';
import { useFetchData } from '@/composables/fetchData';
import { TYPE0 } from '@/constant/device-type';
import { defaultOptions } from '@/constant/radio-options';
import { FactorDatas } from '@/model/FactorDatas';
import monitorDataApi from '@/api/monitorDataApi';
import DashBoard from './component/DashBoard.vue';
import RealTimeTrend from './component/RealTimeTrend.vue';
import DeviceChange from './component/DeviceChange.vue';
import SourceTrace from '@/views/sourcetrace/SourceTrace.vue';
import UnderwayAdvice from '@/views/sourcetrace/UnderwayAdvice.vue';
import PollutedClueItem from '@/views/sourcetrace/component/PollutedClueItem.vue';
import { realTimeMapAnimation } from '@/utils/map/animation';
import {
  fetchHistoryData,
  startLoopFetchRealTimeData,
  clearFetchingTask,
  pauseTask
} from '@/utils/factor/data';
import thirdPartyDataApi from '@/api/thirdPartyDataApi';
import websocket from '@/api/websocket';
// const mapAnimation = new MapAnimation();
// 调试模式
const mode = 'debug';
// const mode = 'product';
export default {
  components: { DashBoard },
  components: {
    DashBoard,
    RealTimeTrend,
    DeviceChange,
    SourceTrace,
    UnderwayAdvice,
    PollutedClueItem
  },
  setup() {
    const { loading, fetchData } = useFetchData(10000);
    return { loading, fetchData };
@@ -36,38 +80,157 @@
    return {
      // 监测设备类型
      deviceType: TYPE0,
      deviceCode: '',
      // 监测因子的类型编号
      factorType: '1',
      // 监测数据
      factorDatas: new FactorDatas()
      factorType: defaultOptions(TYPE0).value,
      // 新获取的监测数据
      factorDatas: new FactorDatas(),
      // 全部监测数据
      allFactorDatas: new FactorDatas(),
      pause: false
    };
  },
  watch: {
    factorType(nV, oV) {
      if (nV != oV) {
        realTimeMapAnimation.setFactorType(nV);
      }
    }
  },
  computed: {
    // 数据最新时间(最新数据的采样时间加1秒;没有数据时,采用当前时间的前6分钟)
    latestTime() {
      if (this.factorDatas.times.length == 0) {
        return moment().subtract(6, 'm').format('YYYY-MM-DD HH:mm:ss');
      } else {
        const _time = this.factorDatas.times[this.factorDatas.times.length - 1];
        return moment(_time).add(1, 's').format('YYYY-MM-DD HH:mm:ss');
      }
    }
  },
  methods: {
    onFetchData(type, data) {
      // todo 根据设备类型切换地图监测因子展示单选框、折线图复选框、数据表格复选框的因子类型
    onDeviceChange({ type, deviceCode }) {
      this.deviceType = type;
      this.factorDatas.setData(data, this.drawMode, () => {
        this.factorDatas.refreshHeight(this.factorType);
      this.deviceCode = deviceCode;
      this.clearFetchingTask();
      realTimeMapAnimation.stop();
      this.allFactorDatas.clearData();
      this.factorDatas.clearData();
      this.notFirstFetch = false;
      this.fetchRealTimeData();
    },
    onFetchData(data) {
      // todo 根据设备类型切换地图监测因子展示单选框、折线图复选框、数据表格复选框的因子类型
      // this.deviceType = type;
      const fDatas = new FactorDatas();
      fDatas.setData(data, this.drawMode, () => {
        fDatas.refreshHeight(this.factorType);
        // this.draw();
        this.factorDatas = fDatas;
      });
      if (mode == 'debug') {
        websocket.send(JSON.stringify(data));
      }
    },
    fetchRealTimeData() {
      // fixme 2024.5.3 此处初始获取的数据,参数应该由searchbar决定,后续修改
      this.fetchData((page) => {
        return monitorDataApi
          .fetchHistroyData({
            deviceCode: '0a0000000001',
            page,
            perPage: 100
          })
          .then((res) => {
            this.onFetchData(TYPE0, res.data);
          });
        const param =
          mode == 'debug'
            ? {
                deviceCode: this.deviceCode,
                // startTime: '2025-01-16 11:34:00',
                // endTime: '2025-01-16 11:35:00',
                // startTime: '2025-01-20 12:40:00',
                // startTime: '2024-12-27 08:30:00',
                // startTime: '2024-12-13 16:35:00',
                // startTime: '2024-11-27 11:50:41', // Pm, 中距离工地
                // startTime: '2024-08-30 15:28:00', // voc 近距离汽修
                startTime: '2024-07-23 15:21:30',
                // startTime: '2024-07-23 14:39:00',
                endTime: '2025-01-16 11:51:41',
                page,
                perPage: 10
              }
            : {
                deviceCode: this.deviceCode,
                page,
                perPage: 100
              };
        return fetchHistoryData(param, false).then((res) => {
          this.onFetchData(res.data);
          this.onMapData(res.data);
          this.fetchNextData();
          thirdPartyDataApi.fetchLatestData(this.deviceType, this.deviceCode);
        });
      });
    },
    pauseTask() {
      this.pause = pauseTask();
    },
    clearFetchingTask() {
      clearFetchingTask();
    },
    fetchNextData() {
      startLoopFetchRealTimeData(
        () => {
          return {
            deviceCode: this.deviceCode,
            updateTime: this.latestTime,
            perPage: mode == 'debug' ? 1 : 10
          };
        },
        (res) => {
          this.onFetchData(res.data);
          this.onMapData(res.data);
          thirdPartyDataApi.fetchLatestData(this.deviceType, this.deviceCode);
        },
        mode == 'debug' ? 4000 : undefined
      );
    },
    onMapData(dataList) {
      let startIndex = this.allFactorDatas.length() - 1;
      if (!this.notFirstFetch) {
        startIndex = dataList.length - 2;
        this.notFirstFetch = true;
      }
      startIndex = startIndex < 0 ? 0 : startIndex;
      return new Promise(() => {
        this.allFactorDatas.addData(dataList, this.drawMode, () => {
          realTimeMapAnimation.moveAnimation(
            this.allFactorDatas,
            this.factorType,
            startIndex
          );
        });
      });
    }
  },
  mounted() {
    this.fetchRealTimeData();
    if (mode == 'debug') {
      websocket.send('start');
    }
  },
  unmounted() {
    this.clearFetchingTask();
    realTimeMapAnimation.stop();
    mapUtil.clearMap();
  }
};
</script>
<style scoped>
.dash-board {
  position: absolute;
  right: 0;
  bottom: 0px;
}
.real-time-trend {
  position: absolute;
  right: 0;
  top: 0;
}
.source-trace {
  position: absolute;
  left: 0;
  bottom: 0px;
}
</style>