Newer
Older
dcms_front / src / views / baseSource / mapSearch.vue
TAN YUE on 15 May 2021 18 KB 20210515 地图查询功能调整
<template>
  <div>
    <div id="map" class="leaflet_container" style="background-color: white">
      <!--查询显示组件-->
      <search-list
        ref="searchList"
        :total-data="searchList"
        :loading="searchLoading"
        @clear="clearSearch"
        @search="search"
        @change="changeSearchPage"
        @item-click="clickSearchItem"/>
      <!--工具箱-->
      <tools-container>
        <!-- 绘制工具-->
        <draw-tool @click="drawBox"/>
        <!--重置工具-->
        <clear-tool :disabled="clearDisabled" @click="drawDelete"/>
        <!--图层选择工具-->
        <layer-choose ref="layerRadio" :layers="layers" :select-layers="selectLayers" @check="layerChange"/>
      </tools-container>
      <!--图层选择组件-->
    </div>
  </div>
</template>
<script>
import L from 'leaflet'
import ClearTool from './components/clearTool'
import AppContainer from '@/components/layout/AppContainer'
import LayerChoose from './components/layerChoose'
import SearchList from './components/searchList'
import { mapGetters } from 'vuex'
import ToolsContainer from './components/toolsContainer'
import DrawTool from './components/drawTool'
import AddTool from './components/addTool'
var esri = require('esri-leaflet')
export default {
  name: 'MapSearch',
  components: { AddTool, ClearTool, DrawTool, ToolsContainer, LayerChoose, AppContainer, SearchList },
  data() {
    return {
      keyword: '', // 查询关键字
      searchLoading: false, // 查询状态
      map: null, // 地图对象
      drawLayer: null, // 绘制图层(框选)
      bounds: null, // 查询区域
      clearDisabled: true, // 禁用重置按钮
      baseLayer: [],
      layers: [
        { 'id': 0, 'name': '商户', 'type': 'layer', 'domain': [35] },
        { 'id': 1, 'name': '部件', 'type': 'layer', 'domain': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15, 16, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45] }
      ],
      selectLayers: [0], // 选中图层
      maps: [], // 地图图层
      parts: [], // 部件图层
      layerGroups: [], // 图层组,用于控制一组内容显示或者隐藏
      searchList: [], // 全部查询结果
      featureCollection: [], // 选中的图层和Feature
      featureCollectionLength: 0, // 选中的feature个数
      currentSearchMarkers: [], // 当前查询页面的markers
      searchIconList: [] // 查询结果的Icon列表
    }
  },
  computed: {
    ...mapGetters([
      'baseUrl',
      'partsUrl',
      'shopUrl',
      'mapUrl'
    ])
  },
  destroyed() {
    window.removeEventListener('click', this.handleKeyup, true)
  },
  mounted() {
    this.init()
    this.initIcons()
    window.addEventListener('click', this.handleKeyup, true)
  },
  methods: {
    handleKeyup(val) {
      if (this.$refs.searchList && val.target.id === 'map') {
        this.$refs.searchList.hideSearch()
      }
    },
    // 地图查询功能,关键字keyword,是否需要提示不能为空tips
    search(keyword, tips = true) {
      if (keyword) { // 如果传入了非空keyword表示点击搜索按钮,则将keyword置为keyword
        this.keyword = keyword
      } else if (keyword === '') { // 如果是空字符串,表示未输入任何查询条件,根据内容提示用户
        if (tips) this.$message.warning('请输入查询关键字')
        return
      } // 其他不予处理
      this.searchLoading = true
      const results = [] // 存放查询结果列表

      // 获取是查询部件还是查询商户
      if (this.selectLayers.toString() === '0') {
        // 查询商户
        const str = ['objid', 'dutyname', 'position_'] // 查询条件属性
        const query = esri.query({ url: `${this.baseUrl}${this.shopUrl}` })
        let queryString = '1=1' // 默认查询语句
        // 如果有关键字
        if (this.keyword) {
          // 拼接查询语句
          queryString = str.map(item => `(${item} like '%${this.keyword}%')`).join(' OR ')
        } else {
          return
        }
        query.where(queryString)
        // 如果有查询边界
        if (this.bounds) {
          query.within(this.bounds)
        }
        // 执行查询
        query.run((error, featureCollection, response) => {
          if (error) {
            console.log(error)
            return
          }
          const featuresLength = featureCollection.features.length
          if (featuresLength > 0) {
            // 遍历所有查询结果,放入results
            for (const feature of featureCollection.features) {
              const popupStr = '<div class="popup-div">' +
                '<div class="popup-title">商户信息</div>' +
                '<div class="dashed-line"></div>' +
                '<div class="popup-item"><label>商户名称</label>' + feature.properties.dutyname + '</div>' +
                '<div class="popup-item"><label>商户编号</label>' + feature.properties.objid + '</div>' +
                // '<div class="popup-item"><label>所在社区</label>' + feature.properties.communame + '</div>' +
                // '<div class="popup-item"><label>所在网格编号</label>' + feature.properties.bgid + '</div>' +
                '<div class="popup-item"><label>三包责任单位</label>' + feature.properties.deptname + '</div>' +
                '<div class="popup-item"><label>详细地址</label>' + feature.properties.position_ + '</div>' +
                '</div>'

              results.push({
                name: feature.properties.dutyname,
                code: feature.properties.objid,
                content: {
                  title: '地址',
                  text: feature.properties.position_
                },
                lng: feature.properties.x,
                lat: feature.properties.y,
                popupStr: popupStr
              })
            }
          }

          this.searchList = results
          this.searchLoading = false
        })
      } else if (this.selectLayers.toString() === '1') {
        // 查询部件
        // 遍历所有图层进行查询
        const partsLength = this.parts.length // 全部部件图层数量
        for (let i = 0; i < partsLength; i++) {
          const part = this.parts[i]
          const str = ['objid', 'xl', 'dl']
          const query = esri.query({ url: part.url })
          let queryString = '1=1' // 默认查询语句
          // 如果有关键字
          if (this.keyword) {
            // 拼接查询语句
            queryString = str.map(item => `(${item} like '%${this.keyword}%')`).join(' OR ')
          } else {
            return
          }
          query.where(queryString)
          // 如果有查询边界
          if (this.bounds) {
            query.within(this.bounds)
          }
          // 执行查询
          query.run((error, featureCollection, response) => {
            if (error) {
              console.log(error)
              return
            }
            const featuresLength = featureCollection.features.length
            if (featuresLength > 0) {
              // 遍历所有查询结果,放入results
              for (const feature of featureCollection.features) {
                const popupStr = '<div class="popup-div">' +
                  '<div class="popup-title">部件信息</div>' +
                  '<div class="dashed-line"></div>' +
                  '<div class="popup-item"><label>部件类型</label>' + feature.properties.dl + ' / ' + feature.properties.xl + '</div>' +
                  '<div class="popup-item"><label>部件编号</label>' + feature.properties.objid + '</div>' +
                  '<div class="popup-item"><label>所在网格编号</label>' + feature.properties.bgid + '</div>' +
                  '<div class="popup-item"><label>权属部门</label>' + feature.properties.deptname2 + '</div>' +
                  '<div class="popup-item"><label>责任部门</label>' + feature.properties.deptname1 + '</div>' +
                  '<div class="popup-item"><label>养护部门</label>' + feature.properties.deptname3 + '</div>' +
                  '</div>'

                results.push({
                  name: feature.properties.dl + ' / ' + feature.properties.xl,
                  code: feature.properties.objid,
                  content: {
                    title: '权属部门',
                    text: feature.properties.deptname2
                  },
                  lng: feature.geometry.coordinates[0],
                  lat: feature.geometry.coordinates[1],
                  popupStr: popupStr
                })
              }
            }
            // 如果是最后一个图层
            if (i === (partsLength - 1)) {
              this.searchList = results
              this.searchLoading = false
            }
          })
        }
      } else {
        this.searchLoading = false
      }
    },
    // 清空查询
    clearSearch() {
      this.searchList = []
      if (this.currentSearchMarkers.length > 0) {
        for (const marker of this.currentSearchMarkers) {
          this.map.removeLayer(marker)
        }
        this.currentSearchMarkers = []
      }
    },
    // 查询结果页面变化,重绘icon
    changeSearchPage(data) {
      // 清除原来绘制的点
      if (this.currentSearchMarkers.length > 0) {
        for (const marker of this.currentSearchMarkers) {
          this.map.removeLayer(marker)
        }
      }
      // 赋予新的查询结果
      const currentMarkesLength = data.length
      for (let i = 0; i < currentMarkesLength; i++) {
        const icon = this.searchIconList[i]
        const latlng = L.latLng([data[i].lat, data[i].lng])
        const item = L.marker(latlng, { icon: icon }).addTo(this.map)
        item.on('click', e => {
          if (item.getPopup()) {
            item.unbindPopup()
          }
          // 绑定弹窗
          const popup = L.popup().setContent(data[i].popupStr)
          item.bindPopup(popup).openPopup([data[i].lat, data[i].lng])
        })
        this.currentSearchMarkers.push(item)
      }
      // 中心置为第一个点的中心
      if (this.currentSearchMarkers[0]) {
        this.clickSearchItem(data[0], 0)
      }
    },
    // 点击查询列表项,将位置放在中间
    clickSearchItem(item, index) {
      if (item) {
        const latlng = L.latLng([item.lat, item.lng])
        let zoom = this.map.getZoom()
        if (zoom < 19) {
          zoom = 19
        }
        this.map.flyTo(latlng, zoom)
        // this.currentSearchMarkers[index].openPopup()
      }
    },
    // 移除框选区域
    drawDelete() {
      if (this.drawLayer) {
        this.drawLayer.layer.remove()
      }
      this.bounds = null
      this.search()
    },
    // 绘制选框
    drawBox(type) {
      if (this.drawLayer) {
        this.drawLayer.layer.remove()
      }
      this.bounds = null
      this.$nextTick(() => {
        this.map.pm.enableDraw(type, {
          snappable: false
        })
        // 绘制完成, 选区内重新查询
        this.map.on('pm:create', e => {
          this.clearDisabled = false
          if (this.drawLayer) {
            this.drawLayer.layer.remove()
          }
          this.drawLayer = e
          this.bounds = e.layer._bounds
          this.search()
        })
      })
    },
    // 部件图层切换
    layerChange(node) {
      this.$refs.layerRadio.$refs.layerTree.setCheckedKeys([node.id])
      this.selectLayers = [node.id]

      // 清除查询
      this.clearSearch()
    },
    // 地图初始化
    init() {
      const map = L.map('map', {
        minZoom: 14,
        maxZoom: 25,
        center: this.baseConfig.center,
        zoom: this.baseConfig.zoom,
        zoomControl: false,
        attributionControl: false,
        crs: L.CRS.EPSG3857
      })
      map.doubleClickZoom.disable() // 禁止双击
      this.map = map // data挂载map
      window.map = map

      // 加载天地图底图和标注
      this.baseLayer.push(L.tileLayer(this.baseConfig.mapUrl).addTo(map))
      this.baseLayer.push(L.tileLayer(this.baseConfig.labelUrl).addTo(map))

      // 构建并加载layerGroup
      /* eslint-disable new-cap */
      this.addMapDtLyaer() // 底图

      // 部件图层组
      for (let i = 3; i < 10; i++) {
        this.addPartsLayer(i)
      }
    },
    // 添加底图图层
    addMapDtLyaer: function() {
      const mapDtGroup = new L.layerGroup() // 创建layerGroup

      // 创建图层并加载到layerGroup中
      const item = { url: `${this.baseUrl}${this.mapUrl}` }
      esri.dynamicMapLayer(item).addTo(mapDtGroup)

      this.layerGroups.push(mapDtGroup)
      this.map.addLayer(mapDtGroup)
    },
    addPartsLayer: function(index) {
      const that = this
      const group = new L.layerGroup() // 创建layerGroup

      const domains = this.baseConfig.layers[index].domain
      domains.forEach(dom => {
        // 创建图层并加载到layerGroup中
        const item = { url: `${this.baseUrl}${this.partsUrl}/${dom}`, minZoom: 18 }
        const layer = esri.featureLayer(item).addTo(group)
        this.parts.push(item)

        layer.on('click', function(e) {
          // 获取要素的属性
          const properties = e.layer.feature.properties

          // 弹窗样式
          const popupStr = '<div class="popup-div">' +
            '<div class="popup-title">部件信息</div>' +
            '<div class="dashed-line"></div>' +
            '<div class="popup-item"><label>部件类型</label>' + properties.dl + ' / ' + properties.xl + '</div>' +
            '<div class="popup-item"><label>部件编号</label>' + properties.objid + '</div>' +
            '<div class="popup-item"><label>所在网格编号</label>' + properties.bgid + '</div>' +
            '<div class="popup-item"><label>权属部门</label>' + properties.deptname2 + '</div>' +
            '<div class="popup-item"><label>责任部门</label>' + properties.deptname1 + '</div>' +
            '<div class="popup-item"><label>养护部门</label>' + properties.deptname3 + '</div>' +
            '</div>'
          // 弹出窗口
          L.popup().setContent(popupStr).setLatLng(e.latlng).openOn(that.map)
        })

        that.layerGroups.push(group)
      })
      this.map.addLayer(group)
    },
    // 初始化图标
    initIcons() {
      // 加载所有图标,1到5
      for (let i = 1; i < 6; i++) {
        const icon = L.icon({
          iconUrl: require(`@/assets/global_images/point${i}.png`),
          iconSize: [25, 25],
          iconAnchor: [12, 25],
          popupAnchor: [0, -25]
        })
        this.searchIconList.push(icon)
      }
    },
    handleCurrentChange(val) {
      this.offset = val
      const num = 5 * val >= this.searchList.length ? this.searchList.length : 5 * val
      this.showlist = this.searchList.slice(5 * (val - 1), num)
      this.drawIcon()
    }
  }
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
  /deep/ .el-input-group__append, .el-input-group__prepend {
    background-color: #409eff !important;
    border: 1px solid #409eff !important;
  }
  /*/deep/ .leaflet-touch .leaflet-control-layers, /deep/ .leaflet-touch .leaflet-bar {*/
    /*!*border: 2px solid rgba(0,0,0,0.2);*!*/
    /*!*background-clip: padding-box;*!*/
    /*position: absolute !important;*/
    /*right: 300px !important;*/
    /*top: 10px;*/
  /*}*/
  $tableTitleHeight:35px;
  .leaflet_container{
    width: calc( 100vw - 208px );
    height: calc( 100vh - 158px );
    background-color: white;
  }
  .search-total{
    background-color: white; width: 300px;height: 35px;
    margin-top: 6px;border: 1px solid #DCDFE6;
    padding-left: 15px;color: #409eff;
    padding-top: 8px;
    font-size: 13px;
    border-radius:3px;
  }
  .draw-icon{
    background-color: white;
    width: 100px;height: 40px;
    border: 1px solid #DCDFE6;
    border-radius:4px;
  }
  .table{
    width: 300px;margin-top: 3px;
    border: 1px solid #DCDFE6;
    border-radius:3px;
    /deep/ .el-table th.is-leaf, /deep/ .el-table td {
      border-bottom: 1px solid white !important;
    }
    /deep/ .el-table--group::after, .el-table--border::after, .el-table::before {
      background-color: white !important;
    }
    .table-item{
      padding: 5px;
      margin-top: 2px;
      margin-bottom: 1px;
      -moz-box-shadow: 0px 1px 3px #d9d9d9; /* 老的 Firefox */
      box-shadow: 0px 1px 3px #d9d9d9;
      .item-icon{
        width: 30px;
        height: 30px;
        background-size: contain;
        background-image: url("../../assets/global_images/point.png");
        color: white;
        text-align: center;
        margin-top: 10px;
        margin-left: 5px;
        padding-top: 2px;
      }
    }
  }
  .top_title{
    height: 40px;
    font-size: 18px;
    border: 1px solid #b5b5b5;
    padding-top: 10px;
  }
  .title{
    height: 40px;
    width: 320px;
    padding-top: 10px;
    padding-left: 5px;
    z-index: 100000;
    background-color: rgba(255, 255, 255, 0.91);
  }
  .titletext{
    text-align: center;
    font-size: 15px;
  }
  .titlenumtext{
    text-align: center;
    font-size: 19px;
  }
  .list{
    text-align:center;
    width: 500px;
    height: 40px;
    z-index: 10000;
    position: absolute;
    right:20px;
    top:20px;
  }
  .btn_bottom{
    text-align:center;
    width: 100%;
    height:70px;
    z-index: 1000;
    position: fixed; bottom: 0; left: 0;right:0;
  }
  .table-name{
    position:relative;
    width: 100px;
    top:20px;
    margin:-10px auto; //外面的div高度的一半
    z-index: 100001;
  }
  .right-card{
    margin-top: 20px;position: absolute;right:50px;z-index: 100000;width: 130px;
  }
  .table-title{
    background-color:rgba(243, 243, 243, 1);
    height: $tableTitleHeight;
    .title-header{
      line-height:$tableTitleHeight;
      color: #606266;
      font-size: 15px;
      i{
        margin-left: 5px;
        margin-right: 5px;
      }
    }
  }
</style>

<style>
  .leaflet-container a.leaflet-popup-close-button {
    top: 5px; /* 修改弹窗关闭按钮样式 */
    right: 10px; /* 修改弹窗关闭按钮样式 */
  }

  .leaflet-popup-content .popup-div {
    font-size: 15px;
    padding: 6px;
  }

  .leaflet-popup-content .popup-title {
    font-weight: bold;
  }

  .leaflet-popup-content .dashed-line {
    border-bottom: 1px dashed #dddddd;
    margin: 10px -10px;
  }

  .leaflet-popup-content .popup-item {
    padding-bottom: 6px;
  }

  .leaflet-popup-content .popup-item label {
    font-weight: bold;
    padding-right: 15px;
  }
</style>