| | |
| | | map: null, |
| | | markers: [], |
| | | currentMakers: [], |
| | | infoWindow: null |
| | | infoWindow: null, |
| | | updateTimer: null, |
| | | markerObjects: {} // Store marker objects by ID |
| | | } |
| | | }, |
| | | watch: { |
| | |
| | | ]), |
| | | }, |
| | | mounted() { |
| | | getHouseMapDistribution().then(res => { |
| | | if (res.code === 200) { |
| | | res.data.map((item, index) => { |
| | | item.position = [item.longitude, item.latitude] |
| | | item.info = { |
| | | address: item.houseAddress, |
| | | name: item.houseName, |
| | | status: item.houseStatus, |
| | | rentStatus: item.rentStatus, |
| | | statusText: item.houseStatus == 1 ? '待出租' : item.houseStatus == 2 ? '已出租' : item.houseStatus == 3 ? '维修中' : '欠费', |
| | | tenant: item.tenant, |
| | | rent: item.rent, |
| | | color: item.houseStatus == 1 ? '#FDAE03' : item.houseStatus == 2 ? '#618CE9' : item.houseStatus == 3 ? '#F64E4F' : '#0FBE6B' |
| | | } |
| | | return item |
| | | }) |
| | | this.currentMakers = JSON.parse(JSON.stringify(res.data)) |
| | | this.markers = res.data |
| | | } |
| | | this.$nextTick(() => { |
| | | this.initMap() |
| | | window.addEventListener('resize', () => { |
| | | this.map && this.map.resize() |
| | | }) |
| | | }) |
| | | }) |
| | | |
| | | this.fetchMapData() |
| | | this.startUpdateTimer() |
| | | }, |
| | | beforeDestroy() { |
| | | window.removeEventListener('resize', () => { |
| | | this.map && this.map.resize() |
| | | }) |
| | | if (this.updateTimer) { |
| | | clearInterval(this.updateTimer) |
| | | } |
| | | }, |
| | | methods: { |
| | | startUpdateTimer() { |
| | | this.updateTimer = setInterval(() => { |
| | | this.fetchMapData() |
| | | }, 3000) |
| | | }, |
| | | fetchMapData() { |
| | | getHouseMapDistribution().then(res => { |
| | | if (res.code === 200) { |
| | | const newData = res.data.map(item => { |
| | | item.position = [item.longitude, item.latitude] |
| | | item.info = { |
| | | address: item.houseAddress, |
| | | name: item.houseName, |
| | | status: item.houseStatus, |
| | | rentStatus: item.rentStatus, |
| | | statusText: item.houseStatus == 1 ? '待出租' : item.houseStatus == 2 ? '已出租' : item.houseStatus == 3 ? '维修中' : '欠费', |
| | | tenant: item.tenant, |
| | | rent: item.rent, |
| | | color: item.houseStatus == 1 ? '#618CE9' : item.houseStatus == 2 ? '#FDAE03' : item.houseStatus == 3 ? '#F64E4F' : '#0FBE6B' |
| | | } |
| | | return item |
| | | }) |
| | | |
| | | if (!this.map) { |
| | | this.currentMakers = JSON.parse(JSON.stringify(newData)) |
| | | this.markers = newData |
| | | this.$nextTick(() => { |
| | | this.initMap() |
| | | window.addEventListener('resize', () => { |
| | | this.map && this.map.resize() |
| | | }) |
| | | }) |
| | | } else { |
| | | this.updateMarkers(newData) |
| | | } |
| | | } |
| | | }) |
| | | }, |
| | | updateMarkers(newData) { |
| | | // Update existing markers and add new ones |
| | | newData.forEach(newMarker => { |
| | | const markerId = `${newMarker.longitude}-${newMarker.latitude}` |
| | | const existingMarker = this.markerObjects[markerId] |
| | | |
| | | if (existingMarker) { |
| | | // Update existing marker content |
| | | const content = this.generateMarkerContent(newMarker) |
| | | existingMarker.setContent(content) |
| | | } else { |
| | | // Create new marker |
| | | const content = this.generateMarkerContent(newMarker) |
| | | const markerObj = new AMap.Marker({ |
| | | position: newMarker.position, |
| | | content: content, |
| | | anchor: 'center', |
| | | offset: new AMap.Pixel(0, 0), |
| | | zIndex: 100 |
| | | }) |
| | | |
| | | markerObj.on('click', () => { |
| | | this.showInfoWindow(markerObj, newMarker.info) |
| | | }) |
| | | |
| | | markerObj.setMap(this.map) |
| | | this.markerObjects[markerId] = markerObj |
| | | } |
| | | }) |
| | | |
| | | // Remove markers that no longer exist |
| | | Object.keys(this.markerObjects).forEach(markerId => { |
| | | const [longitude, latitude] = markerId.split('-') |
| | | const markerExists = newData.some(marker => |
| | | marker.longitude === parseFloat(longitude) && |
| | | marker.latitude === parseFloat(latitude) |
| | | ) |
| | | |
| | | if (!markerExists) { |
| | | this.markerObjects[markerId].setMap(null) |
| | | delete this.markerObjects[markerId] |
| | | } |
| | | }) |
| | | |
| | | this.currentMakers = JSON.parse(JSON.stringify(newData)) |
| | | this.markers = newData |
| | | }, |
| | | generateMarkerContent(marker) { |
| | | return ` |
| | | <div class="marker-container"> |
| | | <svg width="120" height="120" viewBox="0 0 120 120"> |
| | | <defs> |
| | | <filter id="glow" x="-50%" y="-50%" width="200%" height="200%"> |
| | | <feGaussianBlur stdDeviation="3" result="coloredBlur"/> |
| | | <feMerge> |
| | | <feMergeNode in="coloredBlur"/> |
| | | <feMergeNode in="SourceGraphic"/> |
| | | </feMerge> |
| | | </filter> |
| | | </defs> |
| | | <circle class="ripple" cx="60" cy="60" r="12" fill="none" stroke="${marker.info.color}" stroke-width="3" style="opacity: 0.4"> |
| | | <animate attributeName="r" from="12" to="45" dur="3s" begin="0s" repeatCount="indefinite" /> |
| | | <animate attributeName="opacity" from="0.8" to="0" dur="3s" begin="0s" repeatCount="indefinite" /> |
| | | </circle> |
| | | <circle class="ripple" cx="60" cy="60" r="12" fill="none" stroke="${marker.info.color}" stroke-width="3" style="opacity: 0.4"> |
| | | <animate attributeName="r" from="12" to="45" dur="3s" begin="1s" repeatCount="indefinite" /> |
| | | <animate attributeName="opacity" from="0.8" to="0" dur="3s" begin="1s" repeatCount="indefinite" /> |
| | | </circle> |
| | | <circle class="ripple" cx="60" cy="60" r="12" fill="none" stroke="${marker.info.color}" stroke-width="3" style="opacity: 0.4"> |
| | | <animate attributeName="r" from="12" to="45" dur="3s" begin="2s" repeatCount="indefinite" /> |
| | | <animate attributeName="opacity" from="0.8" to="0" dur="3s" begin="2s" repeatCount="indefinite" /> |
| | | </circle> |
| | | <circle class="marker" cx="60" cy="60" r="8" fill="${marker.info.color}" filter="url(#glow)"> |
| | | <animate attributeName="r" values="8;10;8" dur="2s" repeatCount="indefinite" /> |
| | | <animate attributeName="fill-opacity" values="1;0.8;1" dur="2s" repeatCount="indefinite" /> |
| | | </circle> |
| | | </svg> |
| | | </div> |
| | | ` |
| | | }, |
| | | async initMap() { |
| | | const map = await AMapLoader.load({ |
| | | key: '67968c82f27c7e2cb9f40c1a9aa3042b', |