Newer
Older
robot_dog_patrol_front / src / components / aMap / index.vue
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import AMapLoader from '@amap/amap-jsapi-loader'
import dogUrl from '../../assets/tempImages/dog.png'
import markerUrl from '../../assets/marker/marker.png'
const props = defineProps({
  patrolInfoList: Array as any,
})
// 定义巡航点的 GPS 坐标
const cruisePoints: any = ref([])

const mapContainer = ref<HTMLDivElement | null>(null)
const map: any = ref(null) // 地图实例
const markerLayer = ref<AMap.OverlayGroup | null>(null)
const dogLayer = ref<AMap.OverlayGroup | null>(null)
const dogMarker = ref<AMap.Marker | null>(null)
const dogMarkerPosition = ref() // 狗的当前位置
// 初始化地图
const initMap = async () => {
  if (!mapContainer.value) { return }
  console.log('aMapIndex: aMapSecret', window.localStorage.getItem('aMapSecret'))
  console.log('aMapIndex: aMapKey', window.localStorage.getItem('aMapKey'))
  try {
    if (!window._AMapSecurityConfig) {
      // 安全码
      window._AMapSecurityConfig = {
        securityJsCode: window.localStorage.getItem('aMapSecret'),
      }
    }
    // 加载高德地图 API
    const AMap = await AMapLoader.load({
      key: window.localStorage.getItem('aMapKey')!, // 替换为你的高德地图 API Key
      version: '2.0',
      plugins: ['AMap.Scale', 'AMap.MoveAnimation'],
    })

    // 创建地图实例
    map.value = new AMap.Map(mapContainer.value, {
      zoom: 18,
      center: [116.397428, 39.90923],
      viewMode: '2D', // 地图模式
    })
    console.log('map实例', map.value)
  }
  catch (error) {
    console.error('Failed to load AMap API:', error)
    return null
  }
}

// ----------------------------------------marker-----------------------------------------------
// 移除标记图层
const removeMarkerLayer = () => {
  if (map.value && markerLayer.value) {
    map.value.remove(markerLayer.value)
    markerLayer.value = null
  }
}

// 创建巡航点标记
const createMarkers = () => {
  if (!map.value) { return }
  removeMarkerLayer()
  const markers: AMap.Marker[] = []
  // 创建marker图层
  if (!markerLayer.value) {
    markerLayer.value = new AMap.OverlayGroup()
  }

  cruisePoints.value.forEach((item: any, index: number) => {
    let labelText = ''
    if (index === 0) {
      labelText = '起'
    }
    else if (index === cruisePoints.value.length - 1) {
      labelText = '终'
    }
    else {
      labelText = `${index + 1}`
    }

    // 自定义标记内容
    // const markerContent = `
    //   <div class="custom-marker" style="
    //     width: 30px;
    //     height: 30px;
    //     background-color: #0d76d4;
    //     border-radius: 50%;
    //     color: white;
    //     text-align: center;
    //     line-height: 30px;
    //     box-shadow: 0 0 8px rgba(0, 0, 0, 0.3);
    //     transition: transform 0.3s ease;
    //   ">
    //     ${labelText}
    //   </div>
    // `

    const markerContent = `
    <div style="width: 40px; height: 40px; position: relative; display: flex; justify-content: center;">
        <img src="${markerUrl}" style="width: 100%; height: 100%; object-fit: cover;">
        <span style="position: absolute; color: #fff; font-size: 13px;padding-top: 4px;font-weight: 600;">${labelText}</span>
    </div>
    `

    const marker = new AMap.Marker({
      position: item.point,
      content: markerContent,
      offset: new AMap.Pixel(-15, -15), // 调整标记的偏移量,使其居中显示
    })

    const content = '<div style="font-size: 16px;padding: 6px"> <div style="font-weight: bold;padding-bottom: 10px">巡检点信息</div>'
          + `<div style="font-size: 14px;padding-bottom: 6px"><label style="font-weight: bold;padding-right: 16px">巡检路线:</label>${item.routeName}</div>`
          + `<div style="font-size: 14px;padding-bottom: 6px"><label style="font-weight: bold;padding-right: 16px">小区名称:</label>${item.communityName}</div>`
          + `<div style="font-size: 14px;padding-bottom: 6px"><label style="font-weight: bold;padding-right: 16px">小区地址:</label>${item.communityAddress}</div>`
          + `<div style="font-size: 14px;padding-bottom: 6px"><label style="font-weight: bold;padding-right: 16px">点位编号:</label>${item.routeNumber}</div>`
          + `<div style="font-size: 14px;padding-bottom: 6px"><label style="font-weight: bold;padding-right: 16px">位ㅤㅤ置:</label>${item.gpsX}, ${item.gpsY}</div>`
          + '</div>'
    // 创建 InfoWindow 并设置内容
    const infoWindow = new AMap.InfoWindow({
      content,
      offset: new AMap.Pixel(0, -30),
    })

    // 绑定点击事件,点击 marker 显示 InfoWindow
    marker.on('click', () => {
      infoWindow.open(map.value, marker.getPosition())
    })
    // map.value.setView(cruisePoints.value[cruisePoints.value.length - 1].point)
    markers.push(marker)
    markerLayer.value.addOverlay(marker)
    map.value.setFitView(markers)
  })
  map.value.add(markerLayer)
  return markers
}

// 创建连线
const createPolylines = () => {
  if (!map.value || !markerLayer.value) { return }
  for (let i = 1; i < cruisePoints.value.length; i++) {
    const polyline = new AMap.Polyline({
      path: [cruisePoints.value[i - 1].point, cruisePoints.value[i].point],
      strokeColor: '#FF33FF',
      strokeWeight: 2,
      strokeOpacity: 1,
      lineJoin: 'round',
      lineCap: 'round',
      zIndex: 50,
    })
    markerLayer.value.addOverlay(polyline)
  }
}

// 创建标记和连线并添加到图层
const createMarkersAndPolylines = () => {
  if (!map.value) { return }
  markerLayer.value = new AMap.OverlayGroup()
  createMarkers()
  createPolylines()
  map.value.add(markerLayer.value)
}

// --------------------------------------------dog------------------------------------------------
// 移除狗图层
const removeDogLayer = () => {
  if (map.value && dogLayer.value) {
    map.value.remove(dogLayer.value)
    dogLayer.value = null
  }
}

// 创建移动标记并添加到 dogLayer 图层
const createDogMarker = () => {
  if (!map.value) { return }
  // 创建 dogLayer 图层
  dogLayer.value = new AMap.OverlayGroup()
  map.value.add(dogLayer.value)
  const movingMarkerContent = `
    <div style="width: 50px; height: 50px;">
      <img src="${dogUrl}" style="width: 100%; height: 100%; object-fit: cover;">
    </div>
  `

  const movingMarker = new AMap.Marker({
    position: cruisePoints.value[0].point,
    content: movingMarkerContent,
    offset: new AMap.Pixel(-15, -15),
  })
  dogMarkerPosition.value = cruisePoints.value[0].point
  dogLayer.value.addOverlay(movingMarker)
  dogMarker.value = movingMarker
}

// 开始移动标记
const startMoving = (e: any, endPoint: string[]) => {
  if (!dogMarker.value) {
    console.error('移动标记不存在')
    return
  }
  console.log('点击开始移动', cruisePoints.value)
  if (map.value && dogLayer.value && dogMarker.value) {
    const path = [dogMarkerPosition.value, endPoint]
    console.log('移动路径', path)
    dogMarker.value.moveAlong(path, {
      // speed: 10000, // 移动速度为 x米/秒
      loop: false, // 不循环移动
      duration: window.localStorage.getItem('dogWalkTime') || 2000, // 动画时长
      autoRotation: false, // 标记根据移动方向自动旋转
    })
    dogMarkerPosition.value = endPoint
  }
}
// -----------------------------------------------------------------------------------------------

watch(() => props.patrolInfoList, async (newVal) => {
  console.log('监听到巡检点变化', newVal)

  if (!map.value) {
    await initMap()
  }
  if (Array.isArray(newVal) && newVal.length) {
    cruisePoints.value = newVal.map((item: any) => {
      return {
        ...item,
        point: [Number(item.gpsX), Number(item.gpsY)],
      }
    })
    createMarkersAndPolylines()
  }
}, { deep: true, immediate: true })

onMounted(async () => {
  await initMap()
})
// ----------------------- 以下是暴露的方法内容 ----------------------------
defineExpose({ createMarkers, createPolylines, removeMarkerLayer, createDogMarker, startMoving })
</script>

<template>
  <div ref="mapContainer" style="width: 100%; height: 500px;" />
</template>