fix
13404089107
2025-04-03 4a370455a472f64e0a6ffe099078c5254f1bfba9
fix
2个文件已修改
158 ■■■■ 已修改文件
src/components/BottomCharts.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/MapPanel.vue 154 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/BottomCharts.vue
@@ -12,11 +12,11 @@
    </div>
    <div class="map-container">
      <div class="map-marker-item" @click="handleMapMarkerClick('已出租')" :class="{ active: activeStatus === '已出租' }">
        <img :src="require('@/assets/blue.png')" width="30" height="30">
        <img :src="require('@/assets/yellow.png')" width="30" height="30">
        <div class="map-marker-item-text">已出租</div>
      </div>
      <div class="map-marker-item" @click="handleMapMarkerClick('待出租')" :class="{ active: activeStatus === '待出租' }">
        <img :src="require('@/assets/yellow.png')" width="30" height="30">
        <img :src="require('@/assets/blue.png')" width="30" height="30">
        <div class="map-marker-item-text">待出租</div>
      </div>
      <div class="map-marker-item" @click="handleMapMarkerClick('维修中')" :class="{ active: activeStatus === '维修中' }">
src/components/MapPanel.vue
@@ -16,7 +16,9 @@
      map: null,
      markers: [],
      currentMakers: [],
      infoWindow: null
      infoWindow: null,
      updateTimer: null,
      markerObjects: {} // Store marker objects by ID
    }
  },
  watch: {
@@ -44,40 +46,136 @@
    ]),
  },
  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',