|
|
@@ -0,0 +1,295 @@
|
|
|
+<template>
|
|
|
+ <box class="map-box">
|
|
|
+ <div class="l-flex__fill l-flex--col device-map">
|
|
|
+ <DeviceStatus
|
|
|
+ :items="statusData"
|
|
|
+ style="margin: 70px 0 40px"
|
|
|
+ />
|
|
|
+ <div
|
|
|
+ ref="map"
|
|
|
+ class="l-flex__fill"
|
|
|
+ >
|
|
|
+ <AlarmInfo
|
|
|
+ v-if="isShowAlarm"
|
|
|
+ :alarm="alarm"
|
|
|
+ :style="alarmPositionStyle"
|
|
|
+ class="c-alarm"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </box>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import Box from './Box'
|
|
|
+import DeviceStatus from './DeviceStatus'
|
|
|
+import AlarmInfo from './AlarmInfo'
|
|
|
+import AMapLoader from '@amap/amap-jsapi-loader'
|
|
|
+const onlineIcon = require('@/assets/v1/icon_position1.svg')
|
|
|
+const offlineIcon = require('@/assets/v1/icon_position2.svg')
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'Map',
|
|
|
+ components: {
|
|
|
+ Box,
|
|
|
+ DeviceStatus,
|
|
|
+ AlarmInfo
|
|
|
+ },
|
|
|
+ props: {
|
|
|
+ deviceList: {
|
|
|
+ type: Array,
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ statusData: {
|
|
|
+ type: Array,
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ city: {
|
|
|
+ type: String,
|
|
|
+ default: '深圳市'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data () {
|
|
|
+ this.curMarker = null
|
|
|
+ this.polylines = null
|
|
|
+ return {
|
|
|
+ marks: [],
|
|
|
+ alarmPosition: [],
|
|
|
+ isShowAlarm: false,
|
|
|
+ alarm: {}
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ alarmPositionStyle () {
|
|
|
+ if (!this.alarmPosition.length) {
|
|
|
+ return {}
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ left: this.alarmPosition[0],
|
|
|
+ top: this.alarmPosition[1]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ deviceList () {
|
|
|
+ if (this.map) {
|
|
|
+ this.refreshMarkers()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted () {
|
|
|
+ this.initMap()
|
|
|
+ },
|
|
|
+ beforeDestroy () {
|
|
|
+ this.map?.destroy()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ initMap () {
|
|
|
+ AMapLoader.load({
|
|
|
+ key: process.env.VUE_APP_GAODE_MAP_KEY,
|
|
|
+ version: '2.0',
|
|
|
+ plugins: ['AMap.DistrictSearch']
|
|
|
+ }).then(AMap => {
|
|
|
+ this.$AMap = AMap
|
|
|
+
|
|
|
+ const options = {
|
|
|
+ subdistrict: 2,
|
|
|
+ extensions: 'all',
|
|
|
+ level: 'province'
|
|
|
+ }
|
|
|
+
|
|
|
+ const district = new AMap.DistrictSearch(options)
|
|
|
+ // 查询区域
|
|
|
+ district.search(this.city, (status, result) => {
|
|
|
+ const bounds = result.districtList[0]['boundaries']
|
|
|
+ const mask = []
|
|
|
+ console.log(result)
|
|
|
+ for (let i = 0; i < bounds.length; i++) {
|
|
|
+ mask.push([bounds[i]])
|
|
|
+ }
|
|
|
+
|
|
|
+ // 实例化地图
|
|
|
+ const map = new AMap.Map(this.$refs.map, {
|
|
|
+ mask,
|
|
|
+ // expandZoomRange: true, // 开启显示范围设置
|
|
|
+ // zooms: [7, 20], // 最小显示级别为7,最大显示级别为20
|
|
|
+ // viewMode: '3D', // 这里特别注意,设置为3D则其它地区不显示
|
|
|
+ zoomEnable: true, // 是否可以缩放地图
|
|
|
+ // resizeEnable: true
|
|
|
+ mapStyle: 'amap://styles/darkblue'
|
|
|
+ })
|
|
|
+ this.map = map
|
|
|
+
|
|
|
+ this.marks = []
|
|
|
+ this.$deviceMap = {}
|
|
|
+
|
|
|
+ this.$onlineIcon = new AMap.Icon({
|
|
|
+ image: onlineIcon
|
|
|
+ })
|
|
|
+ this.$offlineIcon = new AMap.Icon({
|
|
|
+ image: offlineIcon
|
|
|
+ })
|
|
|
+
|
|
|
+ this.deviceList.forEach(({ id, longitude, latitude, name, onlineStatus }) => {
|
|
|
+ if (longitude && latitude) {
|
|
|
+ const markObj = new AMap.Marker({
|
|
|
+ position: [Number(longitude), Number(latitude)],
|
|
|
+ title: name,
|
|
|
+ icon: onlineStatus === 1 ? this.$onlineIcon : this.$offlineIcon
|
|
|
+ })
|
|
|
+ this.marks.push(markObj)
|
|
|
+ this.$deviceMap[id] = {
|
|
|
+ onlineStatus,
|
|
|
+ markObj
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ map.add(this.marks)
|
|
|
+
|
|
|
+ const polylines = []
|
|
|
+ // 添加描边
|
|
|
+ for (let i = 0; i < bounds.length; i += 1) {
|
|
|
+ polylines.push(
|
|
|
+ new AMap.Polyline({
|
|
|
+ path: bounds[i],
|
|
|
+ strokeColor: '#182C65',
|
|
|
+ strokeWeight: 0,
|
|
|
+ map
|
|
|
+ })
|
|
|
+ )
|
|
|
+ }
|
|
|
+ this.polylines = polylines
|
|
|
+ this.resetView()
|
|
|
+ map.on('complete', () => {
|
|
|
+ map.on('zoomstart', () => {
|
|
|
+ this.isShowAlarm = false
|
|
|
+ })
|
|
|
+ map.on('movestart', () => {
|
|
|
+ this.isShowAlarm = false
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ // 区级线条
|
|
|
+ for (const item of result.districtList[0].districtList) {
|
|
|
+ district.search(item.adcode, (status, result) => {
|
|
|
+ const bounds = result.districtList[0]['boundaries']
|
|
|
+ for (let i = 0; i < bounds.length; i++) {
|
|
|
+ new AMap.Polyline({
|
|
|
+ path: bounds[i],
|
|
|
+ strokeColor: '#182C65',
|
|
|
+ strokeWeight: 4,
|
|
|
+ map
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ setNewAlarm (alarm) {
|
|
|
+ let marker
|
|
|
+ for (const item of this.marks) {
|
|
|
+ if (item._originOpts.id === alarm.deviceId) {
|
|
|
+ marker = item
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!marker) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.alarm = alarm
|
|
|
+ alarm.status = alarm.status?.label
|
|
|
+ alarm.mac = marker._originOpts.mac
|
|
|
+ alarm.address = marker._originOpts.address
|
|
|
+ //
|
|
|
+ this.map.on('zoomend', this.onSetNewAlarmFitView)
|
|
|
+ this.map.on('moveend', this.onSetNewAlarmFitView)
|
|
|
+
|
|
|
+ this.map.setFitView(marker)
|
|
|
+ this.curMarker = marker
|
|
|
+ },
|
|
|
+ resetView () {
|
|
|
+ this.map.setFitView(this.polylines)
|
|
|
+ this.isShowAlarm = false
|
|
|
+ },
|
|
|
+ onSetNewAlarmFitView () {
|
|
|
+ this.showAlarm(this.curMarker._points)
|
|
|
+ },
|
|
|
+ showAlarm (position) {
|
|
|
+ this.map.off('zoomend', this.onSetNewAlarmFitView)
|
|
|
+ this.map.off('moveend', this.onSetNewAlarmFitView)
|
|
|
+ const x = this.$refs.map.offsetWidth
|
|
|
+ // const y = this.$refs.map.offsetHeight
|
|
|
+ const padding = 40
|
|
|
+ const width = 700 / 2
|
|
|
+ const height = 420
|
|
|
+ let left = position[0]
|
|
|
+ let top = position[1]
|
|
|
+ if (left < width) {
|
|
|
+ left = 0
|
|
|
+ } else if (left + width > x) {
|
|
|
+ left = x - width * 2
|
|
|
+ } else {
|
|
|
+ left -= width
|
|
|
+ }
|
|
|
+ if (left < padding) {
|
|
|
+ left = padding
|
|
|
+ }
|
|
|
+ if (top - height - padding > 0) {
|
|
|
+ top = top - height - padding
|
|
|
+ } else {
|
|
|
+ top += padding
|
|
|
+ }
|
|
|
+
|
|
|
+ this.alarmPosition = [`${left}px`, `${top}px`]
|
|
|
+ this.isShowAlarm = true
|
|
|
+ },
|
|
|
+ refreshMarkers () {
|
|
|
+ const map = {}
|
|
|
+ const arr = []
|
|
|
+ this.deviceList.forEach(({ id, longitude, latitude, name, onlineStatus }) => {
|
|
|
+ if (longitude && latitude) {
|
|
|
+ const device = this.$deviceMap[id]
|
|
|
+ if (device) {
|
|
|
+ device.onlineStatus = onlineStatus
|
|
|
+ device.markObj.setPosition([Number(longitude), Number(latitude)])
|
|
|
+ device.markObj.setIcon(onlineStatus === 1 ? this.$onlineIcon : this.$offlineIcon)
|
|
|
+ map[id] = device
|
|
|
+ delete this.$deviceMap[id]
|
|
|
+ } else {
|
|
|
+ const markObj = new this.$AMap.Marker({
|
|
|
+ position: [Number(longitude), Number(latitude)],
|
|
|
+ title: name,
|
|
|
+ icon: onlineStatus === 1 ? this.$onlineIcon : this.$offlineIcon
|
|
|
+ })
|
|
|
+ map[id] = {
|
|
|
+ onlineStatus,
|
|
|
+ markObj
|
|
|
+ }
|
|
|
+ arr.push(markObj)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ if (arr.length) {
|
|
|
+ this.map.add(arr)
|
|
|
+ }
|
|
|
+ const marks = Object.values(this.$deviceMap).filter(Boolean).map(({ markObj }) => markObj)
|
|
|
+ if (marks.length) {
|
|
|
+ this.map.remove(marks)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.map-box {
|
|
|
+ .amap-container {
|
|
|
+ background: none !important;
|
|
|
+ }
|
|
|
+ .c-alarm {
|
|
|
+ position: absolute;
|
|
|
+ z-index: 9;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|