Newer
Older
smartwell_front / src / views / home / pipeline / components / map.vue
liyaguang on 13 Dec 9 KB 需求修改
<!--
  Description: 闸井监测-地图
  Author: 李亚光
  Date: 2023-07-08
 -->
<script lang="ts" setup name="WellMap">
import detailInfo from './detailInfoDialog.vue'
import AMap from '@/components/map/index.vue'

const $props = defineProps({
  height: {
    type: Number,
    default: 0,
  },
  // 点位数据
  data: {
    type: Array,
    default: () => ([]),
  },
  // 管线数据
  pipe: {
    type: Array,
    default: () => ([]),
  },
})
// 地图实例
const mapRef = ref()
const publicPath = window.location.href.split('#')[0]
// console.log(publicPath, 'publicPath')
// 展示图例数据
const legendShowData = ref(['管网哨兵', '智能警示桩'])
// 地图图例数据
const legendData = ref([
  {
    name: '管网哨兵',
    url: `${publicPath}/image/pipeline/underground-normal.png`,
    value: '管网哨兵',
  },
  {
    name: '智能警示桩',
    url: `${publicPath}/image/pipeline/warning-normal.png`,
    value: '智能警示桩',
  },
  // {
  //   name: '离线',
  //   url: `${publicPath}/image/station/station-offline.png`,
  //   value: '3',
  // },
])
// 控制图例
const clickLegend = (type: string) => {
  if (legendShowData.value.includes(type)) {
    legendShowData.value = legendShowData.value.filter((item: string) => item !== type)
  }
  else {
    legendShowData.value.push(type)
  }
  resetDraw()
}
// 初次加载标识
const pageIsFirst = ref(true)
// 绘制标记点
const drawMarker = () => {
  const style = [
    {
      url: `${publicPath}/image/pipeline/地埋式哨兵-离线.png`, // 图标地址
      anchor: new mapRef.value.AMap.Pixel(4, 4), // 图标显示位置偏移量,基准点为图标左上角
      size: new mapRef.value.AMap.Size(20, 20), // 图标的尺寸
      zIndex: 99, // 每种样式图标的叠加顺序,数字越大越靠前
    },
    {
      url: `${publicPath}/image/pipeline/underground-normal.png`, // 图标地址
      anchor: new mapRef.value.AMap.Pixel(4, 4), // 图标显示位置偏移量,基准点为图标左上角
      size: new mapRef.value.AMap.Size(20, 20), // 图标的尺寸
      zIndex: 100, // 每种样式图标的叠加顺序,数字越大越靠前
    },
    {
      url: `${publicPath}/image/pipeline/地埋式哨兵-异常.png`, // 图标地址
      anchor: new mapRef.value.AMap.Pixel(4, 4), // 图标显示位置偏移量,基准点为图标左上角
      size: new mapRef.value.AMap.Size(20, 20), // 图标的尺寸
      zIndex: 99, // 每种样式图标的叠加顺序,数字越大越靠前
    },
    {
      url: `${publicPath}/image/pipeline/警示桩-离线.png`, // 图标地址
      anchor: new mapRef.value.AMap.Pixel(4, 4), // 图标显示位置偏移量,基准点为图标左上角
      size: new mapRef.value.AMap.Size(20, 20), // 图标的尺寸
      zIndex: 99, // 每种样式图标的叠加顺序,数字越大越靠前
    },
    {
      url: `${publicPath}/image/pipeline/warning-normal.png`, // 图标地址
      anchor: new mapRef.value.AMap.Pixel(4, 4), // 图标显示位置偏移量,基准点为图标左上角
      size: new mapRef.value.AMap.Size(20, 20), // 图标的尺寸
      zIndex: 100, // 每种样式图标的叠加顺序,数字越大越靠前
    },
    {
      url: `${publicPath}/image/pipeline/警示桩-异常.png`, // 图标地址
      anchor: new mapRef.value.AMap.Pixel(4, 4), // 图标显示位置偏移量,基准点为图标左上角
      size: new mapRef.value.AMap.Size(20, 20), // 图标的尺寸
      zIndex: 99, // 每种样式图标的叠加顺序,数字越大越靠前
    },
    // {
    //   url: `${publicPath}/image/pipeline/station-offline.png`, // 图标地址
    //   anchor: new mapRef.value.AMap.Pixel(4, 4), // 图标显示位置偏移量,基准点为图标左上角
    //   size: new mapRef.value.AMap.Size(20, 20), // 图标的尺寸
    //   zIndex: 99, // 每种样式图标的叠加顺序,数字越大越靠前
    // },
  ]
  const styleDict = {
    '管网哨兵-0': 0,
    '管网哨兵-1': 1,
    '管网哨兵-2': 2,
    '智能警示桩-0': 3,
    '智能警示桩-1': 4,
    '智能警示桩-2': 5,
  } as { [key: string]: number }
  const data = $props.data.filter((item: any) => legendShowData.value.includes(item.deviceTypeName)).filter((item: any) => item.lng && item.lat && item.deviceTypeName && item.status).map((item: any) => ({
    lnglat: [item.lng, item.lat],
    name: item.deviceTypeName,
    style: styleDict[`${item.deviceTypeName}-${item.status}`] || 0,
    id: item.deviceCode,
    row: item,
  }))
  console.log(data, '绘制标记点')
  mapRef.value.addMassMarks({
    path: data,
    zIndex: 111,
    zooms: [3, 20],
    style,
  })
  if (pageIsFirst.value) {
    mapRef.value.map.setCenter([116.397428, 39.90923])
  }
  else {
    mapRef.value.map.setFitView()
  }
  mapRef.value.map.setZoom(10.5)
}
// 绘制线
const drawLine = () => {
  const data = $props.pipe.filter((item: any) => item.endLat && item.endLng && item.startLng && item.startLat && item.pipeCode)
  console.log(data, '准备绘制线')
  data.forEach((item: any) => {
    mapRef.value.addPolyline({
      path: [[item.startLng, item.startLat], [item.endLng, item.endLat]],
      style: {
        strokeColor: '#E80D0D',
        strokeWeight: 2,
        strokeStyle: 'solid',
        zIndex: 95,
      },
    })
  })
}
// 点标记弹窗
const detail = ref()
const detailRef = ref()
const massMarksClick = (data: any) => {
  mapRef.value.map.setZoom(10.5)
  // 定义弹窗
  detail.value = new mapRef.value.AMap.InfoWindow({
    closeWhenClickMap: true, // 是否在鼠标点击地图后关闭信息窗体
    autoMove: true, // 是否自动调整窗体到视野内
    isCustom: true, // 自定义信息窗体
    content: detailRef.value.$el, // 窗体内容(vue组件)
    offset: new mapRef.value.AMap.Pixel(9, -5), // 偏移
  })
  // 打开信息窗口
  detail.value.open(data.map, data.event.data.lnglat)
  // 初始化信息窗口
  detailRef.value.initDialog({
    overlay: data.event.target,
    infoWindow: detail.value,
    info: data.event.data,
    map: mapRef.value.map,
  })
  setTimeout(() => {
    // mapRef.value.map.setZoom(14)
    // mapRef.value.map.setFitView()
    // mapRef.value.map.setCenter(data.event.data.lnglat)
    const center = JSON.parse(JSON.stringify(data.event.data.lnglat))
    center[1] = Number(center[1]) + 0.0045
    mapRef.value.map.setCenter(center)
  })
  // 关联的管线高亮
  const line = $props.pipe.filter((item: any) => item.pipeCode === data.event.data.row.pipeCode)
  console.log(line, 'line')
  if (line.length) {
    if (!mapRef.value.lineAllList.length) {
      return
    }
    const link = mapRef.value.lineAllList.filter((item: any) => line.filter((citem: any) => [[citem.startLng, citem.startLat], [citem.endLng, citem.endLat]].join() === item.$x.join()).length)
    console.log(link, 'link')
    if (link.length) {
      link.forEach((element: any) => {
        element.setOptions({
          strokeColor: '#34A0E8',
          strokeWeight: 4,
        })
      })
    }
  }
}

// 打开信息窗体
const openInfoDetail = (data: any) => {
  mapRef.value.map.setZoom(10.5)
  // 定义弹窗
  detail.value = new mapRef.value.AMap.InfoWindow({
    closeWhenClickMap: true, // 是否在鼠标点击地图后关闭信息窗体
    autoMove: true, // 是否自动调整窗体到视野内
    isCustom: true, // 自定义信息窗体
    content: detailRef.value.$el, // 窗体内容(vue组件)
    offset: new mapRef.value.AMap.Pixel(9, -5), // 偏移
  })
  // 打开信息窗口
  setTimeout(() => {
    detail.value.open(mapRef.value.map, data.lnglat)
    // 初始化信息窗口
    detailRef.value.initDialog({
      infoWindow: detail.value,
      info: data,
      map: mapRef.value.map,
    })
    // mapRef.value.map.setCenter(data.lnglat)
    const center = JSON.parse(JSON.stringify(data.lnglat))
    center[1] = Number(center[1]) + 0.0045
    mapRef.value.map.setCenter(center)
  })
}
// 重置标记点
function resetDraw() {
  mapRef.value.removeMassMarks()
  if (detailRef.value) {
    detailRef.value.close()
  }
  if ($props.data) {
    // 清空标记点重新绘制
    drawMarker()
  }
}
// 重置线
function resetDrawLine() {
  mapRef.value.removePolyline()
  if (detailRef.value) {
    detailRef.value.close()
  }
  if ($props.pipe) {
    // 清空闲重新绘制
    drawLine()
  }
}

// 地图绘制完毕
const completeMap = () => {
  console.log('地图绘制完毕')
  // 绘制海量点
  resetDraw()
  clickLegend('智能警示桩')
  setTimeout(() => {
    clickLegend('智能警示桩')
  })
  // 绘制线
  resetDrawLine()
  setTimeout(() => {
    pageIsFirst.value = false
  }, 2000)
}
defineExpose({ openInfoDetail, drawMarker, resetDraw, drawLine, resetDrawLine, mapRef })
</script>

<template>
  <div :style="`height: ${$props.height}px`" class="map-container">
    <!-- 设备信息窗体 -->
    <detail-info ref="detailRef" />
    <!-- 地图 -->
    <a-map ref="mapRef" :show-pieple-layer="true" @complete="completeMap" @massMarksClick="massMarksClick" />
    <!-- 图例 -->
    <div class="legend">
      <div v-for="item in legendData" :key="item.value" class="legend-item" @click="clickLegend(item.value)">
        <img v-show="legendShowData.includes(item.value)" class="img" :src="item.url">
        <span v-show="!legendShowData.includes(item.value)" class="img" />
        <span style="margin-left: 5px;">{{ item.name }}</span>
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.map-container {
  width: 100%;
  position: relative;
}

.legend {
  background: rgb(255 255 255 / 80%);
  position: absolute;
  z-index: 1;
  left: 15px;
  bottom: 10px;
  padding: 0 10px;
  border-radius: 3px;
  color: #000;

  .legend-item {
    margin: 10px 0;
    // font-weight: 700;
    display: flex;
    align-items: center;

    .img {
      width: 20px;
      height: 20px;
    }

    &:hover {
      cursor: pointer;
    }
  }
}
</style>