Newer
Older
dcms_front / src / views / baseSource / mapSearch.vue
StephanieGitHub on 17 Mar 2021 14 KB MOD:整合基础资源、地理编码
<template>
  <div>
    <div id="map" class="leaflet_container" style="background-color: white">
      <!--查询显示组件-->
      <search-list
        ref="searchList"
        :total-data="searchList"
        @search="search"
        @change="changeSearchPage"
        @item-click="clickSearchItem"/>
      <!--工具箱-->
      <tools-container>
        <!-- 绘制工具-->
        <draw-tool @click="drawBox"/>
        <!--重置工具-->
        <clear-tool :disabled="clearDisabled" @click="drawDelete"/>
        <!--图层选择工具-->
        <layer-choose :layers="layers" :select-layers="selectLayers" @choose="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: '', // 查询关键字
      map: null, // 地图对象
      drawLayer: null, // 绘制图层(框选)
      bounds: null, // 查询区域
      clearDisabled: true, // 禁用重置按钮
      layers: this.baseConfig.layers, // 所有图层
      selectLayers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], // 选中图层
      maps: [], // 地图图层
      parts: [], // 部件图层
      searchList: [], // 全部查询结果
      featureCollection: [], // 选中的图层和Feature
      featureCollectionLength: 0, // 选中的feature个数
      currentSearchMarkers: [], // 当前查询页面的markers
      searchIconList: [] // 查询结果的Icon列表
    }
  },
  computed:{
    ...mapGetters([
      'baseUrl',
      'partsUrl',
      'partsAllUrl',
      'mapUrl',
      'partsEditUrl'
    ])
  },
  destroyed() {
    window.removeEventListener('click', this.handleKeyup, true)
    this.socket.close()
  },
  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
      } // 其他不予处理
      var that = this
      const results = [] // 存放查询结果列表
      // 遍历所有图层进行查询
      const partsLength = this.parts.length // 全部部件图层数量
      for (let i = 0; i < partsLength; i++) {
        const part = this.parts[i]
        var str = ['编码', '小类名称', '大类名称']
        var query = esri.query({ url: part.options.url })
        let queryString = '1=1' // 默认查询语句
        // 如果有关键字
        if (keyword) {
          // 拼接查询语句
          queryString = str.map(item => `(${item} like '%${keyword}%')`).join(' OR ')
          console.log(queryString)
        } 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) {
              results.push({
                layer: part,
                feature: feature
              })
            }
          }
          // 如果是最后一个图层
          if (i === (partsLength - 1)) {
            this.searchList = results
          }
        })
      }
    },
    // 查询结果页面变化,重绘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 feature = data[i].feature
        var icon = this.searchIconList[i]
        const latlng = L.latLng([feature.geometry.coordinates[1], feature.geometry.coordinates[0]])
        var item = L.marker(latlng, { icon: icon, layer: data[i].layer, properties: feature.properties }).addTo(this.map)
        this.currentSearchMarkers.push(item)
        item.on('click', function(e) {
          console.log(e)
          if (e.target.dragging._marker._popup) {
            e.target.dragging._marker.unbindPopup()
          }
          const properties = feature.properties
          var str = `<div class="pop-window">
                        <div class="pop-title">
                          ${properties['小类名称']}
                        </div>
                        <div class="pop-line"><col>大类:</col>${properties['大类名称']}</div>
                        <div class="pop-line"><col>小类:</col>${properties['小类名称']}</div>
                        <div class="pop-line"><col>部件编码:</col>${properties['编码']}</div>
                        <div class="pop-line"><col>权属单位:</col>${properties['权属单位'] ? properties.权属单位 : '未知'}</div>
                        <div class="pop-line"><col>详细地址:</col>${properties['详细地址'] ? properties.详细地址 : '未知'}</div>
                      <div>`
          var popup = L.popup().setContent(str)
          e.target.dragging._marker.bindPopup(popup).openPopup()
          // e.target.dragging._marker.openPopup()
        })
      }
      // 中心置为第一个点的中心
      if (this.currentSearchMarkers[0]) {
        this.clickSearchItem(data[0])
      }
    },
    // 点击查询列表项,将位置放在中间
    clickSearchItem(item, index) {
      console.log('clickItem')
      if (item) {
        const feature = item.feature
        const latlng = L.latLng([feature.geometry.coordinates[1], feature.geometry.coordinates[0]])
        let zoom = this.map.getZoom()
        if (zoom < 19) {
          zoom = 19
        }
        this.map.flyTo(latlng, zoom)
      }
    },
    // 移除框选区域
    drawDelete() {
      if (this.drawLayer) {
        this.drawLayer.layer.remove()
      }
      this.bounds = null
      this.search()
    },
    // 绘制选框
    drawBox(type) {
      this.drawDelete()
      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, checked) {
      const selectItem = this.layers.filter(item => item.name === node.name)[0]
      // 如果选中底图,选中添加,没选中移除
      if (selectItem.type === 'map') {
        if (!checked) {
          for (const item of this.maps) {
            this.map.removeLayer(item)
          }
        } else {
          for (const item of this.maps) {
            this.map.addLayer(item)
          }
        }
      } else if (node.type === 'layer') { // 其他图层
        if (!checked) {
          for (let i = 0; i < selectItem.domain.length; i++) {
            this.map.removeLayer(this.parts[selectItem.domain[i] - 1])
          }
        } else {
          for (let i = 0; i < selectItem.domain.length; i++) {
            this.map.addLayer(this.parts[selectItem.domain[i] - 1])
          }
        }
      }
    },
    // 地图初始化
    init() {
      const map = L.map('map', {
        minZoom: 4,
        maxZoom: 21,
        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
      const that = this
      // 添加底图
      for (let i = 0; i <= 21; i++) {
        const item = { url: `${this.baseUrl}${this.mapUrl}/${i}` }
        this.maps.push(esri.featureLayer(item).addTo(map))
      }
      // TODO: 添加部件:可优化为读取配置文件里的部件图层信息
      // 添加部件,
      // const partsLayer = this.baseConfig.partsLayer
      for (let i = 1; i <= 40; i++) {
        let item = { url: `${this.baseUrl}${this.partsUrl}/${i}`, minZoom: 18 }
        console.log(item)
        if (i === 15) {
          item = {
            url: `${this.baseUrl}${this.partsUrl}/${i}`,
            minZoom: 18,
            style: function(feature) {
              return { color: '#ff0000', opacity: 0.75, weight: 5 }
            }
          }
        }
        var layer = esri.featureLayer(item).addTo(map)
        // 点击部件事件
        layer.on('click', function(e) {
          // 获取要素的属性
          const properties = e.layer.feature.properties
          that.currentItem = e.layer.feature
          that.searchLayerByUrl(e.layer.options.url)
          // 弹窗样式
          var str = `<div class="pop-window">
                        <div class="pop-title">
                          ${properties['小类名称']}
                        </div>
                        <div class="pop-line"><col>大类:</col>${properties['大类名称']}</div>
                        <div class="pop-line"><col>小类:</col>${properties['小类名称']}</div>
                        <div class="pop-line"><col>部件编码:</col>${properties['编码']}</div>
                        <div class="pop-line"><col>权属单位:</col>${properties['权属单位'] ? properties.权属单位 : '未知'}</div>
                        <div class="pop-line"><col>详细地址:</col>${properties['详细地址'] ? properties.详细地址 : '未知'}</div>
                      <div>`
          var popup = L.popup().setContent(str)
          e.layer.dragging._marker.bindPopup(popup, { minWidth: 200 }).openPopup()
        })
        this.parts.push(layer)
      }
      // this.map.setZoom(15)
    },
    // 初始化图标
    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.5, 25]
        })
        this.searchIconList.push(icon)
      }
    },
    handleCurrentChange(val) {
      this.offset = val
      var num = 5 * val >= this.searchlist.length ? this.searchlist.length : 5 * val
      this.showlist = this.searchlist.slice(5 * (val - 1), num)
      this.drawIcon()
    },
    // 根据url找到layer
    searchLayerByUrl(url) {
      const layer = this.parts.filter(item => item.options.url === url)[0]
      if (layer) {
        this.currentLayer = layer
      }
    }
  }
}
</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: 100%;
    height: 84vh;
  }
  .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>