|
|
|
@ -50,12 +50,61 @@ |
|
|
|
<Icon type="ios-close" class="ivu-icon-ios-close" /> |
|
|
|
</a> |
|
|
|
</div> |
|
|
|
<div :id="id" :style="{ width: '100%', height: modalHeight }"></div> |
|
|
|
<div class="amap-panel"> |
|
|
|
<div v-if="searchable" class="amap-search"> |
|
|
|
<Input |
|
|
|
v-model="keyword" |
|
|
|
search |
|
|
|
enter-button="搜索" |
|
|
|
placeholder="搜索校区/地点名称" |
|
|
|
@on-search="searchPlace" |
|
|
|
/> |
|
|
|
<Button |
|
|
|
v-if="locate" |
|
|
|
class="amap-locate-btn" |
|
|
|
size="small" |
|
|
|
icon="md-locate" |
|
|
|
:loading="locating" |
|
|
|
@click="locateByAmap" |
|
|
|
>定位到当前位置</Button |
|
|
|
> |
|
|
|
<ul v-if="searchResults.length" class="amap-search-list"> |
|
|
|
<li |
|
|
|
v-for="(item, index) in searchResults" |
|
|
|
:key="index" |
|
|
|
@click="selectSearchResult(item)" |
|
|
|
> |
|
|
|
<div class="name">{{ item.name }}</div> |
|
|
|
<div class="addr">{{ item.address || item.district || "" }}</div> |
|
|
|
</li> |
|
|
|
</ul> |
|
|
|
</div> |
|
|
|
<div |
|
|
|
v-else-if="locate" |
|
|
|
class="amap-locate-only" |
|
|
|
> |
|
|
|
<Button |
|
|
|
size="small" |
|
|
|
icon="md-locate" |
|
|
|
:loading="locating" |
|
|
|
@click="locateByAmap" |
|
|
|
>定位到当前位置</Button |
|
|
|
> |
|
|
|
</div> |
|
|
|
<div |
|
|
|
:id="id" |
|
|
|
class="amap-container" |
|
|
|
:style="{ width: '100%', height: modalHeight }" |
|
|
|
></div> |
|
|
|
</div> |
|
|
|
<div slot="footer"> |
|
|
|
<Row align="middle" justify="space-between"> |
|
|
|
<Alert show-icon style="margin-bottom: 0" |
|
|
|
>当前选点坐标:{{ currentValue }}</Alert |
|
|
|
> |
|
|
|
<div style="flex: 1; margin-right: 12px"> |
|
|
|
<Alert show-icon style="margin-bottom: 0" |
|
|
|
>当前选点坐标:{{ currentValue || "未选择" }}</Alert |
|
|
|
> |
|
|
|
<div class="locate-tip">坐标为高德 GCJ-02;可搜索、定位或点击地图选点</div> |
|
|
|
</div> |
|
|
|
<div> |
|
|
|
<Button type="text" @click="showModal = false">取消</Button> |
|
|
|
<Button type="primary" @click="handelSubmit">确认提交</Button> |
|
|
|
@ -65,9 +114,10 @@ |
|
|
|
</Modal> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
<script> |
|
|
|
import mapboxgl from "mapbox-gl"; |
|
|
|
import MapboxGeocoder from "@mapbox/mapbox-gl-geocoder"; |
|
|
|
import { loadAmap, getAmapLocation } from "@/libs/amapLoader"; |
|
|
|
|
|
|
|
export default { |
|
|
|
name: "map", |
|
|
|
props: { |
|
|
|
@ -91,10 +141,6 @@ export default { |
|
|
|
type: Number, |
|
|
|
default: 900, |
|
|
|
}, |
|
|
|
pitch: { |
|
|
|
type: Number, |
|
|
|
default: 0 |
|
|
|
}, |
|
|
|
decimal: { |
|
|
|
type: Number, |
|
|
|
default: 6, |
|
|
|
@ -131,367 +177,266 @@ export default { |
|
|
|
type: String, |
|
|
|
default: "md-locate", |
|
|
|
}, |
|
|
|
style: { |
|
|
|
type: String, |
|
|
|
default: "mapbox://styles/mapbox/streets-v11", |
|
|
|
}, |
|
|
|
center: { |
|
|
|
type: Array, |
|
|
|
default: [116.35, 39.85], |
|
|
|
default: () => [116.397428, 39.90923], |
|
|
|
}, |
|
|
|
zoom: { |
|
|
|
type: Number, |
|
|
|
default: 9, |
|
|
|
}, |
|
|
|
compact: { |
|
|
|
type: Boolean, |
|
|
|
default: true, |
|
|
|
}, |
|
|
|
customAttribution: { |
|
|
|
type: String, |
|
|
|
default: "", |
|
|
|
default: 12, |
|
|
|
}, |
|
|
|
searchable: { |
|
|
|
type: Boolean, |
|
|
|
default: true, |
|
|
|
}, |
|
|
|
changeStyle: { |
|
|
|
type: Boolean, |
|
|
|
default: true, |
|
|
|
}, |
|
|
|
navigation: { |
|
|
|
type: Boolean, |
|
|
|
default: true, |
|
|
|
}, |
|
|
|
locate: { |
|
|
|
type: Boolean, |
|
|
|
default: true, |
|
|
|
}, |
|
|
|
fullscreen: { |
|
|
|
type: Boolean, |
|
|
|
default: false, |
|
|
|
}, |
|
|
|
building3D: { |
|
|
|
type: Boolean, |
|
|
|
default: true, |
|
|
|
}, |
|
|
|
}, |
|
|
|
data() { |
|
|
|
return { |
|
|
|
data: this.value, |
|
|
|
mapbox: null, |
|
|
|
map: null, |
|
|
|
marker: null, |
|
|
|
placeSearch: null, |
|
|
|
currentValue: "", |
|
|
|
showModal: false, |
|
|
|
full: false, |
|
|
|
modalHeight: "500px", |
|
|
|
marker: null, |
|
|
|
keyword: "", |
|
|
|
searchResults: [], |
|
|
|
locating: false, |
|
|
|
mapReady: false, |
|
|
|
}; |
|
|
|
}, |
|
|
|
methods: { |
|
|
|
init() { |
|
|
|
if (!config.mapboxToken) { |
|
|
|
return; |
|
|
|
getAmapKey() { |
|
|
|
return (typeof config !== "undefined" && config.amapKey) || ""; |
|
|
|
}, |
|
|
|
getSecurityCode() { |
|
|
|
return (typeof config !== "undefined" && config.amapSecurityJsCode) || ""; |
|
|
|
}, |
|
|
|
formatLngLat(lng, lat) { |
|
|
|
let decimal = this.decimal; |
|
|
|
if (decimal < 0) decimal = 0; |
|
|
|
if (decimal > 14) decimal = 14; |
|
|
|
return Number(lng).toFixed(decimal) + ", " + Number(lat).toFixed(decimal); |
|
|
|
}, |
|
|
|
parsePosition(value) { |
|
|
|
if (!value || !String(value).trim()) return null; |
|
|
|
const parts = String(value).split(","); |
|
|
|
if (parts.length < 2) return null; |
|
|
|
const lng = Number(parts[0].trim()); |
|
|
|
const lat = Number(parts[1].trim()); |
|
|
|
if (!Number.isFinite(lng) || !Number.isFinite(lat)) return null; |
|
|
|
return { lng, lat }; |
|
|
|
}, |
|
|
|
ensureMap() { |
|
|
|
if (this.map) { |
|
|
|
return Promise.resolve(this.map); |
|
|
|
} |
|
|
|
mapboxgl.accessToken = config.mapboxToken; |
|
|
|
this.mapbox = new mapboxgl.Map({ |
|
|
|
container: this.id, |
|
|
|
style: this.style, |
|
|
|
center: this.center, |
|
|
|
zoom: this.zoom, |
|
|
|
pitch: this.pitch, |
|
|
|
attributionControl: false, |
|
|
|
}); |
|
|
|
// 属性 |
|
|
|
this.mapbox.addControl( |
|
|
|
new mapboxgl.AttributionControl({ |
|
|
|
compact: this.compact, |
|
|
|
customAttribution: this.customAttribution, |
|
|
|
}) |
|
|
|
); |
|
|
|
// 搜索 |
|
|
|
if (this.searchable) { |
|
|
|
this.mapbox.addControl( |
|
|
|
new MapboxGeocoder({ |
|
|
|
accessToken: mapboxgl.accessToken, |
|
|
|
mapboxgl: mapboxgl, |
|
|
|
}) |
|
|
|
); |
|
|
|
const key = this.getAmapKey(); |
|
|
|
if (!key) { |
|
|
|
return Promise.reject(new Error("未配置高德地图 Key")); |
|
|
|
} |
|
|
|
// 地图样式切换 |
|
|
|
class ChangeStyleControl { |
|
|
|
getDefaultPosition() { |
|
|
|
const defaultPosition = "top-right"; |
|
|
|
return defaultPosition; |
|
|
|
} |
|
|
|
onAdd(map) { |
|
|
|
this.map = map; |
|
|
|
this.controlContainer = document.createElement("div"); |
|
|
|
this.controlContainer.classList.add("mapboxgl-ctrl"); |
|
|
|
this.controlContainer.classList.add("mapboxgl-ctrl-group"); |
|
|
|
this.mapStyleContainer = document.createElement("div"); |
|
|
|
this.styleButton = document.createElement("button"); |
|
|
|
this.styleButton.type = "button"; |
|
|
|
this.mapStyleContainer.classList.add("mapboxgl-style-list"); |
|
|
|
const defaultStyle = "街道地图"; |
|
|
|
const styles = [ |
|
|
|
{ title: "街道地图", uri: "mapbox://styles/mapbox/streets-v11" }, |
|
|
|
{ |
|
|
|
title: "卫星街道", |
|
|
|
uri: "mapbox://styles/mapbox/satellite-streets-v11", |
|
|
|
}, |
|
|
|
{ title: "暗黑风格", uri: "mapbox://styles/mapbox/dark-v10" }, |
|
|
|
{ title: "明亮风格", uri: "mapbox://styles/mapbox/light-v10" }, |
|
|
|
{ title: "户外地图", uri: "mapbox://styles/mapbox/outdoors-v11" }, |
|
|
|
{ title: "卫星地图", uri: "mapbox://styles/mapbox/satellite-v9" }, |
|
|
|
]; |
|
|
|
for (const style of styles) { |
|
|
|
const styleElement = document.createElement("button"); |
|
|
|
styleElement.type = "button"; |
|
|
|
styleElement.innerText = style.title; |
|
|
|
styleElement.classList.add( |
|
|
|
style.title.replace(/[^a-z0-9-]/gi, "_") |
|
|
|
); |
|
|
|
styleElement.dataset.uri = JSON.stringify(style.uri); |
|
|
|
styleElement.addEventListener("click", (event) => { |
|
|
|
const srcElement = event.srcElement; |
|
|
|
if (srcElement.classList.contains("active")) { |
|
|
|
return; |
|
|
|
} |
|
|
|
this.map.setStyle(JSON.parse(srcElement.dataset.uri)); |
|
|
|
setTimeout(() => { |
|
|
|
const labelList = this.map.getStyle().layers.filter((layer) => { |
|
|
|
return /-label/.test(layer.id); |
|
|
|
}); |
|
|
|
for (let labelLayer of labelList) { |
|
|
|
this.map.setLayoutProperty(labelLayer.id, "text-field", [ |
|
|
|
"coalesce", |
|
|
|
["get", "name_zh-Hans"], |
|
|
|
["get", "name"], |
|
|
|
]); |
|
|
|
} |
|
|
|
}, 500); |
|
|
|
this.mapStyleContainer.style.display = "none"; |
|
|
|
this.styleButton.style.display = "block"; |
|
|
|
const elms = this.mapStyleContainer.getElementsByClassName( |
|
|
|
"active" |
|
|
|
return loadAmap(key, this.getSecurityCode()).then((AMap) => { |
|
|
|
const centerPos = this.parsePosition(this.data) || { |
|
|
|
lng: this.center[0], |
|
|
|
lat: this.center[1], |
|
|
|
}; |
|
|
|
this.map = new AMap.Map(this.id, { |
|
|
|
zoom: this.parsePosition(this.data) ? 16 : this.zoom, |
|
|
|
center: [centerPos.lng, centerPos.lat], |
|
|
|
resizeEnable: true, |
|
|
|
mapStyle: "amap://styles/normal", |
|
|
|
}); |
|
|
|
this.map.on("click", (e) => { |
|
|
|
if (!e || !e.lnglat) return; |
|
|
|
this.placeMarker(e.lnglat.getLng(), e.lnglat.getLat()); |
|
|
|
}); |
|
|
|
return new Promise((resolve) => { |
|
|
|
AMap.plugin( |
|
|
|
["AMap.ToolBar", "AMap.Scale", "AMap.PlaceSearch", "AMap.Geolocation"], |
|
|
|
() => { |
|
|
|
this.map.addControl( |
|
|
|
new AMap.ToolBar({ |
|
|
|
position: "RB", |
|
|
|
locate: false, |
|
|
|
}) |
|
|
|
); |
|
|
|
while (elms[0]) { |
|
|
|
elms[0].classList.remove("active"); |
|
|
|
} |
|
|
|
srcElement.classList.add("active"); |
|
|
|
}); |
|
|
|
if (style.title === defaultStyle) { |
|
|
|
styleElement.classList.add("active"); |
|
|
|
this.map.addControl(new AMap.Scale({ position: "LB" })); |
|
|
|
this.placeSearch = new AMap.PlaceSearch({ |
|
|
|
pageSize: 8, |
|
|
|
pageIndex: 1, |
|
|
|
citylimit: false, |
|
|
|
}); |
|
|
|
this.mapReady = true; |
|
|
|
resolve(this.map); |
|
|
|
} |
|
|
|
this.mapStyleContainer.appendChild(styleElement); |
|
|
|
} |
|
|
|
this.styleButton.classList.add("mapboxgl-ctrl-icon"); |
|
|
|
this.styleButton.classList.add("mapboxgl-style-switcher"); |
|
|
|
this.styleButton.addEventListener("click", () => { |
|
|
|
this.styleButton.style.display = "none"; |
|
|
|
this.mapStyleContainer.style.display = "block"; |
|
|
|
}); |
|
|
|
document.addEventListener("click", this.onDocumentClick); |
|
|
|
this.controlContainer.appendChild(this.styleButton); |
|
|
|
this.controlContainer.appendChild(this.mapStyleContainer); |
|
|
|
return this.controlContainer; |
|
|
|
} |
|
|
|
onRemove() { |
|
|
|
if ( |
|
|
|
!this.controlContainer || |
|
|
|
!this.controlContainer.parentNode || |
|
|
|
!this.map || |
|
|
|
!this.styleButton |
|
|
|
) { |
|
|
|
return; |
|
|
|
} |
|
|
|
this.styleButton.removeEventListener("click", this.onDocumentClick); |
|
|
|
this.controlContainer.parentNode.removeChild(this.controlContainer); |
|
|
|
document.removeEventListener("click", this.onDocumentClick); |
|
|
|
this.map = undefined; |
|
|
|
} |
|
|
|
onDocumentClick(event) { |
|
|
|
if ( |
|
|
|
this.controlContainer && |
|
|
|
!this.controlContainer.contains(event.target) && |
|
|
|
this.mapStyleContainer && |
|
|
|
this.styleButton |
|
|
|
) { |
|
|
|
this.mapStyleContainer.style.display = "none"; |
|
|
|
this.styleButton.style.display = "block"; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (this.changeStyle) { |
|
|
|
this.mapbox.addControl(new ChangeStyleControl()); |
|
|
|
} |
|
|
|
// 导航控件 |
|
|
|
if (this.navigation) { |
|
|
|
this.mapbox.addControl(new mapboxgl.NavigationControl()); |
|
|
|
} |
|
|
|
// 定位 |
|
|
|
if (this.locate) { |
|
|
|
this.mapbox.addControl( |
|
|
|
new mapboxgl.GeolocateControl({ |
|
|
|
positionOptions: { |
|
|
|
enableHighAccuracy: true, |
|
|
|
}, |
|
|
|
trackUserLocation: true, |
|
|
|
}) |
|
|
|
); |
|
|
|
} |
|
|
|
// 全屏 |
|
|
|
if (this.fullscreen) { |
|
|
|
this.mapbox.addControl( |
|
|
|
new mapboxgl.FullscreenControl({ |
|
|
|
container: document.querySelector("body"), |
|
|
|
}) |
|
|
|
); |
|
|
|
} |
|
|
|
this.mapbox.on("load", () => { |
|
|
|
// 中文 |
|
|
|
const labelList = this.mapbox.getStyle().layers.filter((layer) => { |
|
|
|
return /-label/.test(layer.id); |
|
|
|
); |
|
|
|
}); |
|
|
|
for (let labelLayer of labelList) { |
|
|
|
this.mapbox.setLayoutProperty(labelLayer.id, "text-field", [ |
|
|
|
"coalesce", |
|
|
|
["get", "name_zh-Hans"], |
|
|
|
["get", "name"], |
|
|
|
]); |
|
|
|
} |
|
|
|
// 3D建筑 |
|
|
|
if (this.building3D) { |
|
|
|
this.mapbox.addLayer({ |
|
|
|
id: "3d-buildings", |
|
|
|
source: "composite", |
|
|
|
"source-layer": "building", |
|
|
|
filter: ["==", "extrude", "true"], |
|
|
|
type: "fill-extrusion", |
|
|
|
minzoom: 15, |
|
|
|
paint: { |
|
|
|
"fill-extrusion-color": "#aaa", |
|
|
|
"fill-extrusion-height": [ |
|
|
|
"interpolate", |
|
|
|
["linear"], |
|
|
|
["zoom"], |
|
|
|
15, |
|
|
|
0, |
|
|
|
15.05, |
|
|
|
["get", "height"], |
|
|
|
], |
|
|
|
"fill-extrusion-base": [ |
|
|
|
"interpolate", |
|
|
|
["linear"], |
|
|
|
["zoom"], |
|
|
|
15, |
|
|
|
0, |
|
|
|
15.05, |
|
|
|
["get", "min_height"], |
|
|
|
], |
|
|
|
"fill-extrusion-opacity": 0.6, |
|
|
|
}, |
|
|
|
}); |
|
|
|
// 显示点 |
|
|
|
this.flyTo(); |
|
|
|
} |
|
|
|
}); |
|
|
|
// 单点标记 |
|
|
|
this.mapbox.on("click", (e) => { |
|
|
|
}, |
|
|
|
placeMarker(lng, lat, zoom) { |
|
|
|
if (!this.map || typeof window.AMap === "undefined") return; |
|
|
|
if (this.marker) { |
|
|
|
this.marker.setMap(null); |
|
|
|
this.marker = null; |
|
|
|
} |
|
|
|
this.marker = new window.AMap.Marker({ |
|
|
|
position: [lng, lat], |
|
|
|
draggable: this.draggable, |
|
|
|
cursor: "move", |
|
|
|
}); |
|
|
|
this.marker.setMap(this.map); |
|
|
|
if (this.draggable) { |
|
|
|
this.marker.on("dragend", (e) => { |
|
|
|
const pos = e.lnglat || (e.target && e.target.getPosition()); |
|
|
|
if (!pos) return; |
|
|
|
const nextLng = typeof pos.getLng === "function" ? pos.getLng() : pos.lng; |
|
|
|
const nextLat = typeof pos.getLat === "function" ? pos.getLat() : pos.lat; |
|
|
|
this.currentValue = this.formatLngLat(nextLng, nextLat); |
|
|
|
this.$emit("on-click", this.currentValue); |
|
|
|
}); |
|
|
|
} |
|
|
|
this.currentValue = this.formatLngLat(lng, lat); |
|
|
|
this.$emit("on-click", this.currentValue); |
|
|
|
this.map.setZoomAndCenter(zoom || Math.max(this.map.getZoom(), 16), [ |
|
|
|
lng, |
|
|
|
lat, |
|
|
|
]); |
|
|
|
}, |
|
|
|
syncMarkerFromValue() { |
|
|
|
const pos = this.parsePosition(this.data); |
|
|
|
if (pos) { |
|
|
|
this.currentValue = this.data; |
|
|
|
this.placeMarker(pos.lng, pos.lat, 16); |
|
|
|
} else { |
|
|
|
this.currentValue = ""; |
|
|
|
if (this.marker) { |
|
|
|
this.marker.remove(); |
|
|
|
} |
|
|
|
this.marker = new mapboxgl.Marker({ |
|
|
|
offset: [0, -25], |
|
|
|
draggable: this.draggable, |
|
|
|
}) |
|
|
|
.setLngLat([e.lngLat.lng, e.lngLat.lat]) |
|
|
|
.addTo(this.mapbox); |
|
|
|
if (this.decimal < 0) { |
|
|
|
this.decimal = 0; |
|
|
|
this.marker.setMap(null); |
|
|
|
this.marker = null; |
|
|
|
} |
|
|
|
if (this.decimal > 14) { |
|
|
|
this.decimal = 14; |
|
|
|
if (this.map) { |
|
|
|
this.map.setZoomAndCenter(this.zoom, this.center); |
|
|
|
} |
|
|
|
let lng = e.lngLat.lng.toFixed(this.decimal); |
|
|
|
let lat = e.lngLat.lat.toFixed(this.decimal); |
|
|
|
this.currentValue = lng + ", " + lat; |
|
|
|
this.$emit("on-click", this.currentValue); |
|
|
|
}); |
|
|
|
} |
|
|
|
}, |
|
|
|
flyTo() { |
|
|
|
if (this.data) { |
|
|
|
try { |
|
|
|
let lngLat = this.data.split(","); |
|
|
|
let lng = lngLat[0].trim(); |
|
|
|
let lat = lngLat[1].trim(); |
|
|
|
this.currentValue = this.data; |
|
|
|
if (this.marker) { |
|
|
|
this.marker.remove(); |
|
|
|
searchPlace() { |
|
|
|
const keyword = (this.keyword || "").trim(); |
|
|
|
if (!keyword) { |
|
|
|
this.searchResults = []; |
|
|
|
return; |
|
|
|
} |
|
|
|
this.ensureMap() |
|
|
|
.then(() => { |
|
|
|
if (!this.placeSearch) { |
|
|
|
this.$Message.warning("搜索组件未就绪,请稍后重试"); |
|
|
|
return; |
|
|
|
} |
|
|
|
this.marker = new mapboxgl.Marker({ |
|
|
|
offset: [0, -25], |
|
|
|
draggable: true, |
|
|
|
}) |
|
|
|
.setLngLat([lng, lat]) |
|
|
|
.addTo(this.mapbox); |
|
|
|
this.mapbox.flyTo({ |
|
|
|
center: [lng, lat], |
|
|
|
essential: true, |
|
|
|
this.placeSearch.search(keyword, (status, result) => { |
|
|
|
if (status === "complete" && result && result.poiList) { |
|
|
|
this.searchResults = result.poiList.pois || []; |
|
|
|
if (!this.searchResults.length) { |
|
|
|
this.$Message.info("未找到相关地点"); |
|
|
|
} |
|
|
|
} else { |
|
|
|
this.searchResults = []; |
|
|
|
this.$Message.warning("搜索失败,请换个关键词试试"); |
|
|
|
} |
|
|
|
}); |
|
|
|
} catch (error) { |
|
|
|
this.$Message.error("您输入的坐标不合法"); |
|
|
|
} |
|
|
|
} else { |
|
|
|
this.currentValue = ""; |
|
|
|
if (this.marker) { |
|
|
|
this.marker.remove(); |
|
|
|
} |
|
|
|
this.mapbox.flyTo({ |
|
|
|
center: this.center, |
|
|
|
zoom: 9, |
|
|
|
essential: true, |
|
|
|
}) |
|
|
|
.catch((err) => { |
|
|
|
this.$Message.error((err && err.message) || "地图初始化失败"); |
|
|
|
}); |
|
|
|
}, |
|
|
|
selectSearchResult(item) { |
|
|
|
if (!item || !item.location) return; |
|
|
|
const lng = item.location.lng; |
|
|
|
const lat = item.location.lat; |
|
|
|
this.placeMarker(lng, lat, 17); |
|
|
|
this.searchResults = []; |
|
|
|
this.keyword = item.name || this.keyword; |
|
|
|
}, |
|
|
|
locateByAmap() { |
|
|
|
if (!this.getAmapKey()) { |
|
|
|
this.$Message.warning("请先在 config.js 配置高德地图 Key"); |
|
|
|
return; |
|
|
|
} |
|
|
|
this.locating = true; |
|
|
|
const loading = this.$Message.loading({ |
|
|
|
content: "正在定位...", |
|
|
|
duration: 0, |
|
|
|
}); |
|
|
|
this.ensureMap() |
|
|
|
.then(() => getAmapLocation(this.getAmapKey(), this.getSecurityCode())) |
|
|
|
.then((pos) => { |
|
|
|
loading(); |
|
|
|
this.locating = false; |
|
|
|
this.placeMarker(pos.lng, pos.lat, 17); |
|
|
|
if (pos.accuracy && pos.accuracy > 1000) { |
|
|
|
this.$Message.warning( |
|
|
|
`定位成功,精度约 ${Math.round(pos.accuracy)} 米,请核对后确认` |
|
|
|
); |
|
|
|
} else { |
|
|
|
this.$Message.success( |
|
|
|
pos.address ? `定位成功:${pos.address}` : "定位成功" |
|
|
|
); |
|
|
|
} |
|
|
|
}) |
|
|
|
.catch((err) => { |
|
|
|
loading(); |
|
|
|
this.locating = false; |
|
|
|
this.$Message.error( |
|
|
|
(err && err.message) || "定位失败,请搜索或手动点击地图选点" |
|
|
|
); |
|
|
|
}); |
|
|
|
}, |
|
|
|
handleChange(v) { |
|
|
|
handleChange() { |
|
|
|
this.$emit("input", this.data); |
|
|
|
this.$emit("on-change", this.data); |
|
|
|
}, |
|
|
|
setData(value) { |
|
|
|
if (!this.mapbox) { |
|
|
|
this.init(); |
|
|
|
} |
|
|
|
if (value != this.data) { |
|
|
|
this.data = value; |
|
|
|
this.$emit("input", this.data); |
|
|
|
this.$emit("on-change", this.data); |
|
|
|
} |
|
|
|
if (this.showModal && this.map) { |
|
|
|
this.syncMarkerFromValue(); |
|
|
|
} |
|
|
|
}, |
|
|
|
handleFull() { |
|
|
|
this.full = !this.full; |
|
|
|
if (this.full) { |
|
|
|
this.modalHeight = "100%"; |
|
|
|
} else { |
|
|
|
this.modalHeight = "500px"; |
|
|
|
} |
|
|
|
setTimeout(() => { |
|
|
|
this.mapbox.resize(); |
|
|
|
}, 10); |
|
|
|
this.modalHeight = this.full ? "100%" : "500px"; |
|
|
|
this.$nextTick(() => { |
|
|
|
if (this.map) { |
|
|
|
this.map.resize(); |
|
|
|
} |
|
|
|
}); |
|
|
|
}, |
|
|
|
handleShow() { |
|
|
|
if (!config.mapboxToken) { |
|
|
|
this.$Message.warning("请先配置Mapbox地图的accessToken"); |
|
|
|
if (!this.getAmapKey()) { |
|
|
|
this.$Message.warning("请先在 config.js 配置高德地图 Key"); |
|
|
|
return; |
|
|
|
} |
|
|
|
this.showModal = true; |
|
|
|
}, |
|
|
|
changeModal(v) { |
|
|
|
if (v) { |
|
|
|
setTimeout(() => { |
|
|
|
this.mapbox.resize(); |
|
|
|
this.flyTo(); |
|
|
|
}, 10); |
|
|
|
this.$nextTick(() => { |
|
|
|
this.ensureMap() |
|
|
|
.then(() => { |
|
|
|
this.map.resize(); |
|
|
|
this.syncMarkerFromValue(); |
|
|
|
}) |
|
|
|
.catch((err) => { |
|
|
|
this.$Message.error((err && err.message) || "地图初始化失败"); |
|
|
|
}); |
|
|
|
}); |
|
|
|
} else { |
|
|
|
this.searchResults = []; |
|
|
|
} |
|
|
|
}, |
|
|
|
handelSubmit() { |
|
|
|
@ -502,9 +447,13 @@ export default { |
|
|
|
}, |
|
|
|
}, |
|
|
|
beforeDestroy() { |
|
|
|
// 调用销毁 API 对当前编辑器实例进行销毁 |
|
|
|
if (this.mapbox != null) { |
|
|
|
this.mapbox.remove(); |
|
|
|
if (this.marker) { |
|
|
|
this.marker.setMap(null); |
|
|
|
this.marker = null; |
|
|
|
} |
|
|
|
if (this.map) { |
|
|
|
this.map.destroy(); |
|
|
|
this.map = null; |
|
|
|
} |
|
|
|
}, |
|
|
|
watch: { |
|
|
|
@ -512,49 +461,76 @@ export default { |
|
|
|
this.setData(val); |
|
|
|
}, |
|
|
|
}, |
|
|
|
mounted() { |
|
|
|
this.init(); |
|
|
|
}, |
|
|
|
}; |
|
|
|
</script> |
|
|
|
<style lang="less"> |
|
|
|
.mapboxgl-style-list { |
|
|
|
display: none; |
|
|
|
} |
|
|
|
|
|
|
|
.mapboxgl-ctrl-group .mapboxgl-style-list button { |
|
|
|
background: none; |
|
|
|
border: none; |
|
|
|
cursor: pointer; |
|
|
|
display: block; |
|
|
|
font-size: 14px; |
|
|
|
padding: 8px 8px 6px; |
|
|
|
text-align: right; |
|
|
|
width: 100%; |
|
|
|
height: auto; |
|
|
|
<style lang="less"> |
|
|
|
.map-modal { |
|
|
|
.ivu-modal-body { |
|
|
|
padding: 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.mapboxgl-style-list button.active { |
|
|
|
font-weight: bold; |
|
|
|
.amap-panel { |
|
|
|
position: relative; |
|
|
|
} |
|
|
|
|
|
|
|
.mapboxgl-style-list button:hover { |
|
|
|
background-color: rgba(0, 0, 0, 0.05); |
|
|
|
.amap-search { |
|
|
|
position: absolute; |
|
|
|
top: 12px; |
|
|
|
left: 12px; |
|
|
|
z-index: 120; |
|
|
|
width: 320px; |
|
|
|
} |
|
|
|
|
|
|
|
.mapboxgl-style-list button + button { |
|
|
|
border-top: 1px solid #ddd; |
|
|
|
.amap-locate-btn { |
|
|
|
margin-top: 8px; |
|
|
|
background: #fff; |
|
|
|
} |
|
|
|
|
|
|
|
.mapboxgl-style-switcher { |
|
|
|
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJDYXBhXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iNTQuODQ5cHgiIGhlaWdodD0iNTQuODQ5cHgiIHZpZXdCb3g9IjAgMCA1NC44NDkgNTQuODQ5IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1NC44NDkgNTQuODQ5OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PGc+PGc+PGc+PHBhdGggZD0iTTU0LjQ5NywzOS42MTRsLTEwLjM2My00LjQ5bC0xNC45MTcsNS45NjhjLTAuNTM3LDAuMjE0LTEuMTY1LDAuMzE5LTEuNzkzLDAuMzE5Yy0wLjYyNywwLTEuMjU0LTAuMTA0LTEuNzktMC4zMThsLTE0LjkyMS01Ljk2OEwwLjM1MSwzOS42MTRjLTAuNDcyLDAuMjAzLTAuNDY3LDAuNTI0LDAuMDEsMC43MTZMMjYuNTYsNTAuODFjMC40NzcsMC4xOTEsMS4yNTEsMC4xOTEsMS43MjksMEw1NC40ODgsNDAuMzNDNTQuOTY0LDQwLjEzOSw1NC45NjksMzkuODE3LDU0LjQ5NywzOS42MTR6Ii8+PHBhdGggZD0iTTU0LjQ5NywyNy41MTJsLTEwLjM2NC00LjQ5MWwtMTQuOTE2LDUuOTY2Yy0wLjUzNiwwLjIxNS0xLjE2NSwwLjMyMS0xLjc5MiwwLjMyMWMtMC42MjgsMC0xLjI1Ni0wLjEwNi0xLjc5My0wLjMyMWwtMTQuOTE4LTUuOTY2TDAuMzUxLDI3LjUxMmMtMC40NzIsMC4yMDMtMC40NjcsMC41MjMsMC4wMSwwLjcxNkwyNi41NiwzOC43MDZjMC40NzcsMC4xOSwxLjI1MSwwLjE5LDEuNzI5LDBsMjYuMTk5LTEwLjQ3OUM1NC45NjQsMjguMDM2LDU0Ljk2OSwyNy43MTYsNTQuNDk3LDI3LjUxMnoiLz48cGF0aCBkPSJNMC4zNjEsMTYuMTI1bDEzLjY2Miw1LjQ2NWwxMi41MzcsNS4wMTVjMC40NzcsMC4xOTEsMS4yNTEsMC4xOTEsMS43MjksMGwxMi41NDEtNS4wMTZsMTMuNjU4LTUuNDYzYzAuNDc3LTAuMTkxLDAuNDgtMC41MTEsMC4wMS0wLjcxNkwyOC4yNzcsNC4wNDhjLTAuNDcxLTAuMjA0LTEuMjM2LTAuMjA0LTEuNzA4LDBMMC4zNTEsMTUuNDFDLTAuMTIxLDE1LjYxNC0wLjExNiwxNS45MzUsMC4zNjEsMTYuMTI1eiIvPjwvZz48L2c+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjwvc3ZnPg==); |
|
|
|
background-position: center; |
|
|
|
background-repeat: no-repeat; |
|
|
|
background-size: 70%; |
|
|
|
.amap-locate-only { |
|
|
|
position: absolute; |
|
|
|
top: 12px; |
|
|
|
left: 12px; |
|
|
|
z-index: 120; |
|
|
|
} |
|
|
|
.map-modal { |
|
|
|
.ivu-modal-body { |
|
|
|
padding: 0px; |
|
|
|
.amap-search-list { |
|
|
|
margin: 8px 0 0; |
|
|
|
padding: 0; |
|
|
|
list-style: none; |
|
|
|
max-height: 240px; |
|
|
|
overflow: auto; |
|
|
|
background: #fff; |
|
|
|
border-radius: 4px; |
|
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); |
|
|
|
li { |
|
|
|
padding: 8px 12px; |
|
|
|
cursor: pointer; |
|
|
|
border-bottom: 1px solid #f0f0f0; |
|
|
|
&:hover { |
|
|
|
background: #f5f7fa; |
|
|
|
} |
|
|
|
.name { |
|
|
|
color: #17233d; |
|
|
|
font-size: 13px; |
|
|
|
} |
|
|
|
.addr { |
|
|
|
margin-top: 2px; |
|
|
|
color: #808695; |
|
|
|
font-size: 12px; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
.amap-container { |
|
|
|
min-height: 360px; |
|
|
|
} |
|
|
|
.locate-tip { |
|
|
|
margin-top: 6px; |
|
|
|
color: #808695; |
|
|
|
font-size: 12px; |
|
|
|
line-height: 1.4; |
|
|
|
} |
|
|
|
.modal-fullscreen { |
|
|
|
position: absolute; |
|
|
|
right: 42px; |
|
|
|
top: 10px; |
|
|
|
font-size: 18px; |
|
|
|
color: #999; |
|
|
|
} |
|
|
|
</style> |