<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>