riku
2025-02-13 660021a28de9b84b4362c171fdbbf89587f0c5af
1. 修改部分bug
2. 新增2D路线轨迹绘制
已修改11个文件
已添加5个文件
已重命名1个文件
488 ■■■■■ 文件已修改
src/api/missionApi.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components.d.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/mission/MissionEdit.vue 43 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/mission/MissionManage.vue 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/monitor/DataTable.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/constant/checkbox-options.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/constant/checkbox-options/options.js 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/stores/mission.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/color.js 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/calculate.js 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/grid.js 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/line.js 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/marks.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/HomePage.vue 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/historymode/HistoryMode.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/satellitetelemetry/SatelliteTelemetry.vue 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/grid_test_data.js 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/missionApi.js
@@ -15,6 +15,10 @@
    return $http.post(`air/mission/create`, mission).then((res) => res.data);
  },
  updateMission(mission) {
    return $http.post(`air/mission/update`, mission).then((res) => res.data);
  },
  deleteMission(missionCode) {
    let params = `missionCode=${missionCode}`;
    return $http.post(`air/mission/delete?${params}`).then((res) => res.data);
src/components.d.ts
@@ -56,7 +56,7 @@
    MapScene: typeof import('./components/map/MapScene.vue')['default']
    MapToolbox: typeof import('./components/map/MapToolbox.vue')['default']
    MessageBox: typeof import('./components/MessageBox.vue')['default']
    MissionCreate: typeof import('./components/mission/MissionCreate.vue')['default']
    MissionEdit: typeof import('./components/mission/MissionEdit.vue')['default']
    MissionImport: typeof import('./components/mission/MissionImport.vue')['default']
    MissionManage: typeof import('./components/mission/MissionManage.vue')['default']
    OptionDevice: typeof import('./components/search/OptionDevice.vue')['default']
src/components/mission/MissionEdit.vue
ÎļþÃû´Ó src/components/mission/MIssionCreate.vue ÐÞ¸Ä
@@ -1,12 +1,5 @@
<template>
  <el-button
    type="primary"
    class="el-button-custom"
    @click="dialogVisible = !dialogVisible"
  >
    æ–°å»ºä»»åŠ¡
  </el-button>
  <CardDialog v-model="dialogVisible" title="新建走航任务">
  <CardDialog v-model="visible" title="新建走航任务">
    <el-form
      :inline="false"
      :model="formObj"
@@ -50,6 +43,22 @@
      </el-form-item>
    </el-form>
  </CardDialog>
  <el-button
    v-if="mode == 'create'"
    type="primary"
    class="el-button-custom"
    @click="visible = !visible"
  >
    æ–°å»ºä»»åŠ¡
  </el-button>
  <el-button
    v-else
    type="primary"
    size="small"
    icon="EditPen"
    class="el-button-custom"
    @click="visible = !visible"
  ></el-button>
</template>
<script setup>
import moment from 'moment';
@@ -60,8 +69,20 @@
import { useFetchData } from '@/composables/fetchData';
import { useMissionStore } from '@/stores/mission';
const props = defineProps({
  // èµ°èˆªä»»åŠ¡ç¼–è¾‘æ¨¡å¼ï¼Œæ–°å»ºæˆ–æ›´æ–°
  mode: {
    type: String,
    default: 'create'
  }
  // visible: {
  //   type: String,
  //   default: 'create'
  // }
});
const missionStore = useMissionStore();
const dialogVisible = ref(false);
const visible = ref(false);
const { loading, fetchData } = useFetchData();
const rules = reactive({
  location: [
@@ -113,7 +134,7 @@
function createMission() {
  fetchData((page, pageSize) => {
    return missionApi.putNewMission(param.value).then((res) => {
      dialogVisible.value = false;
      visible.value = false;
      missionStore.fetchMission();
      // é€šçŸ¥æœåŠ¡ç«¯å¯åŠ¨ä»»åŠ¡èŒƒå›´å†…çš„ç¬¬ä¸‰æ–¹æ•°æ®èŽ·å–ä»»åŠ¡
      thirdPartyDataApi.fetchMissionData(param.value.missionCode);
@@ -126,7 +147,7 @@
  },
  cancel: {
    do: () => {
      dialogVisible.value = false;
      visible.value = false;
    }
  }
});
src/components/mission/MissionManage.vue
@@ -21,7 +21,7 @@
          :show-overflow-tooltip="true"
          border
          height="64vh"
          row-class-name="t-row"
          row-class-name="t-row-normal"
          cell-class-name="t-cell"
          header-row-class-name="t-header-row"
          header-cell-class-name="t-header-cell"
@@ -38,41 +38,44 @@
            label="开始时间"
            align="center"
            :formatter="timeFormatter"
            width="150"
          />
          <el-table-column
            prop="endTime"
            label="结束时间"
            align="center"
            :formatter="timeFormatter"
            width="150"
          />
          <el-table-column label="管理" width="140" align="center">
          <el-table-column label="管理" width="160" align="center">
            <template #default="{ row }">
              <MissionEdit mode="update"></MissionEdit>
              <el-button
                type="primary"
                size="small"
                icon="Delete"
                class="el-button-custom"
                @click="deleteMission(row)"
                >删除</el-button
              >
              ></el-button>
              <el-button
                :loading="row.downloadLoading"
                type="primary"
                size="small"
                icon="Document"
                class="el-button-custom"
                @click="downloadReport(row)"
                >报告</el-button
              >
              ></el-button>
            </template>
          </el-table-column>
        </el-table>
      </el-col>
      <el-col :span="4" class="flex-col">
        <div>
          <!-- <el-button type="primary" class="el-button-custom">
        <!-- <div> -->
        <!-- <el-button type="primary" class="el-button-custom">
                æ–°å»ºä»»åŠ¡
              </el-button> -->
          <MissionCreate></MissionCreate>
        </div>
        <MissionEdit></MissionEdit>
        <!-- </div> -->
        <!-- <div>
          <el-button type="primary" class="el-button-custom">
            æ•°æ®å¯¼å…¥
@@ -166,4 +169,8 @@
.mission-table {
  /* height: 60vh; */
}
:deep(.t-row-normal) {
  background-color: transparent !important;
}
</style>
src/components/monitor/DataTable.vue
@@ -177,7 +177,7 @@
    //   }
    // },
    tableColumn() {
      return checkboxOptions(this.deviceType);
      return checkboxOptions(this.deviceType, true);
    }
  },
  methods: {
src/constant/checkbox-options.js
@@ -1,6 +1,7 @@
import { TYPE0, TYPE1, TYPE2, TYPE4 } from '@/constant/device-type';
import {
  option1,
  option1All,
  default1,
  option2,
  option3,
@@ -13,7 +14,7 @@
} from '@/constant/checkbox-options/options-jingan';
// ç›‘测因子单选框选项
function checkboxOptions(deviceType) {
function checkboxOptions(deviceType, allOptions) {
  if (import.meta.env.VITE_DATA_MODE == 'jingan') {
    switch (deviceType) {
      case TYPE0:
@@ -24,7 +25,7 @@
  } else {
    switch (deviceType) {
      case TYPE0:
        return option1;
        return allOptions ? option1All : option1;
      case TYPE1:
        return option3;
      case TYPE2:
src/constant/checkbox-options/options.js
@@ -71,6 +71,95 @@
  // }
];
const option1All = [
  {
    label: 'NO2',
    name: 'NO2',
    value: '1'
  },
  {
    label: 'CO',
    name: 'CO',
    value: '2'
  },
  {
    label: 'H2S',
    name: 'H2S',
    value: '3'
  },
  {
    label: 'SO2',
    name: 'SO2',
    value: '4'
  },
  {
    label: 'O3',
    name: 'O3',
    value: '5'
  },
  {
    label: 'PM2.5',
    name: 'PM25',
    value: '6'
  },
  {
    label: 'PM10',
    name: 'PM10',
    value: '7'
  },
  {
    label: '温度',
    name: 'TEMPERATURE',
    value: '8'
  },
  {
    label: '湿度',
    name: 'HUMIDITY',
    value: '9'
  },
  {
    label: 'TVOC',
    name: 'VOC',
    value: '10'
  },
  // {
  //     label: "NOI",
  //     name: "NOI",
  //     value: "11"
  // },
  {
    label: '经度',
    name: 'LNG',
    value: '12'
  },
  {
    label: '纬度',
    name: 'LAT',
    value: '13'
  },
  {
    label: '车速',
    name: 'VELOCITY',
    value: '14'
  },
  {
    label: '风速',
    name: 'WIND_SPEED',
    value: '16'
  },
  {
    label: '风向',
    name: 'WIND_DIRECTION',
    value: '17'
  }
  // {
  //   label: '高度',
  //   name: 'HEIGHT',
  //   value: '18'
  // }
];
// é»˜è®¤é€‰é¡¹
const default1 = [option1[5].value, option1[6].value, option1[7].value];
@@ -181,4 +270,4 @@
  }
];
export { option1, default1, option2, option3, default3, option4 };
export { option1, option1All, default1, option2, option3, default3, option4 };
src/stores/mission.js
@@ -6,7 +6,7 @@
// èµ°èˆªä»»åŠ¡
export const useMissionStore = defineStore('mission', () => {
  const missionList = ref([]);
  const { loading, fetchData } = useFetchData();
  const { loading, fetchData } = useFetchData(1000);
  function fetchMission(type) {
    return fetchData((page, pageSize) => {
src/utils/color.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
//转化颜色
function getHexColor(values) {
  // ä¼ çš„color须为字符串
  // var values = color
  //   .replace(/rgba?\(/, '')  // æŠŠ "rgba(" åŽ»æŽ‰ï¼Œå˜æˆ  "194, 7, 15, 1)"
  //   .replace(/\)/, '')         // æŠŠ ")" åŽ»æŽ‰ï¼Œå˜æˆ "194, 7, 15, 1"
  //   .replace(/[\s+]/g, '')   // æŠŠç©ºæ ¼åŽ»æŽ‰ï¼Œå˜æˆ "194,7,15,1"
  //   .split(',')                 // å˜æˆæ•°ç»„ [194,7,15,1]
  var a = parseFloat(values[3] || 1), // values[3]是rgba中的a值,没有的话设置a为1,a可能为小数,所以用parseFloat函数
    r = Math.floor(a * parseInt(values[0]) + (1 - a) * 255), // è½¬æ¢ä¸º16进制
    g = Math.floor(a * parseInt(values[1]) + (1 - a) * 255),
    b = Math.floor(a * parseInt(values[2]) + (1 - a) * 255);
  return (
    '#' +
    ('0' + r.toString(16)).slice(-2) + // è½¬æ¢åŽçš„16进制可能为一位,比如 7 å°±è½¬æ¢ä¸º 7 ï¼Œ 15 è½¬æ¢ä¸º f
    ('0' + g.toString(16)).slice(-2) + // å½“为一位的时候就在前面加个 0,
    ('0' + b.toString(16)).slice(-2)
  ); // è‹¥æ˜¯ä¸ºä¸¤ä½ï¼ŒåŠ  0 åŽå°±å˜æˆäº†ä¸‰ä½ï¼Œæ‰€ä»¥è¦ç”¨ slice(-2) æˆªå–后两位
}
//计算线性渐变的中间颜色值
function getColorBetweenTwoColors(colorA, colorB, ratio) {
  const r = Math.round((colorB[0] - colorA[0]) * ratio + colorA[0]);
  const g = Math.round((colorB[1] - colorA[1]) * ratio + colorA[1]);
  const b = Math.round((colorB[2] - colorA[2]) * ratio + colorA[2]);
  return getHexColor([r, g, b, 1]);
}
export { getHexColor, getColorBetweenTwoColors };
src/utils/map/calculate.js
@@ -197,5 +197,24 @@
      let mglng = Math.round((lng * 2 - lng - dlng) * 1000000) / 1000000;
      return [mglng, mglat];
    }
  },
  //从GPS转高德
  wgs84_To_Gcj02(lon, lat) {
    if (out_of_china(lon, lat)) {
      return [lon, lat];
    } else {
      let dLat = transformlat(lon - 105.0, lat - 35.0);
      let dLon = transformlng(lon - 105.0, lat - 35.0);
      let radLat = (lat / 180.0) * PI;
      let magic = Math.sin(radLat);
      magic = 1 - ee * magic * magic;
      let sqrtMagic = Math.sqrt(magic);
      dLat = (dLat * 180.0) / (((a * (1 - ee)) / (magic * sqrtMagic)) * PI);
      dLon = (dLon * 180.0) / ((a / sqrtMagic) * Math.cos(radLat) * PI);
      let mgLat = lat + dLat;
      let mgLon = lon + dLon;
      return [mgLon, mgLat];
    }
  }
};
src/utils/map/grid.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,52 @@
/**
 * ç½‘格绘制
 */
import { map } from './index_old';
export default {
  /**
   * ç»˜åˆ¶ç½‘格风险图
   * @param {*} points
   */
  drawRectangle: function (points) {
    const gridViews = [];
    points.forEach((p) => {
      const { lb, rt, c } = p;
      // eslint-disable-next-line no-undef
      let pList = [lb, rt].map((v) => new AMap.LngLat(v[0], v[1]));
      // eslint-disable-next-line no-undef
      var bounds = new AMap.Bounds(...pList);
      // eslint-disable-next-line no-undef
      var rectangle = new AMap.Rectangle({
        bounds: bounds,
        // strokeColor: '#ffffffff',
        strokeWeight: 0,
        strokeOpacity: 0,
        // strokeStyle还支持 solid
        strokeStyle: 'solid',
        fillColor: '990D0D',
        fillOpacity: 0.8,
        cursor: 'pointer',
        zIndex: 50
      });
      // var text = new AMap.Text({
      //   text: p.value,
      //   anchor: 'center', // è®¾ç½®æ–‡æœ¬æ ‡è®°é”šç‚¹
      //   draggable: false,
      //   style: {
      //     'background-color': 'transparent',
      //     'border-width': 0,
      //     'text-align': 'center',
      //     'font-size': '12px',
      //     color: 'white'
      //   },
      //   position: c
      // });
      gridViews.push(rectangle);
      // that.textView.push(text);
    });
    map.add(gridViews);
  }
};
src/utils/map/line.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
import { map } from './index_old';
import calculate from './calculate';
import { getHexColor } from '../color';
var _polylineArr = [];
export default {
  drawLine(fDatas, factor) {
    const lnglats_GD = fDatas.lnglats_GD;
    const colors = factor.colors;
    if (_polylineArr) {
      map.remove(_polylineArr);
      _polylineArr = [];
    }
    var path = calculate.parse2LngLat(lnglats_GD);
    let sIndex = 0;
    for (let i = 1; i < path.length; i++) {
      // if (colors[i] == colors[i - 1]) {
      // } else {
      // }
      const _path = [path[i], path[i + 1]];
      const _color = getHexColor(colors[i + 1].map((v) => v * 255));
      // åˆ›å»ºæŠ˜çº¿å®žä¾‹
      // eslint-disable-next-line no-undef
      const polyline = new AMap.Polyline({
        path: _path,
        strokeStyle: 'solid',
        isOutline: true,
        borderWeight: 2,
        outlineColor: 'white',
        strokeWeight: 4, // çº¿æ¡å®½åº¦ï¼Œé»˜è®¤ä¸º 1
        strokeColor: _color, // çº¿æ¡é¢œè‰²
        lineJoin: 'round', // æŠ˜çº¿æ‹ç‚¹è¿žæŽ¥å¤„样式
        showDir: true
      });
      _polylineArr.push(polyline);
    }
    // å°†æŠ˜çº¿æ·»åŠ è‡³åœ°å›¾å®žä¾‹
    map.add(_polylineArr);
    return _polylineArr;
  }
};
src/utils/map/marks.js
@@ -25,7 +25,7 @@
    for (let i = 0; i < lnglats.length; i++) {
      data.push({
        lnglat: lnglats[i], //点标记位置
        name: `${fDatas.times[i]}<br/>${_factor.factorName}: ${_factor.datas[i].factorData} mg/m³`,
        name: `${fDatas.times[i]}<br/>${_factor.factorName}: ${_factor.datas[i].factorData} Î¼g/m³`,
        id: i
      });
    }
src/views/HomePage.vue
@@ -4,6 +4,7 @@
    <CoreHeader></CoreHeader>
    <el-row class="dropdown-wrap">
      <MapToolbox></MapToolbox>
      <!-- <SatelliteTelemetry></SatelliteTelemetry> -->
      <!-- <MissionManage></MissionManage> -->
      <ConfigManage></ConfigManage>
      <!-- <MapLocation></MapLocation> -->
@@ -15,7 +16,9 @@
  </div>
</template>
<script setup></script>
<script setup>
import SatelliteTelemetry from '@/views/satellitetelemetry/SatelliteTelemetry.vue';
</script>
<style scoped>
.overlay-container {
src/views/historymode/HistoryMode.vue
@@ -49,6 +49,7 @@
<script>
import Layer from '@/utils/map/3dLayer';
import mapLine from '@/utils/map/line';
import marks from '@/utils/map/marks';
import sector from '@/utils/map/sector';
import mapUtil from '@/utils/map/util';
@@ -137,7 +138,8 @@
      // åˆ·æ–°å›¾ä¾‹
      const factor = this.factorDatas.factor[this.factorType];
      sector.clearSector();
      this.drawRoadMap(factor);
      this.drawRoadLine(factor);
      // this.drawRoadMap(factor);
      this.drawMassMarks(factor);
    },
    // ç»˜åˆ¶3D走行路线图
@@ -145,7 +147,9 @@
      this.factorDatas.refreshHeight(this.factorType);
      Layer.drawRoadMap(this.factorDatas, e, this.merge, this.setCenter);
      // }
    },
    drawRoadLine(e) {
      mapLine.drawLine(this.factorDatas, e);
    },
    drawMassMarks(e) {
      marks.drawMassMarks(this.factorDatas, e, (index) => {
src/views/satellitetelemetry/SatelliteTelemetry.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
<template>
  <div class="p-events-auto">
    <el-button type="info" icon="Memo" plain @click="drawGrid">
      ç»˜åˆ¶ç½‘æ ¼
    </el-button>
  </div>
</template>
<script setup>
import calculate from '@/utils/map/calculate';
import grid from '@/utils/map/grid';
import { gridData } from '../../../test/grid_test_data';
function drawGrid() {
  // const points = gridData.map((v) => {
  //   return calculate.wgs84_To_Gcj02(v[0], v[1]);
  // });
  // const p1 = points[0];
  // const p2 = points[1];
  // const diffLng = Math.abs(p1[0] - p2[0]);
  // const diffLat = Math.abs(p1[1] - p2[1]);
  // const bounds = points.map((v) => {
  //   return {
  //     // ä¸œç»ï¼ŒåŒ—纬情况下
  //     lb: [v[0] - diffLng, v[1] - diffLat],
  //     rt: [v[0] + diffLng, v[1] - diffLat],
  //     c: v
  //   };
  // });
  const bounds = [
    {
      lb: [121.360898, 31.222733],
      rt: [121.364898, 31.226733],
      c: [121.362898, 31.224733]
    }
  ];
  grid.drawRectangle(bounds);
}
</script>
test/grid_test_data.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,112 @@
const gridData = [
  [121.329723, 31.240625],
  [121.339366, 31.241204],
  [121.34901, 31.241781],
  [121.358654, 31.242358],
  [121.368299, 31.242935],
  [121.377943, 31.24351],
  [121.387588, 31.244085],
  [121.397234, 31.244659],
  [121.406879, 31.245233],
  [121.416525, 31.245805],
  [121.426171, 31.246377],
  [121.435818, 31.246949],
  [121.330396, 31.232339],
  [121.340039, 31.232918],
  [121.349682, 31.233495],
  [121.359325, 31.234072],
  [121.368969, 31.234648],
  [121.378613, 31.235223],
  [121.388257, 31.235798],
  [121.397901, 31.236372],
  [121.407546, 31.236945],
  [121.417191, 31.237518],
  [121.426836, 31.23809],
  [121.436482, 31.238661],
  [121.331069, 31.224054],
  [121.340711, 31.224632],
  [121.350353, 31.225209],
  [121.359996, 31.225786],
  [121.369639, 31.226362],
  [121.379282, 31.226937],
  [121.388925, 31.227511],
  [121.398569, 31.228085],
  [121.408213, 31.228658],
  [121.417857, 31.22923],
  [121.427501, 31.229802],
  [121.437146, 31.230373],
  [121.331742, 31.215768],
  [121.341383, 31.216346],
  [121.351025, 31.216923],
  [121.360666, 31.217499],
  [121.370308, 31.218075],
  [121.379951, 31.21865],
  [121.389593, 31.219224],
  [121.399236, 31.219798],
  [121.408879, 31.220371],
  [121.418522, 31.220943],
  [121.428166, 31.221514],
  [121.43781, 31.222085],
  [121.332415, 31.207482],
  [121.342055, 31.20806],
  [121.351696, 31.208637],
  [121.361337, 31.209213],
  [121.370978, 31.209788],
  [121.380619, 31.210363],
  [121.390261, 31.210937],
  [121.399903, 31.211511],
  [121.409545, 31.212083],
  [121.419188, 31.212655],
  [121.42883, 31.213227],
  [121.438473, 31.213797],
  [121.333087, 31.199196],
  [121.342727, 31.199774],
  [121.352366, 31.20035],
  [121.362006, 31.200926],
  [121.371647, 31.201502],
  [121.381287, 31.202076],
  [121.390928, 31.20265],
  [121.400569, 31.203224],
  [121.410211, 31.203796],
  [121.419853, 31.204368],
  [121.429494, 31.204939],
  [121.439137, 31.205509],
  [121.333759, 31.19091],
  [121.343398, 31.191488],
  [121.353037, 31.192064],
  [121.362676, 31.19264],
  [121.372316, 31.193215],
  [121.381955, 31.19379],
  [121.391595, 31.194363],
  [121.401236, 31.194936],
  [121.410876, 31.195509],
  [121.420517, 31.19608],
  [121.430158, 31.196651],
  [121.4398, 31.197221],
  [121.334431, 31.182624],
  [121.344069, 31.183201],
  [121.353707, 31.183778],
  [121.363345, 31.184354],
  [121.372984, 31.184928],
  [121.382623, 31.185503],
  [121.392262, 31.186076],
  [121.401902, 31.186649],
  [121.411542, 31.187221],
  [121.421182, 31.187793],
  [121.430822, 31.188363],
  [121.440462, 31.188933],
  [121.335103, 31.174338],
  [121.34474, 31.174915],
  [121.354377, 31.175492],
  [121.364015, 31.176067],
  [121.373652, 31.176642],
  [121.38329, 31.177216],
  [121.392929, 31.177789],
  [121.402568, 31.178362],
  [121.412206, 31.178934],
  [121.421846, 31.179505],
  [121.431485, 31.180076],
  [121.441125, 31.180645]
];
export { gridData };