riku
2024-04-30 add483d13841cf472a9adb5c0cc72454f501fb7c
新增搜索框
已修改10个文件
已添加49个文件
1425 ■■■■■ 文件已修改
.prettierrc.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/missionApi.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/monitorDataApi.js 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/border.css 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/boat_driving.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/border.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/c_level_0.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/c_level_1.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/c_level_2.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/c_level_no.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/car_driving.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/car_offline.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/car_stop.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/company.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/data_chart.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/device.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/dust.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/ic_down_white.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/ic_up_white.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/location.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/oil_paint.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/other_smell.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/plastics.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/pungent.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/scene.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/shrink_left.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/shrink_right.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/slider_handle.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/stink.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/title_bg.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/underway-2.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/underway.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/微信图片_20210608110133.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/微信图片_202106081101331.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mipmap/微信图片_202106081101332.png 补丁 | 查看 | 原始文档 | blame | 历史
src/components.d.ts 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/monitor/FactorRadio.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/search/OptionDevice.vue 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/search/OptionMission.vue 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/search/OptionTime.vue 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/search/OptionType.vue 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/search/SearchBar.vue 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/composables/fetchData.js 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/constant/factor-name.js 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/constant/factor-unit.js 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/constant/wind-dir.js 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/stores/toolbox.js 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/styles/base.scss 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/styles/elementUI.scss 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/styles/index.scss 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/3dLayer.js 155 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/calculate.js 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/dialog.js 260 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/index_old.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/marks.js 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/sector.js 232 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/toolbox.js 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/historymode/HistoryMode.vue 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.prettierrc.json
@@ -3,6 +3,6 @@
  "semi": true,
  "tabWidth": 2,
  "singleQuote": true,
  "printWidth": 100,
  "printWidth": 80,
  "trailingComma": "none"
}
src/api/index.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,84 @@
import axios from 'axios';
import { ElMessage } from 'element-plus';
const debug = false;
let ip1 = 'http://114.215.109.124:8805/';
if (debug) {
  ip1 = 'http://192.168.0.138:8082/';
}
const $http = axios.create({
  baseURL: ip1,
  timeout: 20000
});
//添加拦截器
[$http].forEach((i) => {
  // æ·»åŠ è¯·æ±‚æ‹¦æˆªå™¨
  i.interceptors.request.use(
    function (config) {
      // åœ¨å‘送请求之前做些什么
      console.log('==>请求开始');
      console.log(`${config.baseURL}${config.url}`);
      if (config.data) {
        console.log('==>请求数据', config.data);
      }
      return config;
    },
    function (error) {
      // å¯¹è¯·æ±‚错误做些什么
      console.log('==>请求开始');
      console.log(error);
      ElMessage({
        message: error,
        type: 'error'
      });
      return Promise.reject(error);
    }
  );
  // æ·»åŠ å“åº”æ‹¦æˆªå™¨
  i.interceptors.response.use(
    function (response) {
      // 2xx èŒƒå›´å†…的状态码都会触发该函数。
      // å¯¹å“åº”数据做点什么
      console.log(response);
      console.log('==>请求结束');
      if (response.status == 200) {
        if (
          response.data.success != undefined &&
          response.data.success != null
        ) {
          if (response.data.success == true) {
            return response;
          } else {
            ElMessage({
              message: response.data.message,
              type: 'error'
            });
            return Promise.reject(response.data.message);
          }
        } else {
          return response;
        }
      } else {
        return Promise.reject(response);
      }
    },
    function (error) {
      // è¶…出 2xx èŒƒå›´çš„状态码都会触发该函数。
      // å¯¹å“åº”错误做点什么
      console.log(error);
      console.log('==>请求结束');
      ElMessage({
        message: error,
        type: 'error'
      });
      return Promise.reject(error);
    }
  );
});
export { $http };
src/api/missionApi.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
import { $http } from './index';
/**
 *
 */
export default {
  fethchMission({ type, page, pageSize }) {
    let params = `page=${page}&perPage=${pageSize}`;
    params += type ? `&type=${type}` : '';
    return $http.get(`air/mission/type?${params}`).then((res) => res.data);
  }
};
src/api/monitorDataApi.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
import { $http } from './index';
/**
 *
 */
export default {
  fethcRealtimeData(deviceCode, type, page, perPage) {
    const params = `deviceCode=${deviceCode}&type=${type}&page=${page}&perPage=${perPage}`;
    $http.get(`air/realtime/sec?${params}`);
  }
};
src/assets/border.css
@@ -656,4 +656,5 @@
.ff-toggle-btn-down .ff-border-top .ff-border-content {
    transform: rotateZ(90deg);
}
/*****************按钮区域样式 - end *************************/
src/assets/mipmap/boat_driving.png
src/assets/mipmap/border.png
src/assets/mipmap/c_level_0.png
src/assets/mipmap/c_level_1.png
src/assets/mipmap/c_level_2.png
src/assets/mipmap/c_level_no.png
src/assets/mipmap/car_driving.png
src/assets/mipmap/car_offline.png
src/assets/mipmap/car_stop.png
src/assets/mipmap/company.png
src/assets/mipmap/data_chart.png
src/assets/mipmap/device.png
src/assets/mipmap/dust.png
src/assets/mipmap/ic_down_white.png
src/assets/mipmap/ic_up_white.png
src/assets/mipmap/location.png
src/assets/mipmap/oil_paint.png
src/assets/mipmap/other_smell.png
src/assets/mipmap/plastics.png
src/assets/mipmap/pungent.png
src/assets/mipmap/scene.png
src/assets/mipmap/shrink_left.png
src/assets/mipmap/shrink_right.png
src/assets/mipmap/slider_handle.png
src/assets/mipmap/stink.png
src/assets/mipmap/title_bg.png
src/assets/mipmap/underway-2.png
src/assets/mipmap/underway.png
src/assets/mipmap/΢ÐÅͼƬ_20210608110133.png
src/assets/mipmap/΢ÐÅͼƬ_202106081101331.png
src/assets/mipmap/΢ÐÅͼƬ_202106081101332.png
src/components.d.ts
@@ -13,15 +13,26 @@
    CoreMenu: typeof import('./components/core/CoreMenu.vue')['default']
    ElButton: typeof import('element-plus/es')['ElButton']
    ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
    ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
    ElDropdown: typeof import('element-plus/es')['ElDropdown']
    ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
    ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
    ElForm: typeof import('element-plus/es')['ElForm']
    ElFormItem: typeof import('element-plus/es')['ElFormItem']
    ElIcon: typeof import('element-plus/es')['ElIcon']
    ElOption: typeof import('element-plus/es')['ElOption']
    ElRadio: typeof import('element-plus/es')['ElRadio']
    ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
    ElRow: typeof import('element-plus/es')['ElRow']
    ElSelect: typeof import('element-plus/es')['ElSelect']
    FactorRadio: typeof import('./components/monitor/FactorRadio.vue')['default']
    MapToolbox: typeof import('./components/map/MapToolbox.vue')['default']
    OptionDevice: typeof import('./components/search/OptionDevice.vue')['default']
    OptionMission: typeof import('./components/search/OptionMission.vue')['default']
    OptionTime: typeof import('./components/search/OptionTime.vue')['default']
    OptionType: typeof import('./components/search/OptionType.vue')['default']
    RouterLink: typeof import('vue-router')['RouterLink']
    RouterView: typeof import('vue-router')['RouterView']
    SearchBar: typeof import('./components/search/SearchBar.vue')['default']
  }
}
src/components/monitor/FactorRadio.vue
@@ -23,7 +23,7 @@
  },
  method:{
    handleChange(value) {
      this.$emit('change', value)
      this.$emit('change', value);
      // todo åœ°å›¾3d图像切换展示监测因子
    }
  }
src/components/search/OptionDevice.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,59 @@
<template>
  <el-form-item label="设备">
    <el-select
      :model-value="modelValue"
      @change="handleChange"
      placeholder="设备"
      size="small"
      class="w-120"
    >
      <el-option
        v-for="(s, i) in deviceList"
        :key="i"
        :label="s.label"
        :value="s.value"
      />
    </el-select>
  </el-form-item>
</template>
<script>
export default {
  props: {
    type: String,
    modelValue: String
  },
  emits: ['update:modelValue'],
  data() {
    return {};
  },
  computed: {
    deviceList() {
      const t = this.type ? this.type : '0a';
      return [1, 2, 3].map((v) => {
        const text = `${t}000000000${v}`;
        return {
          label: text,
          value: text
        };
      });
    }
  },
  watch: {
    deviceList(nV, oV) {
      if (nV != oV) {
        this.handleChange(nV[0].value);
      }
    }
  },
  methods: {
    handleChange(value) {
      this.$emit('update:modelValue', value);
    }
  },
  mounted() {
    this.handleChange(this.deviceList[0].value);
  }
};
</script>
<style scoped></style>
src/components/search/OptionMission.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,71 @@
<template>
  <el-form-item label="任务">
    <el-select
      :model-value="modelValue"
      @change="handleChange"
      placeholder="任务"
      size="small"
      class="w-150"
    >
      <el-option
        v-for="(s, i) in missionList"
        :key="i"
        :label="s.label"
        :value="s.value"
      />
    </el-select>
  </el-form-item>
</template>
<script>
import missionApi from '../../api/missionApi';
import { useFetchData } from '@/composables/fetchData';
export default {
  setup() {
    const { loading, fetchData } = useFetchData();
    return { loading, fetchData };
  },
  props: {
    type: String,
    modelValue: String
  },
  emits: ['update:modelValue'],
  data() {
    return {
      missionList: []
    };
  },
  methods: {
    fetchMission() {
      this.fetchData((page, pageSize) => {
        return missionApi
          .fethchMission({ type: this.type, page, pageSize })
          .then((res) => {
            this.missionList = res.data.map((item) => {
              return {
                label: item.missionCode,
                value: item.missionCode
              };
            });
            if (this.missionList.length > 0) {
              this.handleChange(this.missionList[0].value);
            }
            return res.head;
          });
      });
    },
    handleChange(value) {
      this.$emit('update:modelValue', value);
    }
  },
  mounted() {
    this.fetchMission();
  }
};
</script>
<style scoped>
/* :deep() .el-form-item__label {
  color: red !important;
} */
</style>
src/components/search/OptionTime.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
<template>
  <el-form-item label="时间">
    <el-date-picker
      v-model="date"
      @change="handleChange"
      :type="type"
      start-placeholder="选择开始时间"
      end-placeholder="选择结束时间"
      size="small"
      class="w-150"
    />
  </el-form-item>
</template>
<script>
export default {
  props: {
    modelValue: Array,
    type: {
      type: String,
      default: 'datetimerange'
    }
  },
  emits: ['update:modelValue'],
  data() {
    return {
      date: this.modelValue
    };
  },
  methods: {
    handleChange(value) {
      this.$emit('update:modelValue', value);
    }
  },
  mounted() {
    // this.handleChange();
  }
};
</script>
<style scoped></style>
src/components/search/OptionType.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,54 @@
<template>
  <el-form-item label="类型">
    <el-select
      :model-value="modelValue"
      @change="handleChange"
      placeholder="类型"
      size="small"
      class="w-80"
    >
      <el-option
        v-for="(s, i) in typeList"
        :key="i"
        :label="s.label"
        :value="s.value"
      />
    </el-select>
  </el-form-item>
</template>
<script>
export default {
  props: {
    modelValue: String
  },
  emits: ['update:modelValue'],
  data() {
    return {
      typeList: [
        {
          label: '车载',
          value: '0a'
        },
        {
          label: '无人机',
          value: '0b'
        },
        {
          label: '无人船',
          value: '0c'
        }
      ]
    };
  },
  methods: {
    handleChange(value) {
      this.$emit('update:modelValue', value);
    }
  },
  mounted() {
    this.handleChange(this.typeList[0].value);
  }
};
</script>
<style scoped></style>
src/components/search/SearchBar.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
<template>
  <BaseCard class="map-date-selector">
    <template #content>
      <el-form :inline="true">
        <OptionMission v-model="formSearch.missionCode"></OptionMission>
        <OptionType v-model="formSearch.type"></OptionType>
        <OptionDevice
          :type="formSearch.type"
          v-model="formSearch.deviceCode"
        ></OptionDevice>
        <OptionTime v-model="formSearch.timeArray"></OptionTime>
      </el-form>
    </template>
  </BaseCard>
</template>
<script>
// æœç´¢æ¡†
export default {
  data() {
    return {
      formSearch: {
        missionCode: '',
        type: '',
        deviceCode: '',
        timeArray: []
      }
    };
  },
  method: {}
};
</script>
<style scoped></style>
src/composables/fetchData.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
// æŽ¥å£æ•°æ®çš„获取
import { ref, watch, computed } from 'vue';
export function useFetchData(page_size) {
  // åˆ†é¡µä¿¡æ¯
  const page = ref(1);
  const pageNum = ref(1);
  const pageSize = ref(page_size ? page_size : 20);
  const total = ref(0);
  watch(page, (nValue, oValue) => {
    if (nValue != oValue) {
      fetchData();
    }
  });
  watch(pageSize, (nValue, oValue) => {
    if (nValue != oValue) {
      fetchData();
    }
  });
  // åŠ è½½çŠ¶æ€, 0: åŠ è½½å®Œæˆ; 1: åŠ è½½ä¸­; 2: å·²å…¨éƒ¨åŠ è½½; 3: åŠ è½½å¤±è´¥;
  const loadStatus = ref(0);
  const loading = computed(() => {
    return loadStatus.value == 1;
  });
  // æ•°æ®èŽ·å–
  function fetchData(fetch) {
    loadStatus.value = 1;
    fetch(page.value, pageSize.value)
      .then((pageInfo) => {
        if (pageInfo) {
          page.value = pageInfo.page ? pageInfo.page : 1;
          pageNum.value = pageInfo.pageNum ? pageInfo.pageNum : 1;
          total.value = pageInfo.total ? pageInfo.total : 0;
        }
        loadStatus.value = 0;
      })
      .catch(() => {
        loadStatus.value = 3;
      })
      .finally(() => {
        loadStatus.value = 2;
      });
  }
  return { page, pageNum, pageSize, total, loadStatus, loading, fetchData };
}
src/constant/factor-name.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
/**
 * ç›‘测因子名称
 */
export const factorName = {
  NO2: 'NO2', //2
  CO: 'CO', //4
  H2S: 'H2S', //6
  SO2: 'SO2', //3
  O3: 'O3', //1
  PM25: 'PM2.5', //7
  PM10: 'PM10', //8
  TEMPERATURE: '温度',
  HUMIDITY: '湿度',
  VOC: 'TVOC', //5
  // 'NOI': 'NOI', //9
  LNG: '经度',
  LAT: '纬度',
  VELOCITY: '车速',
  TIME: '时间',
  WIND_SPEED: '风速',
  WIND_DIRECTION: '风向',
  HEIGHT: '高度',
  TMP: '温度', //1
  spC: '电导率', //2
  tur: '浊度', //3
  DO: '溶解氧', //4
  PH: 'PH' //5
};
src/constant/factor-unit.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
/**
 * ç›‘测因子单位
 */
export const factorUnit = {
  NO2: 'μg/m³', //2
  CO: 'mg/m³', //4
  H2S: 'μg/m³', //6
  SO2: 'μg/m³', //3
  O3: 'μg/m³', //1
  PM25: 'μg/m³', //7
  PM10: 'μg/m³', //8
  TEMPERATURE: '℃',
  HUMIDITY: '%',
  VOC: 'μg/m³', //5
  NOI: 'μg/m³', //9
  LNG: '',
  LAT: '',
  VELOCITY: 'km/s',
  TIME: '时间',
  WIND_SPEED: 'm/s',
  WIND_DIRECTION: '°',
  HEIGHT: 'm',
  TMP: '℃', //1
  spC: 'μS/cm', //2, ç”µå¯¼çŽ‡ï¼ˆè¥¿é—¨å­/米)
  tur: 'NTU', //3, æµŠåº¦
  DO: 'mg/L', //4, æº¶è§£æ°§
  PH: '' //5
};
src/constant/wind-dir.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
/**
 * é£Žå‘中文转译
 */
export function windDir(angle) {
  if (angle == 0) {
    return '北风';
  } else if (angle > 0 && angle < 90) {
    return '东北风';
  } else if (angle == 90) {
    return '东风';
  } else if (angle > 90 && angle < 180) {
    return '东南风';
  } else if (angle == 180) {
    return '南风';
  } else if (angle > 180 && angle < 270) {
    return '西南风';
  } else if (angle == 270) {
    return '西风';
  } else if (angle > 270 && angle < 360) {
    return '西北风';
  }
}
src/stores/toolbox.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
import { ref } from 'vue';
import { defineStore } from 'pinia';
export const useToolboxStore = defineStore('toolbox', () => {
  // å¼€å…³åœ°ç‰©æ ‡æ³¨
  const featuresStatus = ref(false);
  // å¼€å…³å«æ˜Ÿåœ°å›¾
  const satelliteStatus = ref(false);
  // å¼€å…³æŽ§åˆ¶ç½—盘
  const controlbarStatus = ref(false);
  // å¼€å…³åæ ‡æ‹¾å–
  const coorPickStatus = ref(false);
  // å¼€å…³æ•°æ®æ ‡è®°
  const dataMarkerStatus = ref(true);
  // å¼€å…³æ•°æ®å¼¹æ¡†
  const dataDialogStatus = ref(true);
  return {
    featuresStatus,
    satelliteStatus,
    controlbarStatus,
    coorPickStatus,
    dataMarkerStatus,
    dataDialogStatus
  };
});
src/styles/base.scss
@@ -71,7 +71,7 @@
  default: var(--el-component-size-default),
  large: var(--el-component-size-large)
);
$ws: (20px, 40px, 60px, 100px, 150px, 300px);
$ws: (20, 40, 60, 80, 100, 120, 150, 300);
@each $name, $value in $csize {
  .w-#{$name} {
    width: #{$value};
@@ -82,10 +82,10 @@
}
@each $i in $ws {
  .w-#{$i} {
    width: #{$i};
    width: #{$i}px;
  }
  .h-#{$i} {
    height: #{$i};
    height: #{$i}px;
  }
}
src/styles/elementUI.scss
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
:root {
  // --el-text-color-regular: #ffffff;
}
.el-form-item {
  margin-bottom: 0px;
}
.el-form-item__label {
  color: white;
}
// .el-radio {
//   --el-radio-text-color: white;
// }
src/styles/index.scss
@@ -1 +1,2 @@
@use './base.scss';
@use './elementUI.scss';
src/utils/map/3dLayer.js
@@ -1,3 +1,7 @@
/**
 * é«˜å¾·åœ°å›¾3D图形绘制相关
 */
import { map, object3Dlayer } from './index_old';
// 3d图形
@@ -25,17 +29,151 @@
  }
  const fDatas = _factorDatas;
  const factor = _factor;
  // MapUtil._object3Dlayer.clear()
  // MapUtil.drawMesh(f.lnglats, f.heights, f.type, false)
  MapUtil.drawMesh2(fDatas, factor);
  MapUtil.drawMarker();
  drawMesh(fDatas, factor);
}
var _maxHeight = 1000,
  _minHeight = 100,
  _lastZoom = -1;
/**
 * èŽ·å–å½“å‰åœ°å›¾ç¼©æ”¾ç­‰çº§ä¸‹çš„ç»˜åˆ¶é«˜åº¦ç¼©æ”¾æ¯”ä¾‹
 * @param {*} minH å½“前监测数据的最小高度
 * @param {*} maxH å½“前监测数据的最大高度
 */
function _getScale(minH, maxH) {
  var zoom = map.getZoom();
  if (_lastZoom == -1) {
    _lastZoom = zoom;
  } else if (_lastZoom <= 8) {
    _lastZoom = zoom;
    return;
  } else if (_lastZoom >= 18) {
    _lastZoom = zoom;
    return;
  }
  if (zoom <= 8) {
    _maxHeight = 10000;
    _minHeight = 1000;
  } else if (zoom <= 9) {
    _maxHeight = 9000;
    _minHeight = 900;
  } else if (zoom <= 10) {
    _maxHeight = 8000;
    _minHeight = 800;
  } else if (zoom <= 11) {
    _maxHeight = 7000;
    _minHeight = 700;
  } else if (zoom <= 12) {
    _maxHeight = 6000;
    _minHeight = 600;
  } else if (zoom <= 14) {
    _maxHeight = 5000;
    _minHeight = 500;
  } else if (zoom <= 15) {
    _maxHeight = 4500;
    _minHeight = 450;
  } else if (zoom <= 16) {
    _maxHeight = 4000;
    _minHeight = 400;
  } else if (zoom <= 17) {
    _maxHeight = 2500;
    _minHeight = 250;
  } else if (zoom > 17) {
    _maxHeight = 1000;
    _minHeight = 100;
  }
  var scale = (_maxHeight - _minHeight) / (maxH - minH);
  return scale;
}
/**
 * ç»˜å›¾
 */
function drawMesh(fDatas, factor, center, merge) {
  const lnglats_GD = fDatas.lnglats_GD;
  const coors = fDatas.coors_GD;
  const heights = factor.heights;
  const colors = factor.colors;
  const bColor = factor.bottomColor;
  if (center) {
    map.setZoomAndCenter(16, center);
  }
  // eslint-disable-next-line no-undef
  var cylinder = new AMap.Object3D.Mesh();
  cylinder.backOrFront = 'both';
  cylinder.transparent = true;
  var geometry = cylinder.geometry;
  const scale = _getScale(_minH, _maxH);
  for (let i = 0; i < coors.length; i++) {
    var r = lnglats_GD[i];
    var lastP = lnglats_GD[i - 1];
    var p = coors[i];
    var h = (heights[i] - _minH) * scale + _minHeight;
    if (heights[i] == -1) {
      h = -1;
    }
    geometry.vertices.push(p.x, p.y, 0); //底部顶点
    geometry.vertices.push(p.x, p.y, 0 - h); //顶部顶点
    if (i > 0) {
      // eslint-disable-next-line no-undef
      var distance = AMap.GeometryUtil.distance(r, lastP);
      //两个数据点最小间隔时间为4s,假设车速按照120km/h计算,4s行驶最大距离作为132米,
      //设定超过1分钟的数据绘制特殊的连线
      if (distance <= 500 && h != -1) {
        var bottomIndex = i * 2;
        var topIndex = bottomIndex + 1;
        var lastBottomIndex = bottomIndex - 2;
        var lastTopIndex = bottomIndex - 1;
        geometry.faces.push(bottomIndex, topIndex, lastTopIndex);
        geometry.faces.push(bottomIndex, lastBottomIndex, lastTopIndex);
      }
    }
    // var bColor = bColor
    var tColor = colors[i];
    geometry.vertexColors.push.apply(geometry.vertexColors, bColor); //底部顶点颜色
    geometry.vertexColors.push.apply(geometry.vertexColors, tColor); //顶部顶点颜色
  }
  // 7.根据合并选项重置或新增当前缓存数据
  if (merge != true) {
    _factorDatas = fDatas;
    _factor = factor;
    if (_cylinder != undefined) {
      object3Dlayer.remove(_cylinder);
    }
  } else {
    // _factorDatas.lnglats.push.apply(
    //   _factorDatas.lnglats,
    //   lnglats_GD
    // );
    // _factorDatas.coors.push.apply(_factorDatas.coors, coors);
    // _factorDatas.heights.push.apply(_factorDatas.heights, heights);
    // _factorDatas.colors.push.apply(_factorDatas.colors, colors);
    // _factorDatas.bottomColor = bColor;
  }
  object3Dlayer.add(cylinder);
  /**************test ****************/
  // object3Dlayer.on('mouseover', function (e) {
  //   console.log(
  //     `鼠标移入覆盖物! [${e.lnglat.getlng()}, ${e.lnglat.getLat()}]`
  //   );
  // });
  /**************test ****************/
  _cylinder = cylinder;
}
export default {
  /**
   * ç»˜åˆ¶3D走行路线图
   * @param fDatas å®Œæ•´ç›‘测数据
   * @param factor å½“前展示的监测因子的值value
   * @param factor å½“前展示的监测因子对象
   * @param merge æ˜¯å¦å’Œä¹‹å‰ç»˜åˆ¶çš„图形合并
   * @param setCenter é•œå¤´æ˜¯å¦è‡ªåŠ¨ç§»åŠ¨è‡³å›¾å½¢ä¸­å¿ƒ
   */
@@ -44,7 +182,7 @@
    const heights = factor.heights;
    // 1.关闭地图缩放监听
    map.off('zoomend', this._onMapZoom);
    map.off('zoomend', onMapZoom);
    // 2.计算绘图高度的边界值
    if (merge != true) {
@@ -70,18 +208,19 @@
          break;
        }
      }
      // eslint-disable-next-line no-undef
      center = new AMap.LngLat(...p);
    }
    // 5.绘制3D图形
    drawMesh2(fDatas, factor, center, merge);
    drawMesh(fDatas, factor, center, merge);
    // ç¼©æ”¾åœ°å›¾åˆ°åˆé€‚的视野级别
    // map.setFitView()
    // 6.开启地图缩放监听
    if (lnglats_GD.length > 0) {
      map.on('zoomend', this._onMapZoom);
      map.on('zoomend', onMapZoom);
    }
  }
};
src/utils/map/calculate.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,59 @@
/**
 * åœ°å›¾åæ ‡ç›¸å…³è®¡ç®—
 */
import { map } from './index_old';
export default {
  /**
   * æ ¹æ®åæ ‡ç‚¹ã€è·ç¦»å’Œè§’度,得到另一个坐标点
   * @param {*} pos
   * @param {*} distance ç±³
   * @param {*} angle
   */
  getLatLon: function (pos, distance, angle) {
    var Ea = 6378137; //   èµ¤é“半径
    var Eb = 6356725; //   æžåŠå¾„
    var dx = distance * Math.sin((angle * Math.PI) / 180);
    var dy = distance * Math.cos((angle * Math.PI) / 180);
    var ec = Eb + ((Ea - Eb) * (90.0 - pos[1])) / 90.0;
    var ed = ec * Math.cos((pos[1] * Math.PI) / 180);
    var lng = ((dx / ed + (pos[0] * Math.PI) / 180.0) * 180.0) / Math.PI;
    var lat = ((dy / ec + (pos[1] * Math.PI) / 180.0) * 180.0) / Math.PI;
    return [lng, lat];
  },
  /**
   * å°†äºŒç»´æ•°ç»„形式的坐标点数组转换为高德地图中 LngLat ç±»
   * @param {*} lnglats
   * @returns
   */
  parse2LngLat: function (lnglats) {
    // åˆ›å»ºåŒ…含4个节点的折线及文字标注
    var path = [];
    lnglats.forEach(function (value) {
      // eslint-disable-next-line no-undef
      path.push(new AMap.LngLat(value[0], value[1]));
    });
    return path;
  },
  /**
   * å°†é«˜å¾·åœ°å›¾çš„经纬度坐标转换为图形坐标
   * @param {*} lnglats_GD
   * @returns
   */
  lngLatToGeodeticCoord: function (lnglats_GD) {
    var coors_GD = [];
    for (let i = 0; i < lnglats_GD.length; i++) {
      var gd = lnglats_GD[i];
      // eslint-disable-next-line no-undef
      var r = new AMap.LngLat(...gd);
      var p = map.lngLatToGeodeticCoord(r);
      // **记录转换后的3D地图图形坐标
      coors_GD.push(p);
    }
    return coors_GD;
  }
};
src/utils/map/dialog.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,260 @@
import { factorName } from '../../constant/factor-name';
import { factorUnit } from '../../constant/factor-unit';
import { windDir } from '../../constant/wind-dir';
export const DialogUtil = {
  show: true,
  toggleDataDialog() {
    this.show = !this.show;
    if (this.show) {
      return '数据弹框:开';
    } else {
      return '数据弹框:关';
    }
  },
  /**
   * åˆ›å»ºå¼¹å‡ºæ¡†
   * @param {*} factorDatas ç›‘测数据
   * @param {*} i å½“前显示监测数据索引
   * @param {*} onClose å…³é—­å¼¹å‡ºæ¡†å›žè°ƒ
   * @returns
   */
  createInfoWindow(factorDatas, i, onClose) {
    let m = {
      data: factorDatas,
      index: i,
      window: '',
      close: onClose
    };
    // eslint-disable-next-line no-undef
    m.window = new AMap.InfoWindow({
      isCustom: true, //使用自定义窗体
      content: this.createWindowContent(m),
      // eslint-disable-next-line no-undef
      offset: new AMap.Pixel(16, -45)
    });
    return m.window;
  },
  createInfoWindow2(factorData, onClose) {
    let m = {
      time: factorData.time,
      factorList: factorData.values,
      window: '',
      close: onClose
    };
    // eslint-disable-next-line no-undef
    m.window = new AMap.InfoWindow({
      isCustom: true, //使用自定义窗体
      content: this.createWindowContent2(m),
      // eslint-disable-next-line no-undef
      offset: new AMap.Pixel(16, -45)
    });
    return m.window;
  },
  /**
   * ç«™ç‚¹æ ‡è®°ä¿¡æ¯çª—体
   */
  createWindowContent: function (marker) {
    const factorDatas = marker.data;
    const i = marker.index;
    const time = factorDatas.times[i];
    const factorList = [];
    Object.keys(factorDatas.factor).forEach((k) => {
      var f = factorDatas.factor[k].datas[i];
      factorList.push(f);
    });
    marker.time = time;
    marker.factorList = factorList;
    return this.createWindowContent2(marker);
  },
  createWindowContent2(marker) {
    const time = marker.time;
    const factorList = marker.factorList;
    //实例化信息窗体
    // var title = '<div>' + site.name + '</div>' + '<div class="sub-title">编号:' + site.code + '</div>',
    var title = '',
      content = '',
      tag = '';
    tag += "<div class='time'>" + '时间: ' + time;
    // éåŽ†ç«™ç‚¹æ•°æ®ä¸­çš„æ¯ä¸€é¡¹ç›‘æµ‹å› å­ï¼Œç”Ÿæˆé¡µé¢
    content += "<div><table class='text-table'>";
    var _contents = new Map();
    factorList.forEach((f) => {
      // åˆ é€‰ä¸æ˜¾ç¤ºçš„因子
      if (
        f.factorName == 'NOI' ||
        f.factorName == 'LNG' ||
        f.factorName == 'LAT' ||
        f.factorName == 'VELOCITY' ||
        f.factorName == 'TIME' ||
        f.factorName == 'HEIGHT'
      ) {
        return;
      }
      var factor = factorName[f.factorName];
      var n = 1;
      if (f.factorName == 'WIND_DIRECTION') {
        n = 0;
      }
      var v = f.factorData.toFixed(n);
      var unit = factorUnit[f.factorName];
      if (f.factorName == 'CO') {
        unit = 'μg/m³';
      }
      if (f.factorName == 'WIND_DIRECTION') {
        unit += '(' + windDir(f.factorData) + ')';
      }
      var c = '<tr>';
      if (f.factorName == 'H2S' || f.factorName == 'PM10') {
        c = "<tr class='divide'>";
      }
      c += '<td>' + factor + '</td>';
      c += '<td>' + ': ' + '</td>';
      c += '<td>' + v + '</td>';
      c += "<td class='last-col'>" + unit + '</td>';
      c += '</tr>';
      _contents.set(f.factorName, c);
    });
    var orderList = [
      'VOC',
      'H2S',
      'NO2',
      'CO',
      'SO2',
      'O3',
      'PM25',
      'PM10',
      'TEMPERATURE',
      'HUMIDITY',
      'WIND_SPEED',
      'WIND_DIRECTION'
    ];
    orderList.forEach((e) => {
      content += _contents.get(e);
    });
    // content +=
    content += '</table></div>';
    var info = document.createElement('div');
    // info.className = "custom-info input-card content-window-card";
    info.className = 'flexbox-col';
    //可以通过下面的方式修改自定义窗体的宽高
    //info.style.width = "400px";
    // å®šä¹‰é¡¶éƒ¨æ ‡é¢˜
    var top = document.createElement('div');
    // top.className = "info-top";
    top.className = 'ff-content ff-content-top-left ff-content-small-borderless-t info-top';
    var top_b = document.createElement('div');
    top_b.className = 'ff-border-bottom';
    var top_t = document.createElement('div');
    top_t.className = 'ff-border-top';
    var top_c = document.createElement('div');
    top_c.className = 'ff-border-content flexbox flex-space-between';
    var titleD = document.createElement('div');
    var closeX = document.createElement('i');
    titleD.innerHTML = title;
    closeX.className = 'fa fa-times';
    // eslint-disable-next-line no-undef
    $(closeX).attr('aria-hidden', 'true');
    closeX.onclick = function () {
      marker.close();
      marker.window.close();
    };
    top_c.appendChild(titleD);
    top_c.appendChild(closeX);
    top_t.appendChild(top_c);
    top.appendChild(top_b);
    top.appendChild(top_t);
    info.appendChild(top);
    // å®šä¹‰ä¸­éƒ¨å†…容
    var refreshV = document.createElement('div');
    refreshV.className = 'refresh-btn';
    var refresh = document.createElement('i');
    refresh.className = 'fa fa-refresh';
    // eslint-disable-next-line no-undef
    $(refresh).attr('aria-hidden', 'true');
    // eslint-disable-next-line no-undef
    $(refresh).css('color', '#ffffffc0');
    // eslint-disable-next-line no-undef
    $(refresh).css('cursor', 'pointer');
    refresh.onclick = function () {
      //   $(this).addClass('fa-spin')
      //   that.fetchingData(site.code, function () {
      //     setTimeout(() => {
      //       $(this).removeClass('fa-spin')
      //     }, 1000);
      //   }.bind(this))
    };
    var m_top = document.createElement('div');
    m_top.className = 'ff-content ff-content-left ff-content-medium';
    var m_top_b = document.createElement('div');
    m_top_b.className = 'ff-border-bottom';
    var m_top_t = document.createElement('div');
    m_top_t.className = 'ff-border-top';
    var m_top_c = document.createElement('div');
    m_top_c.className = 'ff-border-content';
    var m_top_f = document.createElement('div');
    m_top_f.className = 'ff-footer flexbox-col flex-center';
    var m_top_tr = document.createElement('div');
    m_top_tr.className = 'ff-triangle';
    var m_top_trb = document.createElement('div');
    m_top_trb.className = 'ff-triangle-border';
    refreshV.appendChild(refresh);
    // m_top_c.appendChild(refreshV);
    var middle = document.createElement('div');
    middle.className = 'info-middle';
    middle.innerHTML = content;
    m_top_f.innerHTML = tag;
    m_top_c.appendChild(middle);
    m_top_t.appendChild(m_top_c);
    m_top_tr.appendChild(m_top_trb);
    m_top.appendChild(m_top_b);
    m_top.appendChild(m_top_t);
    m_top.appendChild(m_top_f);
    m_top.appendChild(m_top_tr);
    info.appendChild(m_top);
    // å®šä¹‰åº•部内容
    var bottom = document.createElement('div');
    bottom.className = 'info-bottom';
    bottom.style.position = 'relative';
    bottom.style.top = '0px';
    bottom.style.margin = '0 auto';
    var sharp = document.createElement('img');
    sharp.src = 'https://webapi.amap.com/images/sharp.png';
    bottom.appendChild(sharp);
    info.appendChild(bottom);
    return info;
  },
  openNewWindow(factorDatas, i, map, position, onClose) {
    if (!this.show) return;
    const window = this.createInfoWindow(factorDatas, i, onClose);
    window.open(map, position);
  },
  openNewWindow2(factorData, map, position, onClose) {
    if (!this.show) return;
    const window = this.createInfoWindow2(factorData, onClose);
    window.open(map, position);
  }
};
src/utils/map/index_old.js
@@ -1,5 +1,8 @@
/* eslint-disable no-undef */
// import '@/lib/AMap';
import { useToolboxStore } from '@/stores/toolbox';
const toolboxStore = useToolboxStore();
var mapInitDone = false;
var onMapMountedEvents = [];
@@ -58,6 +61,7 @@
  satellite = new AMap.TileLayer.Satellite();
  satellite.show();
  map.add([satellite]);
  toolboxStore.featuresStatus = true;
  _initControlbar();
  // _initMouseTool();
@@ -73,6 +77,7 @@
    }
  });
  map.addControl(controlbar);
  toolboxStore.controlbarStatus = true;
}
// é¼ æ ‡ç»˜å›¾åˆå§‹åŒ–
src/utils/map/marks.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,89 @@
/**
 * é«˜å¾·åœ°å›¾ç‚¹æ ‡è®°ç»˜åˆ¶ç›¸å…³
 */
import { map } from './index_old';
import sector from './sector';
import { DialogUtil } from './dialog';
import { useToolboxStore } from '@/stores/toolbox';
const toolboxStore = useToolboxStore();
var _massMarks = undefined;
export default {
  /**
   * ç»˜åˆ¶æµ·é‡ç‚¹æ ‡è®°
   * @param fDatas å®Œæ•´ç›‘测数据
   * @param _factor å½“前展示的监测因子对象
   */
  drawMassMarks(fDatas, _factor, onClick) {
    if (!toolboxStore.dataMarkerStatus) {
      return;
    }
    if (_massMarks) {
      map.remove(_massMarks);
      _massMarks = undefined;
    }
    const lnglats = fDatas.lnglats_GD;
    var data = [];
    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³`,
        id: i
      });
    }
    // åˆ›å»ºæ ·å¼å¯¹è±¡
    var styleObject = {
      url: 'https://a.amap.com/jsapi_demos/static/images/mass1.png',
      // url: './asset/mipmap/ic_up_white.png', // å›¾æ ‡åœ°å€
      // eslint-disable-next-line no-undef
      size: new AMap.Size(11, 11), // å›¾æ ‡å¤§å°
      // eslint-disable-next-line no-undef
      anchor: new AMap.Pixel(5, 5) // å›¾æ ‡æ˜¾ç¤ºä½ç½®åç§»é‡ï¼ŒåŸºå‡†ç‚¹ä¸ºå›¾æ ‡å·¦ä¸Šè§’
    };
    // eslint-disable-next-line no-undef
    var massMarks = new AMap.MassMarks(data, {
      zIndex: 5, // æµ·é‡ç‚¹å›¾å±‚叠加的顺序
      zooms: [15, 18], // åœ¨æŒ‡å®šåœ°å›¾ç¼©æ”¾çº§åˆ«èŒƒå›´å†…展示海量点图层
      style: styleObject // è®¾ç½®æ ·å¼å¯¹è±¡
    });
    massMarks.on('click', (event) => {
      const i = event.data.id;
      // 1. ç»˜åˆ¶æ‰‡å½¢åŒºåŸŸ
      sector.drawSector(fDatas, i);
      // 2. ç»˜åˆ¶å¯¹è¯æ¡†
      DialogUtil.openNewWindow(fDatas, i, map, lnglats[i], () => {
        // ç§»é™¤æ‰‡å½¢åŒºåŸŸ
        // clearSector3();
      });
      // 3. è‡ªå®šä¹‰ç‚¹å‡»äº‹ä»¶
      onClick();
    });
    // eslint-disable-next-line no-undef
    var marker = new AMap.Marker({
      content: ' ',
      map: map,
      // eslint-disable-next-line no-undef
      offset: new AMap.Pixel(13, 12)
    });
    var timeout;
    massMarks.on('mouseover', (e) => {
      if (timeout) {
        clearTimeout(timeout);
      }
      marker.setPosition(e.data.lnglat);
      marker.setLabel({ content: e.data.name });
      map.add(marker);
      timeout = setTimeout(() => {
        map.remove(marker);
      }, 2000);
    });
    _massMarks = massMarks;
    map.add(massMarks);
  }
};
src/utils/map/sector.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,232 @@
import { map, object3Dlayer } from './index_old';
import calculate from './calculate';
var _defaultDeg = 30,
  _sector = undefined,
  _sectorViews = {};
function clearSector() {
  var list = [];
  for (const key in _sectorViews) {
    list.push(_sectorViews[key]);
  }
  if (list.length > 0) {
    map.remove(list);
    _sectorViews = {};
  }
  if (_sector) {
    object3Dlayer.remove(_sector);
  }
}
export default {
  drawSector(fDatas, i) {
    const lnglat = fDatas.lnglats_GD[i];
    let windDir = fDatas.factor[17].datas[i].factorData;
    let windSpeed = fDatas.factor[16].datas[i].factorData;
    if (!windDir) windDir = 0;
    if (!windSpeed) windSpeed = 0;
    if (windSpeed > 10) {
      return;
    }
    if (_sector != undefined) {
      clearSector();
    }
    // eslint-disable-next-line no-undef
    var sector = new AMap.Object3D.Mesh();
    sector.transparent = true;
    sector.backOrFront = 'both';
    var unit = 5;
    var sDeg = windDir - _defaultDeg; //扇形起始角度(以上方作为0度)
    // sDeg = sDeg < 0 ? sDeg + 360 : sDeg
    var eDeg = windDir + _defaultDeg; //扇形结束角度
    // eDeg = eDeg < 0 ? eDeg + 360 : eDeg
    var distance = windSpeed * 10 * 60; //半径(风速*时间)
    var lnglat2 = calculate.getLatLon(lnglat, distance, sDeg);
    var lnglat3 = calculate.getLatLon(lnglat, distance, windDir);
    var lnglat4 = calculate.getLatLon(lnglat, distance, eDeg);
    var list = calculate.parse2LngLat([lnglat, lnglat2, lnglat3, lnglat4]);
    var distance2 = windSpeed * 5 * 60; //半径(风速*时间)
    var lnglat2_2 = calculate.getLatLon(lnglat, distance2, sDeg);
    var lnglat2_3 = calculate.getLatLon(lnglat, distance2, windDir);
    var lnglat2_4 = calculate.getLatLon(lnglat, distance2, eDeg);
    var list2 = calculate.parse2LngLat([lnglat2_2, lnglat2_3, lnglat2_4]);
    var p0 = calculate.lngLatToGeodeticCoord([lnglat])[0];
    var geometry = sector.geometry;
    var count = distance / unit;
    var unitDeg = (eDeg - sDeg) / count;
    for (let i = 0; i < count; i++) {
      var angle1 = sDeg + unitDeg * i;
      var angle2 = sDeg + unitDeg * (i + 1);
      var l1 = calculate.getLatLon(lnglat, distance, angle1);
      var l2 = calculate.getLatLon(lnglat, distance, angle2);
      var l3 = calculate.getLatLon(lnglat, distance2, angle1);
      var l4 = calculate.getLatLon(lnglat, distance2, angle2);
      var coors = calculate.lngLatToGeodeticCoord([l1, l2, l3, l4]);
      l1 = coors[0];
      l2 = coors[1];
      l3 = coors[2];
      l4 = coors[3];
      // å†…测扇形
      geometry.vertices.push(p0.x, p0.y, 0);
      geometry.vertices.push(l3.x, l3.y, 0);
      geometry.vertices.push(l4.x, l4.y, 0);
      // å¤–侧扇形
      geometry.vertices.push(l3.x, l3.y, 0);
      geometry.vertices.push(l4.x, l4.y, 0);
      geometry.vertices.push(l1.x, l1.y, 0);
      geometry.vertices.push(l2.x, l2.y, 0);
      // console.log(l3.x + ',' + l3.y + ' | ' + l1.x + ',' + l1.y);
      // å†…测扇形颜色
      geometry.vertexColors.push(1, 0.11, 0.25, 0.6);
      geometry.vertexColors.push(1, 0.11, 0.25, 0.6);
      geometry.vertexColors.push(1, 0.11, 0.25, 0.6);
      //外侧扇形颜色
      geometry.vertexColors.push(1, 0.37, 0.07, 0.5);
      geometry.vertexColors.push(1, 0.37, 0.07, 0.5);
      geometry.vertexColors.push(1, 0.37, 0.07, 0.5);
      geometry.vertexColors.push(1, 0.37, 0.07, 0.5);
      var index = i * 7;
      geometry.faces.push(index, index + 1, index + 2);
      geometry.faces.push(index + 3, index + 4, index + 5);
      geometry.faces.push(index + 4, index + 5, index + 6);
    }
    object3Dlayer.add(sector);
    _sector = sector;
    distance = distance.toFixed(0);
    distance2 = distance2.toFixed(0);
    const zoomStyleMapping = {
      14: 0,
      15: 0,
      16: 0,
      17: 0,
      18: 0,
      19: 0,
      20: 0
    };
    //10分钟扇形
    // eslint-disable-next-line no-undef
    var text15 = new AMap.ElasticMarker({
      zoom: [14, 20],
      position: list[2],
      styles: [
        {
          icon: {
            img: './asset/mipmap/location.png',
            size: [16, 16], //可见区域的大小
            ancher: [8, 16], //锚点
            fitZoom: 18, //最合适的级别
            scaleFactor: 1, //地图放大一级的缩放比例系数
            maxScale: 2, //最大放大比例
            minScale: 1 //最小放大比例
          },
          label: {
            content: '<div>10分钟</div>',
            offset: [-35, 0],
            position: 'BM',
            minZoom: 15
          }
        }
      ],
      zoomStyleMapping: zoomStyleMapping
    });
    _sectorViews['text10'] = text15;
    // eslint-disable-next-line no-undef
    var textM = new AMap.ElasticMarker({
      zoom: [14, 20],
      position: list[1],
      styles: [
        {
          icon: {
            img: './asset/mipmap/location.png',
            size: [16, 16], //可见区域的大小
            ancher: [8, 16], //锚点
            fitZoom: 18, //最合适的级别
            scaleFactor: 1, //地图放大一级的缩放比例系数
            maxScale: 2, //最大放大比例
            minScale: 1 //最小放大比例
          },
          label: {
            content: `<div>${distance}m</div>`,
            offset: [-35, 0],
            position: 'BM',
            minZoom: 15
          }
        }
      ],
      zoomStyleMapping: zoomStyleMapping
    });
    _sectorViews['textM'] = textM;
    map.add(_sectorViews['text10']);
    map.add(_sectorViews['textM']);
    //5分钟扇形
    let pList = list2;
    // eslint-disable-next-line no-undef
    var text5 = new AMap.ElasticMarker({
      position: pList[1],
      styles: [
        {
          icon: {
            img: './asset/mipmap/location.png',
            size: [16, 16], //可见区域的大小
            ancher: [8, 16], //锚点
            fitZoom: 18, //最合适的级别
            scaleFactor: 1, //地图放大一级的缩放比例系数
            maxScale: 2, //最大放大比例
            minScale: 1 //最小放大比例
          },
          label: {
            content: `<div>5分钟</div>`,
            offset: [-35, 0],
            position: 'BM',
            minZoom: 15
          }
        }
      ],
      zoomStyleMapping: zoomStyleMapping
    });
    _sectorViews['text5'] = text5;
    // eslint-disable-next-line no-undef
    var textM5 = new AMap.ElasticMarker({
      position: pList[0],
      styles: [
        {
          icon: {
            img: './asset/mipmap/location.png',
            size: [16, 16], //可见区域的大小
            ancher: [8, 16], //锚点
            fitZoom: 18, //最合适的级别
            scaleFactor: 1, //地图放大一级的缩放比例系数
            maxScale: 2, //最大放大比例
            minScale: 1 //最小放大比例
          },
          label: {
            content: `<div>${distance2}m</div>`,
            offset: [-35, 0],
            position: 'BM',
            minZoom: 15
          }
        }
      ],
      zoomStyleMapping: zoomStyleMapping
    });
    _sectorViews['textM5'] = textM5;
    map.add(_sectorViews['textM5']);
    map.add(_sectorViews['text5']);
  }
};
src/utils/map/toolbox.js
@@ -1,6 +1,9 @@
/* eslint-disable no-undef */
import { map, satellite, controlbar } from './index_old';
import { map, satellite } from './index_old';
import { useToolboxStore } from '@/stores/toolbox';
// import '@/lib/jquery-3.5.1.min';
const toolboxStore = useToolboxStore();
/**
 * åæ ‡æ‹¾å–鼠标点击回调事件
@@ -42,6 +45,7 @@
   */
  toggleFeatures(value) {
    value ? map.setFeatures(['bg', 'road', 'point', 'building']) : map.setFeatures(['bg', 'road']);
    toolboxStore.featuresStatus = value;
  },
  /**
@@ -50,6 +54,7 @@
   */
  toggleSatellite(value) {
    value ? satellite.show() : satellite.hide();
    toolboxStore.satelliteStatus = value;
  },
  /**
@@ -59,6 +64,7 @@
  toggleControlbar(value) {
    // value ? controlbar.show() : controlbar.hide();
    value ? $('.amap-controlbar').show() : $('.amap-controlbar').hide();
    toolboxStore.controlbarStatus = value;
  },
  /**
@@ -74,5 +80,6 @@
      _locationMarker = undefined;
      _locationText = undefined;
    }
    toolboxStore.coorPickStatus = value;
  }
};
src/views/historymode/HistoryMode.vue
@@ -1,11 +1,65 @@
<template>
  <div class="fy-container">
    <FactorRadio></FactorRadio>
    <FactorRadio @change="(e) => (factorType = e)"></FactorRadio>
    <SearchBar></SearchBar>
  </div>
</template>
<script>
import Layer from '@/utils/map/3dLayer';
import marks from '@/utils/map/marks';
export default {
  name: 'HistoryPage'
  name: 'HistoryPage',
  data() {
    return {
      factorType: '',
      factorDatas: [],
      merge: false,
      setCenter: true
    };
  },
  watch: {
    factorType(nValue, oValue) {
      if (nValue != oValue) {
        this.draw();
      }
    }
  },
  methods: {
    draw() {
      const factor = this.factorDatas.factor[this.factorType];
      this.drawRoadMap(factor);
      this.drawMassMarks(factor);
    },
    // ç»˜åˆ¶3D走行路线图
    drawRoadMap(e) {
      //   this.factorMode = factorMode;
      // this.factorType = factorType;
      // this.factorName = factorName;
      // this.factorDatas.refreshHeight(this.factorType + 1 + '');
      // this.refreshLegend(this.factorDatas);
      // this.mapMaker.setFactorType(factorType);
      // if (!this.mapMaker.runStatus()) {
      Layer.drawRoadMap(this.factorDatas, e, this.merge, this.setCenter);
      // }
    },
    drawMassMarks(e) {
      marks.drawMassMarks(this.factorDatas, e, () => {
        // æŸ¥è¯¢èŒƒå›´å†…的监测站点
        // SceneUtil.searchByCoordinate(lnglat[0], lnglat[1], distance);
        // 3. è¶‹åŠ¿å›¾è·³è½¬å®šä½
        // const progress = FChart.locate(lineChart.chart, lineChart.option, i, _factor.factorName);
        // 4. è¡¨æ ¼æ•°æ®è·³è½¬å®šä½
        // Table.locate(i);
      });
    }
  }
};
</script>
<style scoped>
.fy-container {
  background-color: antiquewhite;
}
</style>