Преглед на файлове

Merge remote-tracking branch 'origin/dev' into dev

zhangyihao преди 10 месеца
родител
ревизия
1aab8f33da

+ 77 - 0
src/components/Dialog/index2.vue

@@ -0,0 +1,77 @@
+<template>
+  <div>
+    <div v-if="modelValue" class="dialog-wrap" :style="{ width: width ? width : '780px', height: height ? height : '590px' }">
+      <!--    <div class="overlay" @click="closeDialog"></div>-->
+      <div class="dialog" :style="{ width: width ? width : '780px', height: height ? height : '590px' }">
+        <div class="dialog-header">
+          <div class="dialog-title">{{ title }}</div>
+          <div class="icon-close" @click="closeDialog">
+            <el-icon size="40px"><Close /></el-icon>
+          </div>
+        </div>
+        <div class="dialog-content">
+          <slot />
+        </div>
+      </div>
+    </div>
+  </div>
+
+</template>
+
+<script lang="ts" setup>
+interface Props {
+  modelValue: boolean;
+  title?: string;
+  width?: string;
+  height?: string;
+}
+const props = withDefaults(defineProps<Props>(), {
+  modelValue: false
+});
+const emit = defineEmits(['update:modelValue', 'close']);
+
+// 关闭弹窗
+const closeDialog = () => {
+  emit('update:modelValue', false);
+  emit('close');
+};
+</script>
+
+<style lang="scss" scoped>
+.dialog-wrap {
+  position: fixed;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  z-index: 2000;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 16px;
+  .dialog {
+    height: 590px;
+    margin: 0 auto;
+    background-color: #fff;
+    border-radius: 10px;
+  }
+}
+.dialog {
+  padding: 0 20px;
+  .dialog-header {
+    width: 100%;
+    height: 70px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    .dialog-title {
+      font-size: 36px;
+    }
+    .icon-close {
+      cursor: pointer;
+    }
+  }
+  .dialog-content {
+    padding: 10px 0;
+  }
+}
+</style>

+ 351 - 0
src/components/Map/company-map.vue

@@ -0,0 +1,351 @@
+<template>
+  <el-dialog v-model="mapPop" title="地图定位" width="80%" @close="handleClose">
+
+    <div class="map_box">
+      <div class="map" id="map"></div>
+      <div class="search">
+        <!-- @input="handleInput(0)" -->
+        <el-input placeholder="请输入地址" v-model="location" />
+        <el-button class="btn" type="primary" @click="handleInput(0)">搜索</el-button>
+      </div>
+
+      <div class="scroll_box" v-if="searchPop">
+        <div style="height: 30px; line-height: 30px;">
+          <span style="font-weight:bold">搜索结果列表</span>
+          <i class="el-icon-close" style="float: right;font-size: 20px;cursor: pointer;" @click="closeSearchList()" />
+        </div>
+
+        <el-scrollbar class="scroll" style="height: 250px;">
+          <div v-show="searchList.length" class="item" v-for="(item, index) in searchList" :key="index" @click="handlePanTo(index)">
+            <el-image class="img" :src="item.img" :alt="item.name" lazy>
+              <div slot="error" class="image-slot">
+                <i class="el-icon-picture-outline"></i>
+              </div>
+            </el-image>
+            <div>
+              <div class="text">{{ item.name }}</div>
+              <div>{{ item.address }}</div>
+            </div>
+          </div>
+          <div class="empty" v-show="!searchList.length" style="text-align: center;">没有搜索到内容</div>
+        </el-scrollbar>
+
+        <el-pagination background small :hide-on-single-page="true" layout="prev, pager, next" :total="total" :page-size="pageSize" :current-page="pageNum" style="margin-top: 10px;" @current-change="handleChangePage">
+        </el-pagination>
+      </div>
+    </div>
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="handleClose">取 消</el-button>
+        <el-button type="primary" @click="sureMark">确 定</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script>
+
+import AMapLoader from '@amap/amap-jsapi-loader'
+
+export default {
+  props: {
+    address: {//公司地址
+      type: String,
+      default: () => {
+        return '';
+      },
+    },
+    latAndLong: {//经纬度
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    visible: {
+      type: Boolean,
+      default: () => {
+        return false;
+      },
+    },
+  },
+  data() {
+    return {
+      // 地图对象
+      map: {},
+      amap: {},
+      location: '',
+      marker: null,//地图上的点标记
+      contextMenu: null,
+      lnglatPosition: null,//选中的新坐标
+
+      pageNum: 1,
+      pageSize: 10,
+      total: 0,
+
+      searchList: [],
+      searchPop: false,
+      placeSearch: null,
+      form: {},
+      open: false,
+      mapPop: false,
+      geocoder: {}
+    };
+  },
+  watch: {
+    async visible(n) {
+      this.mapPop = n;
+      if (n) {
+        await this.initMap()
+        this.location = this.address;
+        this.handleInput(0)
+      }
+    }
+  },
+  destroyed() {
+    if (this.map) {
+      this.map.destroy()
+      this.map.off('rightclick')
+    }
+  },
+  methods: {
+    handleInput(flag) {
+      if (!this.location) return;
+
+      if (!flag) {//搜索
+        this.total = 0
+        this.pageNum = 1
+      }
+
+      const that = this;
+      if (!this.placeSearch) {
+        this.placeSearch = new this.amap.PlaceSearch({
+          pageSize: 10, // 每页条数,默认10,范围1-50
+          pageIndex: 1, // 页码
+          extensions: 'all' // 默认base,返回基本地址信息;all:返回详细信息
+        })
+      }
+
+      this.searchPop = true;
+      this.placeSearch.setPageIndex(this.pageNum)
+      this.placeSearch.search(that.location, (status, result) => {
+        // console.log(result.poiList.pois, 'result')
+        if (!!result.poiList && result.poiList.pois && result.poiList.pois.length > 0) {
+          let arr = []
+          const pois = result.poiList.pois;
+          that.total = result.poiList ? result.poiList.count : 0;
+          arr = pois.map((item) => {
+            return {
+              name: item.name,
+              address: item.address,
+              img: item.photos[0]?.url,
+              lnglat: [item.location.lng, item.location.lat]
+            }
+          })
+          that.searchList = arr
+
+        } else {
+          that.total = 0
+          that.searchList = []
+        }
+
+      })
+    },
+    handleChangePage(newNum) {
+      if (!this.searchPop) return;
+      this.pageNum = newNum
+      this.handleInput(1)
+    },
+    closeSearchList() {
+      this.searchPop = false
+      this.location = ''
+      this.searchList = []
+      this.total = 0
+      this.pageNum = 1
+    },
+    // 地图中心的平移至指定点位置
+    handlePanTo(index) {
+      let lnglat = this.searchList[index].lnglat
+      this.form = {
+        longitude: lnglat[0],
+        latitude: lnglat[1]
+      }
+      this.map.panTo(lnglat)
+      this.setMarks(lnglat);
+      this.closeSearchList()
+    },
+    async initMap() {
+      let position = this.latAndLong.length ? this.latAndLong : [110.93154257997, 21.669064031332];
+      this.form = {
+        longitude: position[0],
+        latitude: position[1]
+      }
+      const AMap = await AMapLoader.load({
+        key: '30d3d8448efd68cb0b284549fd41adcf',     // 申请好的Web端开发者Key,首次调用 load 时必填
+        version: '2.0',      // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
+        plugins: ['AMap.PlaceSearch', 'AMap.ContextMenu', 'AMap.PolygonEditor', 'AMap.Geocoder']       // 插件列表
+      })
+      this.map = new AMap.Map('map', {
+        viewMode: '3D',    //是否为3D地图模式
+        center: position,
+        zoom: 15
+      })
+      this.amap = AMap
+
+      this.setMarks(position);
+      this.geocoder = new AMap.Geocoder({
+        // city 指定进行编码查询的城市,支持传入城市名、adcode 和 citycode
+        city: '010'
+      })
+      // 创建右键菜单
+      this.ContextMenu()
+      this.map.on('rightclick', this.handleRightclick);
+
+    },
+    ContextMenu() {
+      this.contextMenu = new AMap.ContextMenu();
+      this.contextMenu.addItem('选择标点', () => {
+        this.form = {
+          longitude: this.lnglatPosition[0],
+          latitude: this.lnglatPosition[1]
+        }
+        this.contextMenu.close()
+        let lnglat = [this.form.longitude, this.form.latitude];
+        this.setMarks(lnglat);
+      }, 1)
+    },
+    // 右键事件
+    handleRightclick(e) {
+      let lnglat = [e.lnglat.getLng(), e.lnglat.getLat()];
+      this.contextMenu.open(this.map, e.lnglat);
+      this.lnglatPosition = lnglat;
+    },
+    sureMark() {
+      let lnglat = [this.form.longitude, this.form.latitude];
+      this.geocoder.getAddress(lnglat, (status, result) => {
+        if (status === 'complete' && result.info === 'OK') {
+          // result为对应的地理位置详细信息
+          this.$emit("confirm", { lnglat: lnglat, address: result.regeocode.formattedAddress });
+        }
+      })
+
+    },
+    setMarks(lnglat) {//添加标记
+      if (this.marker) this.map.remove(this.marker);
+      let marker = new AMap.Marker({
+        position: lnglat,
+        icon: new AMap.Icon({
+          size: new AMap.Size(22, 28),  //图标所处区域大小
+          imageSize: new AMap.Size(22, 28), //图标大小
+          image: "//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
+        }),
+        anchor: 'bottom-center',
+        offset: new AMap.Pixel(0, 0)
+      });
+      marker.setMap(this.map);
+      this.marker = marker;
+    },
+    handleClose() {
+      this.$emit('update:visible', false)
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.map_box {
+  position: relative;
+  width: 100%;
+  height: 450px;
+  background: rgba(0, 0, 0, 0.3);
+  margin-bottom: 20px;
+}
+.map {
+  width: 100%;
+  height: 100%;
+}
+.search {
+  width: 50%;
+  position: absolute;
+  right: 2%;
+  top: 10px;
+  background: #fff;
+  padding: 8px 8px;
+  border-radius: 3px;
+  display: flex;
+}
+.btn {
+  margin-left: 10px;
+}
+
+.scroll_box {
+  width: 50%;
+  padding-top: 30px;
+  padding-bottom: 20px;
+  background: #fff;
+  position: absolute;
+  right: 2%;
+  top: 70px;
+  padding: 15px;
+  border-radius: 3px;
+  .close {
+    position: absolute;
+    right: 2%;
+    top: 10px;
+    cursor: pointer;
+    font-size: 20px;
+  }
+}
+.scroll {
+  width: 100%;
+  max-height: 250px;
+
+  .item {
+    display: flex;
+    font-size: 14px;
+    cursor: pointer;
+    padding: 8px;
+
+    &:hover {
+      background-color: #f6f6f6;
+    }
+
+    .img {
+      width: 50px;
+      height: 45px;
+      min-width: 50px;
+      margin-right: 10px;
+    }
+
+    &::v-deep {
+      .image-slot {
+        width: 100%;
+        height: 100%;
+        background-color: #f5f7fa;
+        text-align: center;
+        line-height: 50px;
+      }
+
+      .el-icon-picture-outline {
+        font-size: 25px;
+      }
+    }
+
+    .text {
+      color: #3385ff;
+      margin-bottom: 6px;
+    }
+  }
+}
+::v-deep {
+  .el-scrollbar__wrap {
+    overflow-x: hidden !important;
+  }
+
+  .is-horizontal {
+    display: none;
+  }
+}
+.empty {
+  margin: 20px 0;
+}
+</style>

+ 1 - 7
src/types/components.d.ts

@@ -37,15 +37,13 @@ declare module 'vue' {
     ElForm: typeof import('element-plus/es')['ElForm']
     ElFormItem: typeof import('element-plus/es')['ElFormItem']
     ElIcon: typeof import('element-plus/es')['ElIcon']
+    ElImage: typeof import('element-plus/es')['ElImage']
     ElInput: typeof import('element-plus/es')['ElInput']
     ElLink: typeof import('element-plus/es')['ElLink']
     ElMenu: typeof import('element-plus/es')['ElMenu']
     ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
     ElOption: typeof import('element-plus/es')['ElOption']
     ElPagination: typeof import('element-plus/es')['ElPagination']
-    ElPopover: typeof import('element-plus/es')['ElPopover']
-    ElRadio: typeof import('element-plus/es')['ElRadio']
-    ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
     ElRow: typeof import('element-plus/es')['ElRow']
     ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
     ElSelect: typeof import('element-plus/es')['ElSelect']
@@ -62,8 +60,6 @@ declare module 'vue' {
     ElTimeline: typeof import('element-plus/es')['ElTimeline']
     ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
     ElTooltip: typeof import('element-plus/es')['ElTooltip']
-    ElTree: typeof import('element-plus/es')['ElTree']
-    ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
     ElUpload: typeof import('element-plus/es')['ElUpload']
     FileUpload: typeof import('./../components/FileUpload/index.vue')['default']
     FooterSection: typeof import('./../components/FooterSection/index.vue')['default']
@@ -74,7 +70,6 @@ declare module 'vue' {
     HikvisionPlayer: typeof import('./../components/HKVideo/hikvision-player.vue')['default']
     HKVideo: typeof import('./../components/HKVideo/index.vue')['default']
     IconSelect: typeof import('./../components/IconSelect/index.vue')['default']
-    IEpUploadFilled: typeof import('~icons/ep/upload-filled')['default']
     IFrame: typeof import('./../components/iFrame/index.vue')['default']
     ImagePreview: typeof import('./../components/ImagePreview/index.vue')['default']
     ImageUpload: typeof import('./../components/ImageUpload/index.vue')['default']
@@ -102,7 +97,6 @@ declare module 'vue' {
     UserSelect: typeof import('./../components/UserSelect/index.vue')['default']
     VideoContainer: typeof import('./../components/HKVideo/video-container.vue')['default']
     YMap: typeof import('./../components/Map/YMap.vue')['default']
-    YMapold: typeof import('./../components/Map/YMapold.vue')['default']
     YztMap: typeof import('./../components/Map/YztMap/index.vue')['default']
   }
   export interface ComponentCustomProperties {

+ 44 - 0
src/views/routineCommandMap/MiddleSection.vue

@@ -1,11 +1,42 @@
 <template>
   <div class="middle-section">
+    <div class="search-button">
+      <el-button type="primary" @click="handleQuery1">备战防御</el-button>
+      <el-button type="primary" @click="handleQuery2">指挥调度</el-button>
+    </div>
+    <!--    <Dialog id="selectMap" v-model="mapDialogVisible" title="气象图" width="700px" height="600px" @close="dialogClose">-->
+    <company-map v-model:visible="mapDialogVisible" :address="form.address" style="height: 1500px" @confirm="handleMapChange"></company-map>
+    <!--    </Dialog>-->
+
     <GlobalMap is-component width="3894" height="2140" />
   </div>
 </template>
 
 <script lang="ts" setup>
 import GlobalMap from '../globalMap/index.vue';
+import { ref } from 'vue';
+// import Dialog from "@/components/Dialog/index2.vue";
+import CompanyMap from '@/components/Map/company-map.vue';
+
+const form = ref({
+  address: '',
+  lon: '',
+  lat: ''
+});
+const mapDialogVisible = ref(false);
+const handleQuery1 = () => {
+  console.log('备战防御被点击');
+};
+
+const handleQuery2 = () => {
+  mapDialogVisible.value = true;
+};
+const handleMapChange = (data) => {
+  form.value.drillAddress = data.address;
+  form.value.lon = data.lnglat[0];
+  form.value.lat = data.lnglat[1];
+  mapDialogVisible.value = false;
+};
 </script>
 
 <style lang="scss" scoped>
@@ -14,6 +45,19 @@ import GlobalMap from '../globalMap/index.vue';
   flex: 1;
   height: 2140px;
   animation: slideAndFade 1.5s;
+  position: relative;
+}
+.search-button {
+  position: absolute;
+  top: 60px;
+  left: 900px;
+  z-index: 10;
+}
+.el-button {
+  width: 360px;
+  height: 100px;
+  padding: 20px 40px;
+  font-size: 48px;
 }
 
 @keyframes slideAndFade {

+ 1 - 1
src/views/routineCommandMap/index.vue

@@ -22,7 +22,7 @@ onMounted(() => {
       dh: 2520,
       el: '#dashboard-container',
       resize: false,
-      ignore: ['#aMap', '#YztMap']
+      ignore: ['#aMap', '#YztMap', '#selectMap']
     },
     false
   );