<template>
  <div class="AppMerchantMap">
    <div class="search">
      <image :src="$cdn + 'xincheng/search.png'" />
      <input placeholder="请输入店主姓名、店名" v-model="businessName" @input="getList(true)">
    </div>
    <div class="search-list" v-if="isShow">
      <div class="item border" v-for="(item, index) in list" :key="index" @click="toDetail(item)">
        <div class="item-content">
          <h3>{{ item.businessName }} - {{ item.bossName }}</h3>
          <p>{{ item.businessAddress }}</p>
        </div>
      </div>
    </div>
    <div class="map-content" @click.stop="isShow = false">
      <AiTMap :map.sync="map" :lib.sync="lib" :ops="ops" :libraries="['service', 'tools']"/>
    </div>
  </div>
</template>

<script>
  import {mapState} from 'vuex'

  export default {
    name: 'AppMerchantMap',
    appName: '商户地图',
    data() {
      return {
        areaId: '',
        lib: null,
        map: null,
        polygons: [],
        labels: [],
        businessName: '',
        ops: {},
        markers: [],
        isShow: false,
        MarkerCluster: null,
        list: []
      }
    },
    computed: {...mapState(['user', 'config'])},

    created () {
      this.areaId = this.user.areaId
      this.getList()
    },

    mounted () {
      this.initMap()
    },

    methods: {
      toDetail (item) {
        if (!item.lat) {
          return this.$u.toast('该商户尚未标记')
        }

        this.businessName = item.businessName
        this.isShow = false
        this.map.easeTo({
          center: new this.lib.LatLng(item.lat, item.lng),
          zoom: 20
        }, {
          duration: 800
        })
      },

      getList (isSearch) {
        this.$http.post('/app/appcompany/list', null, {
          params: {
            size: isSearch ? 20 : 100000,
            current: 1,
            businessName: this.businessName
          }
        }).then((res) => {
          if (res.code == 0) {
            const markers = res.data.records.filter(item => item.lat).map(item => {
              return {
                ...item,
                title: item.businessName + '-' + item.bossName,
                lnglat: [item.lng, item.lat],
                lat: item.lat,
                lng: item.lng,
                id: item.id,
                name: item.businessName + '-' + item.bossName
              }
            })

            if (isSearch) {
              this.list = res.data.records
              this.isShow = true
            } else {
              this.getMarkerCluster(markers)
            }
          }
        })
      },

      getMarkerCluster(points, count = 0) {
        let {lib: TMap, map} = this
        if (map) {
          if (this.markers.length) {
            this.markers.forEach(v => {
              v.setMap(null)
            })
          }

          class ClusterBubble extends TMap.DOMOverlay {
            constructor(options) {
              super(options);
            }

            onInit(options) {
              this.content = options.content;
              this.position = options.position;
              this.customClass = options.customClass
            };

            onDestroy() {
              this.dom.removeEventListener('click', this.onClick);
              this.removeAllListeners();
            }

            createDOM() {
              let dom = document.createElement('div');
              dom.classList.add(this.customClass || 'marker');
              dom.innerText = this.content;

              // 监听点击事件，实现zoomOnClick
              this.onClick = this.onClick.bind(this);
              // pc端注册click事件，移动端注册touchend事件
              dom.addEventListener('click', this.onClick);
              dom.addEventListener('touchend', this.onClick);
              return dom;
            };

            updateDOM() {
              if (!this.map) {
                return;
              }
              // 经纬度坐标转容器像素坐标
              let pixel = this.map.projectToContainer(this.position);

              // 使文本框中心点对齐经纬度坐标点
              let left = pixel.getX() - this.dom.clientWidth / 2 + 'px';
              let top = pixel.getY() - this.dom.clientHeight / 2 + 'px';
              this.dom.style.transform = `translate(${left}, ${top})`;
              this.emit('dom_updated');
            };

            onClick() {
              this.emit('click');
            }
          }

          this.MarkerCluster = new TMap.MarkerCluster({
            map, gridSize: 60,
            enableDefaultStyle: false, // 关闭默认样式
            geometries: points.map(e => ({
              position: new TMap.LatLng(e.lat, e.lng),
              id: e.id,
              content: `${e.name}`,
              properties: {...e}
            })) || [],
            zoomOnClick: true,
            maxZoom: 18
          })
          this.setCenter(points.map(e => {
            return new TMap.LatLng(e.lat, e.lng)
          }))

          let cls = []
          this.MarkerCluster.on('cluster_changed', () => {
            if (this.markers.length) {
              this.markers.forEach(function (item) {
                item.destroy();
              })
            }
            cls.forEach(e => e.destroy())
            cls = []
            let clusters = this.MarkerCluster.getClusters()
            clusters.forEach((item) => {
              if (item.geometries?.length > 1) {
                //聚合样式
                let clusterBubble = new ClusterBubble({
                  map,
                  position: item.center,
                  content: item.geometries.length,
                  customClass: 'cluster'
                })
                clusterBubble.on('click', () => {
                  map.fitBounds(item.bounds);
                });
                cls.push(clusterBubble)
              } else {
                //点标记样式
                let {content, id} = item.geometries?.[0] || {},
                    overlay = new ClusterBubble({map, position: item.center, content})
                overlay.on('click', () => {
                  uni.navigateTo({
                    url: `../AppMerchantManage/detail?id=${id}`
                  })
                })
                this.markers.push(overlay)
              }
            });
          })
          return Promise.resolve()
        } else {
          if (count < 5) {
            setTimeout(() => {
              return this.getMarkerCluster(points, ++count)
            }, 1000)
          } else Promise.reject("加载失败")
        }
      },

      initMap (retryTimes = 0) {
        this.$nextTick(() => {
          let { map, TMap } = this
          if (map) {
            map.setZoom(15)
          } else {
            if (retryTimes < 10) {
              setTimeout(() => {
                this.initMap(++retryTimes)
              }, 500)
            }
          }
        })
      },

      setCenter (arr) {
        var bounds = new TMap.LatLngBounds()
        arr.forEach(function(item){
          if (bounds.isEmpty() || !bounds.contains(item)){
            bounds.extend(item)
          }
        })

        this.map.fitBounds(bounds, {
          padding: 100
        })
      }
    }
  }
</script>

<style lang="scss" scoped>
  .AppMerchantMap {
    height: 100vh;
    overflow: hidden;

    .search-list {
      position: fixed;
      left: 50%;
      top: 128px;
      width: 718px;
      height: 70%;
      overflow-y: scroll;
      box-sizing: border-box;
      z-index: 2222;
      transform: translateX(-50%);

      .search-icon {
        width: 36px;
        height: 36px;
        margin-right: 16px;
        vertical-align: sub;
      }

      .title {
        height: 82px;
        line-height: 82px;
        font-size: 26px;
        font-family: MicrosoftYaHeiSemibold;
        color: #1365DD;
        padding-left: 44px;
        background-color: #fff;
      }

      .item {
        padding: 20px 30px;
        background-color: #fff;

        &:last-child {
          border: none;
        }
      }

      .item-content {
        display: inline-block;
        width: 610px;
        color: #333;

        h3 {
          font-size: 28px;
          font-family: MicrosoftYaHeiSemibold;
          line-height: 32px;
          margin-bottom: 8px;
        }

        p {
          width: 100%;
          font-size: 24px;
          font-family: MicrosoftYaHei;
          line-height: 32px;
          overflow: hidden;
          white-space: nowrap;
          text-overflow: ellipsis;
        }
      }

      .user-icon {
        vertical-align: top;
      }

      .border {
        border-bottom: 1px solid #DEDFE1;
      }
    }
    @keyframes warn {
      0% {
        transform: scale(.5);
        opacity: 1
      }

      30% {
        opacity: .5
      }

      to {
        transform: scale(1.6);
        opacity: 0
      }
    }

    ::v-deep.cluster {
      display: flex;
      align-items: center;
      justify-content: center;
      flex-direction: column;
      width: 120px;
      height: 120px;
      color: #fff;
      border-radius: 50%;
      background: #0f8f64;

      &:after {
        position: absolute;
        z-index: -1;
        width: 120px;
        height: 120px;
        border-radius: 50%;
        -webkit-animation: warn 1s ease-out 0s infinite;
        animation: warn 1s ease-out 0s infinite;
        background-color: #0f8f64;
        content: " ";
      }
    }

    ::v-deep.marker {
      color: #fff;
      background: #558BFE;
      padding: 0 32px;
      width: fit-content;
      height: 56px;
      border-radius: 52px;
      transform: translate(-50%, -50%);
      display: flex;
      align-items: center;

      &:before {
        content: " ";
        display: block;
        position: absolute;
        bottom: 0;
        left: 50%;
        width: 0;
        height: 0;
        transform: translate(-50%, 100%);
        border: 12px solid transparent;
        border-top-color: #558BFE;
      }
    }

    * {
      box-sizing: border-box;
    }

    .search {
      display: flex;
      position: fixed;
      align-items: center;
      top: 24px;
      left: 50%;
      z-index: 11111;
      width: 718px;
      height: 88px;
      padding: 0 16px;
      background: #FFFFFF;
      box-shadow: 0px 4px 8px 0px rgba(192, 185, 185, 0.5);
      border-radius: 16px;
      transform: translateX(-50%);

      image {
        width: 48px;
        height: 48px;
        margin-right: 16px;
      }

      input {
        flex: 1;
        font-size: 28px;
        color: #666666;
      }
    }

    .map-content {
      width: 100%;
      height: 100vh;

      map {
        width: 100%;
        height: 100vh;
      }
    }
  }
</style>
