riku
2024-05-12 fb876cbc3b21035125668f2db6ee84e47efb544f
实时走航模式完成
已修改12个文件
已添加2个文件
387 ■■■■ 文件已修改
src/components.d.ts 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/animation/HistoricalTrajectory.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chart/RealTimeLineChart.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/core/CoreMenu.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/monitor/VehicleData.vue 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/monitor/WeatherData-copy.vue 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/monitor/WeatherData.vue 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/search/OptionDevice.vue 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/model/FrameAnimation.js 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/animation.js 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/historymode/HistoryMode.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/realtimemode/RealtimeMode.vue 60 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/realtimemode/component/DashBoard.vue 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/realtimemode/component/DeviceChange.vue 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components.d.ts
@@ -11,6 +11,8 @@
    BaseMap: typeof import('./components/map/BaseMap.vue')['default']
    CardButton: typeof import('./components/CardButton.vue')['default']
    CardDialog: typeof import('./components/CardDialog.vue')['default']
    cop: typeof import('./components/monitor/WeatherData.vue')['default']
    copy: typeof import('./components/monitor/WeatherData.vue')['default']
    CoreHeader: typeof import('./components/core/CoreHeader.vue')['default']
    CoreMenu: typeof import('./components/core/CoreMenu.vue')['default']
    DataSummary: typeof import('./components/monitor/DataSummary.vue')['default']
@@ -45,7 +47,6 @@
    FactorTrend: typeof import('./components/monitor/FactorTrend.vue')['default']
    GaugeChart: typeof import('./components/chart/GaugeChart.vue')['default']
    HistoricalTrajectory: typeof import('./components/animation/HistoricalTrajectory.vue')['default']
    LineChart: typeof import('./components/chart/LineChart.vue')['default']
    MapToolbox: typeof import('./components/map/MapToolbox.vue')['default']
    MIssionCreate: typeof import('./components/mission/MIssionCreate.vue')['default']
    MissionImport: typeof import('./components/mission/MissionImport.vue')['default']
@@ -63,6 +64,8 @@
    TrajectoryState: typeof import('./components/animation/TrajectoryState.vue')['default']
    VehicleData: typeof import('./components/monitor/VehicleData.vue')['default']
    WeatherData: typeof import('./components/monitor/WeatherData.vue')['default']
    'WeatherData cop': typeof import('./components/monitor/WeatherData.vue')['default']
    WeatherDataCopy: typeof import('./components/monitor/WeatherData-copy.vue')['default']
  }
  export interface ComponentCustomProperties {
    vLoading: typeof import('element-plus/es')['ElLoadingDirective']
src/components/animation/HistoricalTrajectory.vue
@@ -126,6 +126,9 @@
    mapAnimation.setOnStopCallback(() => {
      this.$emit('stop');
    });
  },
  unmounted() {
    mapAnimation.stop();
  }
};
</script>
src/components/chart/RealTimeLineChart.vue
@@ -66,7 +66,7 @@
  justify-content: center;
}
.line-chart {
  width: 300px;
  width: 318px;
  height: 140px;
  /* border-bottom: 1px solid rgba(255, 255, 255, 0.329); */
}
src/components/core/CoreMenu.vue
@@ -57,10 +57,10 @@
          name: '走航监测',
          path: 'rmode'
        },
        {
          name: '网格化监测',
          path: 'gridmonitor'
        }
        // {
        //   name: '网格化监测',
        //   path: 'gridmonitor'
        // }
        // {
        //   name: '用电量监测',
        //   path: 'emode'
src/components/monitor/VehicleData.vue
@@ -14,17 +14,21 @@
export default {
  props: {
    loading: Boolean,
    factorDatas: FactorDatas
    factorDatas: FactorDatas,
    speed: {
      type: Number,
      default: 0
    }
  },
  data() {
    return {
      speed: 0
      // speed: 0
    };
  },
  watch: {
    factorDatas: {
      handler(nV) {
        this.speed = this.lastOne(nV, '14');
        // this.speed = this.lastOne(nV, '14');
      },
      deep: true
    }
src/components/monitor/WeatherData-copy.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,87 @@
<template>
  <el-row class="wrap">
    <el-form :inline="true" class="form">
      <el-form-item label="温度:" class="w-tag">
        {{ temprature }}
      </el-form-item>
      <el-form-item label="湿度:" class="w-tag">
        {{ humidity }}
      </el-form-item>
    </el-form>
    <!-- <div class="w-tag">{{ temprature }}</div>
    <div class="w-tag">{{ humidity }}</div> -->
  </el-row>
  <el-row class="wrap">
    <el-form :inline="true" class="form">
      <el-form-item label="风向:" class="w-tag">
        {{ windDirection }}
      </el-form-item>
      <el-form-item label="风速:" class="w-tag">
        {{ windSpeed }}
      </el-form-item>
    </el-form>
    <!-- <div class="w-tag">{{ windDirection }}</div>
    <div class="w-tag">{{ windSpeed }}</div> -->
  </el-row>
</template>
<script>
import { FactorDatas } from '@/model/FactorDatas';
export default {
  props: {
    loading: Boolean,
    factorDatas: FactorDatas
  },
  data() {
    return {
      temprature: '--℃',
      humidity: '--%',
      windDirection: '--',
      windSpeed: '--m/s',
    };
  },
  watch: {
    factorDatas: {
      handler(nV) {
        this.temprature = this.lastOne(nV, '8') + '℃';
        this.humidity = this.lastOne(nV, '9') + '%';
        this.windDirection = this.lastOne(nV, '17');
        this.windSpeed = this.lastOne(nV, '16') + 'm/s';
      },
      deep: true
    }
  },
  methods: {
    lastOne(factorDatas, key) {
      const f = factorDatas.factor[key];
      if (f) {
        const lastIndex = f.datas.length - 1;
        return factorDatas.factor[key].datas[lastIndex].factorData;
      } else {
        return '--';
      }
    }
  }
};
</script>
<style scoped>
.w-tag {
  padding: 2px 4px;
  /* background-color: green; */
  border: 1px solid white;
  border-radius: 2px;
  -moz-border-radius: 25px;
  width: 130px;
  /* Old Firefox */
}
.form {
  display: flex;
  gap: 4px;
}
.el-form-item {
  margin-bottom: 4px;
  margin-right: 0px !important;
}
</style>
src/components/monitor/WeatherData.vue
@@ -2,10 +2,10 @@
  <el-row class="wrap">
    <el-form :inline="true" class="form">
      <el-form-item label="温度:" class="w-tag">
        {{ temprature }}
        {{ temprature }}℃
      </el-form-item>
      <el-form-item label="湿度:" class="w-tag">
        {{ humidity }}
        {{ humidity }}%
      </el-form-item>
    </el-form>
    <!-- <div class="w-tag">{{ temprature }}</div>
@@ -14,10 +14,10 @@
  <el-row class="wrap">
    <el-form :inline="true" class="form">
      <el-form-item label="风向:" class="w-tag">
        {{ windDirection }}
        {{ _windDir }}
      </el-form-item>
      <el-form-item label="风速:" class="w-tag">
        {{ windSpeed }}
        {{ windSpeed }}m/s
      </el-form-item>
    </el-form>
    <!-- <div class="w-tag">{{ windDirection }}</div>
@@ -26,31 +26,48 @@
</template>
<script>
import { FactorDatas } from '@/model/FactorDatas';
import { windDir } from '../../constant/wind-dir';
export default {
  props: {
    loading: Boolean,
    factorDatas: FactorDatas
    factorDatas: FactorDatas,
    temprature: {
      type: String,
      default: '--'
    },
    humidity: {
      type: String,
      default: '--'
    },
    windDirection: {
      type: String,
      default: '--'
    },
    windSpeed: {
      type: String,
      default: '--'
    }
  },
  data() {
    return {
      temprature: '--℃',
      humidity: '--%',
      windDirection: '--',
      windSpeed: '--m/s'
    };
    return {};
  },
  watch: {
    factorDatas: {
      handler(nV) {
        this.temprature = this.lastOne(nV, '8') + '℃';
        this.humidity = this.lastOne(nV, '9') + '%';
        this.windDirection = this.lastOne(nV, '17');
        this.windSpeed = this.lastOne(nV, '16') + 'm/s';
        // this.temprature = this.lastOne(nV, '8') + '℃';
        // this.humidity = this.lastOne(nV, '9') + '%';
        // this.windDirection = this.lastOne(nV, '17');
        // this.windSpeed = this.lastOne(nV, '16') + 'm/s';
      },
      deep: true
    }
  },
  computed: {
    _windDir() {
      return windDir(this.windDirection);
    }
  },
  methods: {
    lastOne(factorDatas, key) {
      const f = factorDatas.factor[key];
src/components/search/OptionDevice.vue
@@ -31,10 +31,11 @@
    deviceList() {
      const t = this.type ? this.type : '0a';
      return [1, 2, 3].map((v) => {
        const text = `${t}000000000${v}`;
        const label = `${this.getDeviceType(t)}设备${v}号`;
        const value = `${t}000000000${v}`;
        return {
          label: text,
          value: text
          label: label,
          value: value
        };
      });
    }
@@ -49,6 +50,18 @@
  methods: {
    handleChange(value) {
      this.$emit('update:modelValue', value);
    },
    getDeviceType(t) {
      switch (t) {
        case '0a':
          return '车载';
        case '0b':
          return '无人机';
        case '0c':
          return '无人船';
        default:
          return '车载';
      }
    }
  },
  mounted() {
src/model/FrameAnimation.js
@@ -17,6 +17,7 @@
  this.isPause = false;
  this.isRunning = false;
  this.isStop = false;
  // æ˜¯å¦å¼€å¯åŠ¨æ€ç»˜åˆ¶é€Ÿåº¦
  this.dynamicSpeed = false;
  // æ¯ä¸ªä»»åŠ¡è€—æ—¶ï¼ˆç§’ï¼‰
@@ -29,6 +30,7 @@
  start: function () {
    if (this.intervalFlag != undefined) {
      this.isPause = false;
      this.isStop = false;
    } else {
      this.isRunning = true;
      this._doTask();
@@ -85,7 +87,9 @@
    this.isRunning = false;
    this.isPause = false;
    this.isStop = true;
    this.lastestTime = undefined;
    this.speed = 1;
  },
  setOnStopCallback: function (callback) {
    this.onStopCallback = callback;
@@ -127,7 +131,6 @@
        t.task(t.data, index, t.count);
        index += this.speed;
        // console.log("_doTask:" + index);
      }, this.timeout);
    }
  },
src/utils/map/animation.js
@@ -21,6 +21,7 @@
  this._fps = this.frameAnimation.fps;
  // ç»˜åˆ¶å›¾å½¢ç¼“å­˜
  this.moveViews = {};
  this.clear = true;
}
MapAnimation.prototype = {
@@ -159,6 +160,15 @@
            Layer.drawMesh(d, f);
            // é£Žå‘风速
            sector.drawSectorAna(d, start + index);
            // æ‰§è¡Œç›‘听函数
            if (typeof that.OnEachFrameCallback === 'function') {
              that.OnEachFrameCallback(d, start + index);
            }
            // ç»˜åˆ¶3D图形时,最少需要2个点才可绘制图形
            // å› æ­¤æ­¤å¤„索引只到倒数第二个点就结束,此时执行这段任务结束的监听回调
            if (typeof that.OnEachTaskEndCallback === 'function') {
              that.OnEachTaskEndCallback(d);
            }
          }
          var pos = d.lnglats_GD[d.lnglats_GD.length - 1];
@@ -200,9 +210,27 @@
    this.start();
  },
  /**
   * è®¾ç½®æ¯ä¸€å¸§çš„监听函数
   * @param {Function} callback
   */
  setOnEachFrameCallback(callback) {
    this.OnEachFrameCallback = callback;
  },
  /**
   * è®¾ç½®æ¯ä¸€æ®µä»»åŠ¡ç»“æŸçš„ç›‘å¬å‡½æ•°
   * @param {Function} callback
   */
  setOnEachTaskEndCallback(callback) {
    this.OnEachTaskEndCallback = callback;
  },
  /*******************************动画任务逻辑 -start ******************************/
  start: function () {
    sector.clearSector();
    if (this.frameAnimation.isStop) {
      sector.clearSector();
    }
    this.frameAnimation.start();
  },
  changeSpeed: function (speed) {
@@ -214,6 +242,8 @@
  stop: function () {
    this.factorDatas = undefined;
    this.frameAnimation.addOnNextTasks(undefined);
    // this.OnEachFrameCallback = undefined;
    // this.OnEachTaskEndCallback = undefined;
    this.frameAnimation.stop();
  },
  setOnStopCallback: function (callback) {
@@ -242,6 +272,8 @@
  /*******************************动画任务逻辑 -end ******************************/
  _clearMap: function () {
    if (!this.clear) return;
    var list = [];
    for (const key in this.moveViews) {
      list.push(this.moveViews[key]);
@@ -386,4 +418,7 @@
  }
};
export { MapAnimation };
const realTimeMapAnimation = new MapAnimation();
realTimeMapAnimation.clear = false;
export { realTimeMapAnimation, MapAnimation };
src/views/historymode/HistoryMode.vue
@@ -106,12 +106,7 @@
    },
    // ç»˜åˆ¶3D走行路线图
    drawRoadMap(e) {
      //   this.factorMode = factorMode;
      // this.factorType = factorType;
      // this.factorName = factorName;
      this.factorDatas.refreshHeight(this.factorType);
      // this.mapMaker.setFactorType(factorType);
      // if (!this.mapMaker.runStatus()) {
      Layer.drawRoadMap(this.factorDatas, e, this.merge, this.setCenter);
      // }
@@ -125,7 +120,7 @@
      });
    },
    drawSector(index) {
      // 1. ç»˜åˆ¶æ‰‡å½¢åŒºåŸŸ
      // 1. ç»˜åˆ¶æ–°æ‰‡å½¢åŒºåŸŸ
      sector.drawSector(this.factorDatas, index);
      // 2. ç»˜åˆ¶å¯¹è¯æ¡†
      DialogUtil.openNewWindow(this.factorDatas, index, () => {
src/views/realtimemode/RealtimeMode.vue
@@ -1,6 +1,8 @@
<template>
  <div class="p-events-none m-t-2">
    <el-row justify="center" align="middle" class="top-wrap"> </el-row>
    <el-row justify="center" align="middle" class="top-wrap">
      <DeviceChange @change="onDeviceChange"></DeviceChange>
    </el-row>
    <el-row class="m-t-2">
      <FactorRadio
        :device-type="deviceType"
@@ -13,9 +15,7 @@
        :factor="factorDatas.factor[factorType]"
      ></FactorLegend>
    </el-row>
    <el-row class="m-t-2" justify="start">
      <DashBoard :factor-datas="factorDatas"></DashBoard>
    </el-row>
    <DashBoard class="dash-board" :factor-datas="factorDatas"></DashBoard>
    <RealTimeTrend
      class="real-time-trend"
      :factor-datas="factorDatas"
@@ -31,12 +31,13 @@
import monitorDataApi from '@/api/monitorDataApi';
import DashBoard from './component/DashBoard.vue';
import RealTimeTrend from './component/RealTimeTrend.vue';
import { MapAnimation } from '@/utils/map/animation';
import DeviceChange from './component/DeviceChange.vue';
import { realTimeMapAnimation } from '@/utils/map/animation';
const mapAnimation = new MapAnimation();
// const mapAnimation = new MapAnimation();
export default {
  components: { DashBoard, RealTimeTrend },
  components: { DashBoard, RealTimeTrend, DeviceChange },
  setup() {
    const { loading, fetchData } = useFetchData(10000);
    return { loading, fetchData };
@@ -54,16 +55,33 @@
      allFactorDatas: new FactorDatas()
    };
  },
  watch: {
    factorType(nV, oV) {
      if (nV != oV) {
        realTimeMapAnimation.setFactorType(nV);
      }
    }
  },
  computed: {
    latestTime() {
      if (this.factorDatas.times.length == 0) {
        return '----/--/-- --:--:--';
        return '';
      } else {
        return this.factorDatas.times[this.factorDatas.times.length - 1];
      }
    }
  },
  methods: {
    onDeviceChange({ type, deviceCode }) {
      this.deviceType = type;
      this.deviceCode = deviceCode;
      this.clearFetchingTask();
      realTimeMapAnimation.stop();
      this.allFactorDatas.clearData();
      this.factorDatas.clearData();
      this.notFirstFetch = false;
      this.fetchRealTimeData();
    },
    onFetchData(data) {
      // todo æ ¹æ®è®¾å¤‡ç±»åž‹åˆ‡æ¢åœ°å›¾ç›‘测因子展示单选框、折线图复选框、数据表格复选框的因子类型
      // this.deviceType = type;
@@ -80,7 +98,7 @@
        return monitorDataApi
          .fetchHistroyData({
            deviceCode: this.deviceCode,
            startTime: '2021-11-04 09:53:35',
            // startTime: '2021-11-04 09:53:35',
            page,
            perPage: 100
          })
@@ -94,6 +112,7 @@
    clearFetchingTask() {
      if (this.fetchingTask) {
        clearInterval(this.fetchingTask);
        this.fetchingTask = undefined;
      }
    },
    fetchNextData() {
@@ -109,7 +128,7 @@
            .fetchNextData({
              deviceCode: this.deviceCode,
              updateTime: this.latestTime,
              perPage: 2
              perPage: 10
            })
            .then((res) => {
              this.onFetchData(res.data);
@@ -126,12 +145,14 @@
        this.notFirstFetch = true;
      }
      startIndex = startIndex < 0 ? 0 : startIndex;
      this.allFactorDatas.addData(dataList, this.drawMode, () => {
        mapAnimation.moveAnimation(
          this.allFactorDatas,
          this.factorType,
          startIndex
        );
      return new Promise((resolve, reject) => {
        this.allFactorDatas.addData(dataList, this.drawMode, () => {
          realTimeMapAnimation.moveAnimation(
            this.allFactorDatas,
            this.factorType,
            startIndex
          );
        });
      });
    }
  },
@@ -140,11 +161,16 @@
  },
  unmounted() {
    this.clearFetchingTask();
    mapAnimation.stop();
    realTimeMapAnimation.stop();
  }
};
</script>
<style scoped>
.dash-board {
  position: absolute;
  left: 0;
  bottom: 2px;
}
.real-time-trend {
  position: absolute;
  right: 0;
src/views/realtimemode/component/DashBoard.vue
@@ -3,8 +3,17 @@
    <el-col v-show="show" span="10">
      <BaseCard>
        <template #content>
          <WeatherData :factor-datas="factorDatas"></WeatherData>
          <VehicleData :factor-datas="factorDatas"></VehicleData>
          <WeatherData
            :factor-datas="factorDatas"
            :temprature="temprature"
            :humidity="humidity"
            :wind-direction="windDirection"
            :wind-speed="windSpeed"
          ></WeatherData>
          <VehicleData :factor-datas="factorDatas" :speed="speed"></VehicleData>
          <el-row justify="center">
            <div class="tag-time">时间:{{ time }}</div>
          </el-row>
        </template>
      </BaseCard>
    </el-col>
@@ -15,6 +24,7 @@
</template>
<script>
import { FactorDatas } from '@/model/FactorDatas';
import { realTimeMapAnimation } from '@/utils/map/animation';
export default {
  props: {
@@ -25,8 +35,39 @@
  },
  data() {
    return {
      show: true
      show: true,
      temprature: '--',
      humidity: '--',
      windDirection: '--',
      windSpeed: '--',
      speed: '0',
      time: '----/--/--'
    };
  },
  methods: {
    getFactorData(factorDatas, index, key, scale = 10) {
      let d = factorDatas.factor[key].datas[index].factorData;
      return Math.round(d * scale) / scale;
    },
    refresh(factorDatas, index) {
      this.temprature = this.getFactorData(factorDatas, index, '8') + '';
      this.humidity = this.getFactorData(factorDatas, index, '9') + '';
      this.windDirection = this.getFactorData(factorDatas, index, '17') + '';
      this.windSpeed = this.getFactorData(factorDatas, index, '16') + '';
      this.speed = this.getFactorData(factorDatas, index, '14', 1);
      this.time = factorDatas.times[index];
    }
  },
  mounted() {
    realTimeMapAnimation.setOnEachFrameCallback(this.refresh);
  }
};
</script>
<style scoped>
.tag-time {
  padding: 2px 4px;
  border: 1px solid white;
  border-radius: 2px;
  -moz-border-radius: 25px;
}
</style>
src/views/realtimemode/component/DeviceChange.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
<template>
  <BaseCard size="middle-s" direction="down">
    <template #content>
      <el-form :inline="true">
        <OptionType v-model="formSearch.type"></OptionType>
        <OptionDevice
          :type="formSearch.type"
          v-model="formSearch.deviceCode"
        ></OptionDevice>
        <el-button type="primary" class="el-button-custom" @click="handleClick">
          åˆ‡æ¢
        </el-button>
      </el-form>
    </template>
  </BaseCard>
</template>
<script>
// æœç´¢æ¡†
export default {
  data() {
    return {
      formSearch: {
        type: '',
        deviceCode: ''
      }
    };
  },
  emits: ['change'],
  methods: {
    handleClick() {
      this.$emit('change', this.formSearch);
    }
  }
};
</script>
<style lang="scss">
.map-date-selector {
  display: inline-block;
  position: relative;
  /* left: 0;
      right: 0;
      top: 0px; */
  /* padding: 0 4px; */
  /* color: ffffffbd; */
  /* background-color: antiquewhite; */
}
</style>