<template>
  <view>
    <view class="bottom">
      <div class="info" v-if="showInfo">
        <view class="flex-col section_2">
          <view class="justify-between position-relative">
            <view class="flex-row group_5">
              <image @click="toDetil(detailInfo.userId)" :src="$u.http.config.imgUrl + detailInfo.imageUrl"
                     class="image_5"/>
              <view class="name-work">
                <view class="flex-row items-center h100">
                  <text class="text text_1">{{ detailInfo.name }}</text>
                  <text class="text text_3" v-if="careerList[detailInfo.workFieldName]">
                    <img :src="careerList[detailInfo.workFieldName].icon"
                         alt="">{{ detailInfo.workLableName || detailInfo.workFieldName }}
                  </text>
                  <text class="text text_3" v-else>
                    {{ detailInfo.workLableName }}
                  </text>
                </view>
              </view>
            </view>
            <view class="flex-row section_3">
              <image src="/static/common/img/chats.png" class="image_6"/>
              <text class="text text_2" @click="GoChat(detailInfo.userId)">打招呼</text>
            </view>
          </view>
          <view class="flex-row tags">
            <u-tag :text="detailInfo.college" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
                   type="info"></u-tag>
            <u-tag :text="detailInfo.major" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
                   type="info"></u-tag>
            <u-tag :text="detailInfo.startYear" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
                   type="info"></u-tag>
          </view>
          <view>
            <text v-if="detailInfo.aiBlurb" class="text AIdescribe">{{ detailInfo.aiBlurb }}</text>
          </view>
          <view class="flex-row group_6">
            <image src="/static/common/img/location.svg" style="width: 32rpx;height: 32rpx;"></image>
            <text class="text text_5">{{
                detailInfo.province +
                " " +
                detailInfo.city +
                " 距你 " +
                (detailInfo.distance > 1000
                    ? (detailInfo.distance / 1000).toFixed(1) + "KM"
                    : detailInfo.distance + "M")
              }}
            </text>
          </view>
        </view>
      </div>
    </view>
    <view class="search-box" @click="toSearch">

      <image
          src="/static/common/img/search.svg"
          style="width: 40rpx; height: 40rpx"
      ></image>
    </view>
    <!-- :scale="map.scale"  缩放max：18 min：5-->
    <map
        id="map"
        ref="map"
        :style="'width: 100vw; height: calc(100vh - .5rem );'"
        :scale="mapScale"
        :layer-style="'style1'"
        @regionchange="regionchange"
        @updated="updated"
        :latitude="map.latitude"
        :longitude="map.longitude"
        :markers="covers"
        @callouttap="de"
        @markertap="getUserDetail"
        @click="tap"
    >
    </map>
    <!-- 回到本人定位位置   -->
    <view class="back-to-location" @click="backToLocation"
          v-if="latitude!=vuex_userLocation.latitude||longitude!=vuex_userLocation.longitude">
      <image src="/static/common/img/back-to-location.png" style="width: 120rpx; height: 120rpx"></image>
    </view>
    <u-tabbar
        :list="vuex_tabbar"
        :class="{ phone: vuex_iPhone }"
        :active-color="vuex_tabbar_config.activeColor"
        :inactive-color="vuex_tabbar_config.inactiveColor"
    ></u-tabbar>
    <u-toast ref="uToast"/>
    <!-- 弹出列表 -->
    <view class="popup-box" v-if="showPopup" :style="{
      maxHeight: isExpanded,height: isExpanded,
    }">
      <view class="popup-top"
            @click.stop="togglePopup"
            @touchstart.stop.prevent="touchStart"
            @touchmove.stop.prevent="touchMoveFn"
            @touchend.stop.prevent="touchEnd">
        <view class="pop-top"></view>
        <view class="pop-title">附近校友</view>
      </view>
      <view class="content">
        <template v-for="(item, index) in detailInfoList">
          <view
              v-if="item.userId == 0"
              class="info"
              style="
                position: initial;
                transform: initial;
                margin-bottom: 0.1rem;
              "
              :key="index"
          >
            <view class="flex-col section_2">
              <view class="justify-between position-relative">
                <view class="flex-row group_5">
                  <image
                      :src="$u.http.config.imgUrl + item.imageUrl"
                      class="image_5"
                  />
                  <view class="name-work">
                    <view class="flex-row items-center h100">
                      <text class="text text_1">{{ item.name }}</text>
                      <text class="text text_3" v-if="careerList[item.workFieldName]">
                        <img :src="careerList[item.workFieldName].icon"
                             alt="">{{ item.workLableName || item.workFieldName }}
                      </text>
                      <text class="text text_3" v-else>
                        {{ item.workFieldName }}
                      </text>
                    </view>
                  </view>
                </view>
              </view>
              <view v-if="item.college||item.major||item.startYear" class="flex-row tags">
                <u-tag :text="item.college" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
                       type="info"></u-tag>
                <u-tag :text="item.major" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
                       type="info"></u-tag>
                <u-tag :text="item.startYear" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
                       type="info"></u-tag>
              </view>
              <view>
                <text v-if="item.aiBlurb" class="text AIdescribe">{{ item.aiBlurb }}</text>
              </view>
              <view class="flex-row group_6">
                <image
                    src="/static/common/img/location.svg"
                    style="width: 32rpx; height: 32rpx"
                ></image>
                <text class="text text_5"
                >{{
                    item.province +
                    " " +
                    item.city +
                    " 距你 " +
                    (item.distance > 1000
                        ? (item.distance / 1000).toFixed(1) + "KM"
                        : item.distance + "M")
                  }}
                </text>
              </view>
            </view>
          </view>
          <view
              v-else
              class="info"
              style="
                position: initial;
                transform: initial;
                margin-bottom: 0.1rem;
              "
              :key="index"
          >
            <view class="flex-col section_2">
              <view class="justify-between position-relative">
                <view class="flex-row group_5">
                  <u-avatar
                      @click="toDetil(item.userId)"
                      size="0.5rem"
                      :src="$u.http.config.imgUrl + item.imageUrl"
                      class="image_5"
                  ></u-avatar>
                  <view class="name-work">
                    <view class="flex-row items-center h100">
                      <text class="text text_1">{{ item.name }}</text>
                      <text class="text text_3" v-if="careerList[item.workFieldName]">
                        <img :src="careerList[item.workFieldName].icon"
                             alt="">{{ item.workLableName || item.workFieldName }}
                      </text>
                      <text class="text text_3" v-else>
                        {{ item.workFieldName }}
                      </text>
                    </view>
                    <view>
                    </view>
                  </view>
                </view>
                <view @click="GoChat(item.userId)" class="flex-row section_3">
                  <image src="/static/common/img/chats.png" class="image_6"/>
                  <text class="text text_2">打招呼</text>
                </view>
              </view>
              <view class="flex-row tags">
                <u-tag :text="item.college" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
                       type="info"></u-tag>
                <u-tag :text="item.major" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
                       type="info"></u-tag>
                <u-tag :text="item.startYear" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
                       type="info"></u-tag>
              </view>
              <view>
                <text v-if="item.aiBlurb" class="text AIdescribe">{{ item.aiBlurb }}</text>
              </view>
              <view class="flex-row group_6">
                <image
                    src="/static/common/img/location.svg"
                    style="width: 32rpx; height: 32rpx"
                ></image>
                <text class="text text_5"
                >{{
                    item.province +
                    " " +
                    item.city +
                    " 距你 " +
                    (item.distance > 1000
                        ? (item.distance / 1000).toFixed(1) + "KM"
                        : item.distance + "M")
                  }}
                </text>
              </view>
            </view>
          </view>
        </template>
      </view>
    </view>
  </view>
</template>

<script>
// var jweixin = require('./../../../static/common/js/jweixin.js')
var jweixin = require("jweixin-module");
var map;
var qqmapsdk;
export default {
  data() {
    return {
      latitude: 0, //纬度
      longitude: 0,
      mapScale: 16,
      showInfo: false,
      height: "calc(100vh - .5rem )",
      width: "100vw",
      // showList: true,
      // viewHeight: 0,
      map: {
        scale: 14,
        latitude: 39.909,
        longitude: 116.39742,
      },
      // 标记点
      covers: [],
      pointDataList: "",
      detailInfoList: [],
      // 中心点
      center: {
        userId: 0,
        latitude: 39.909, //纬度
        longitude: 116.39742, //经度
        iconPath: "", //显示的图标
        rotate: 0, // 旋转度数
        width: 50, //宽
        imageUrl: "",
        height: 50, //高
        name: "我",
        province: "",
        city: "",
        distance: "0",
        workFieldName: "",
        title: "我的位置", //标注点名
        alpha: 0.8, //透明度
      },

      callout: {
        content: '',//String 文本
        color: '',//String 文本颜色
        fontSize: '',// Number 文字大小
        x: 3,// label的坐标，原点是 marker 对应的经纬度
        y: -20,// label的坐标，原点是 marker 对应的经纬度
        borderWidth: 0,//Number边框宽度
        borderColor: '',//String 边框颜色
        borderRadius: 0,//Number callout边框圆角
        bgColor: '',//String 背景色
        padding: '',//Number 文本边缘留白
        display: 'ALWAYS',//String 'BYCLICK':点击显示; 'ALWAYS':常显
      },
      careerList: {
        '生物/制药/化工/医疗': {
          icon: '/static/common/icon/icon-1.png',
          minIcon: '/static/common/icon/min-icon-1.png',
        },
        '政府机构/翻译/其他': {
          icon: '/static/common/icon/icon-2.png',
          minIcon: '/static/common/icon/min-icon-2.png',
        },
        '人事/行政/高级管理': {
          icon: '/static/common/icon/icon-3.png',
          minIcon: '/static/common/icon/min-icon-3.png',
        },
        '设计/市场/媒体/广告': {
          icon: '/static/common/icon/icon-4.png',
          minIcon: '/static/common/icon/min-icon-4.png',
        },
        '闽建筑/房地产': {
          icon: '/static/common/icon/icon-5.png',
          minIcon: '/static/common/icon/min-icon-5.png',
        },
        '计算机/互联网/通信/电子': {
          icon: '/static/common/icon/icon-6.png',
          minIcon: '/static/common/icon/min-icon-6.png',
        },
        '服务业': {
          icon: '/static/common/icon/icon-7.png',
          minIcon: '/static/common/icon/min-icon-7.png',
        },
        '教育/培训': {
          icon: '/static/common/icon/icon-8.png',
          minIcon: '/static/common/icon/min-icon-8.png',
        },
        '销售/客服': {
          icon: '/static/common/icon/icon-9.png',
          minIcon: '/static/common/icon/min-icon-9.png',
        },
        '资讯/法律/科研': {
          icon: '/static/common/icon/icon-10.png',
          minIcon: '/static/common/icon/min-icon-10.png',
        },
        '会计/金融/银行/保险': {
          icon: '/static/common/icon/icon-11.png',
          minIcon: '/static/common/icon/min-icon-11.png',
        },
        '生产/营运/采购/物流': {
          icon: '/static/common/icon/icon-12.png',
          minIcon: '/static/common/icon/min-icon-12.png',
        },
        '学生': {
          icon: '/static/common/icon/icon-13.png',
          minIcon: '/static/common/icon/min-icon-13.png',
        },
        '教师': {
          icon: '/static/common/icon/icon-14.png',
          minIcon: '/static/common/icon/min-icon-14.png',
        },
      },
      list: [],
      load: true,
      detailInfo: "",
      Showip: "",
      isExpanded: '0vh',
      touchStartY: 0,
      startScrollTop: 0,
      showPopup: false,
      timeer: null
    };
  },
  onLoad(e) {
    // if(!this.vuex_user.isCard){
    // 	uni.navigateTo({
    // 		url: '/pages/Face/index/index'
    // 	});
    // 	return
    // }
    // if (!this.vuex_user.isFill) {
    // 	uni.navigateTo({
    // 		url: "/pages/login/perfect/perfect",
    // 	});
    // 	return
    // } else {
    // 	this.$u.api.getUser()
    // }

    console.info("🚀 ~ file:index method:onLoad line:374 -----", this.vuex_user)

    this.center.imageUrl = this.vuex_user.head;
    this.center.workField = this.vuex_user?.workField?.workFieldName || "暂无";
    this.center.workFieldName = this.vuex_user?.workFieldName || "暂无";
    this.center.aiBlurb = this.vuex_user?.aiBlurb || "暂无";
    this.center.aiLabel = this.vuex_user?.aiLabel || "";
    this.center.college = this.vuex_user?.college || "";
    this.center.major = this.vuex_user?.major || "";
    this.center.startYear = this.vuex_user?.startYear || "";

    // 创建地图上下文
    map = uni.createMapContext("map", this);
    uni.getSystemInfo({
      success: (res) => {
        this.height = res.windowHeight + "px";
        this.width = res.windowWidth + "px";
      },
    });
    // this.location();
    // qqmapsdk = new QQMapWX({
    // 	key: '2OLBZ-OOSRQ-RYZ5A-GMCM2-DJ43O-3QFLS', //开发者密钥
    // })
    // console.log(this.vuex_user.isFill)
  },
  onShow() {
    /* uni.getSystemInfo({
      success: (res) => {
        this.viewHeight = res.windowHeight;
      },
    }); */

    this.map.latitude = this.vuex_userLocation.latitude;
    this.map.longitude = this.vuex_userLocation.longitude;
    this.center.latitude = this.vuex_userLocation.latitude;
    this.center.longitude = this.vuex_userLocation.longitude;
    setTimeout(() => {
      if (!this.map.latitude || !this.map.longitude) {
        this.location(true);
      }
      this.test();
    }, 500);
    if (!this.vuex_user.isFill) {
      uni.navigateTo({
        url: "/pages/login/perfect/perfect",
      });
      return;
    } else {
      this.$u.api.getUser();
    }
  },
  methods: {
    // 回到当前位置
    backToLocation() {
      this.location(true);
      map.moveToLocation({
        latitude: this.vuex_userLocation.latitude || this.center.latitude,
        longitude: this.vuex_userLocation.longitude || this.center.longitude,
      });

      this.latitude = this.vuex_userLocation.latitude || this.center.latitude;
      this.longitude = this.vuex_userLocation.longitude || this.center.longitude;
    },
    // 查看详情
    toDetil(id) {
      this.$u.route({
        url: "/pages/AlumniCircle/userDetail/userDetail?id=" + id,
      });
    },
    //   去聊天
    GoChat(id) {
      this.showInfo = false;
      uni.navigateTo({
        url:
            "../../message/dialogBox/dialogBox?id=" + id + "&chatType=0&type=0",
      });
    },
    toSearch() {
      if (this.vuex_user.isAttestationXY || true) {
        this.$u.route({
          url: "/pages/main/search/search",
          params: {
            type: 'index',
          },
        });
      } else {
        this.$refs.uToast.show({
          title: "认证后才能进行搜索哦",
          url: "/pages/my/ShoolList/ShoolList",
        });
      }
    },
    test() {
      map.getRegion({
        success: (res) => {
          this.Showip = {
            northeast: res.northeast,
            southwest: res.southwest,
          };
          this.getList();
        },
      });
    },
    getEpsByScale(zoomLevel) {
      // 缩放等级范围限制在 1 到 18
      if (zoomLevel < 1) zoomLevel = 1;
      if (zoomLevel > 18) zoomLevel = 18;

      // 基础距离（单位：米），通常在缩放等级 0 时显示整个地球（约 40075 公里）
      const earthCircumference = 40075000; // 地球赤道周长（米）

      // 根据缩放等级计算当前等级下的单个瓦片的地面宽度
      const tileSize = 256; // 地图瓦片大小（通常是 256x256 像素）
      const scale = 2 ** zoomLevel; // 缩放等级对应的缩放比例

      // 计算每个像素代表的地面距离（米/像素）
      const metersPerPixel = earthCircumference / (tileSize * scale);

      // 返回一个以 50 像素为参考的距离（可以根据需求调整这个值）
      const pixelRange = 50; // 聚合点之间的最小像素距离
      return metersPerPixel * pixelRange;
    },
    //根据东北 西南经纬度 以及后台返回标记点 格式化成marker点
    async getFortMatMarkerList(northeast, southwest, scale, backendMarkerList) {
      // 当前显示的坐标范围

      // console.log(southwest.longitude, northeast.longitude, northeast.latitude, southwest.latitude)
      //屏幕中显示的经度的长度和纬度的长度
      let mapWidth = southwest.longitude - northeast.longitude;
      let mapHeight = northeast.latitude - southwest.latitude;
      //将屏幕中地图分割的横向 格子数和 纵向格子数
      // let widthSize = scale;
      // let heightSize = widthSize + parseInt(scale / 2);
      let widthSize = 30 - parseInt(scale / 2);
      let heightSize = 30 - parseInt(scale / 2);

      //计算每个格子的经纬度的长度
      let unitWidth = mapWidth / widthSize;
      let unitHeight = mapHeight / heightSize;
      // console.log(southwest.longitude - northeast.longitude, unitHeight)
      let pointData = {};
      backendMarkerList.forEach((latLng) => {
        //如果点在显示范围内
        if (
            latLng.latitude < northeast.latitude &&
            latLng.latitude > southwest.latitude &&
            latLng.longitude < northeast.longitude &&
            latLng.longitude > southwest.longitude
        ) {
          let relativeX = latLng.longitude - northeast.longitude;
          let relativeY = latLng.latitude - southwest.latitude;
          //计算出这个点，处于哪个格子
          let x = parseInt(Math.floor(relativeX / unitWidth));
          let y = parseInt(Math.floor(relativeY / unitHeight));
          if (x < 0 || y < 0) {
            console.log("点位不在格子内", "失败");
          }
          //生成单元格点位数据
          let pointKey = x + "," + y;
          if (pointData[pointKey] == undefined) {
            pointData[pointKey] = [];
          }
          if (pointData[pointKey].length <= 99) {
            pointData[pointKey].push(latLng);
          } else {
            return
          }
        } else {
          console.log("点位不在显示范围内", "失败");
        }
      });
      console.info("🚀 ~ file:index method:getFortMatMarkerList line:547 -----", pointData)


      // ===== 新增：使用 DBSCAN 进行全局点聚合 start =====
      const eps = this.getEpsByScale(scale); // 根据缩放级别调整 eps 值
      pointData = this.dbscan(pointData, parseInt(eps)); // 聚合参数可调整


      this.pointDataList = pointData;


      let resultMapArray = [];
      for (let y = 0; y < heightSize; y++) {
        for (let x = 0; x < widthSize; x++) {
          let pointKey = x + "," + y;
          if (
              pointData[pointKey] != undefined &&
              (pointData[pointKey][0].userId ||
                  pointData[pointKey][0].userId === 0)
          ) {
            let markerItem = {};

            //聚合点与单点共存 , 长度等于一 不聚合点
            if (pointData[pointKey].length == 1) {
              var HeadImg = "/static/common/img/adminHeaderImg.png?number=1";
              if (pointData[pointKey][0].userId == 0) {
                if (this.vuex_user.sex == "男") {
                  HeadImg = "/static/common/img/male.png?number=1";
                }
                if (this.vuex_user.sex == "女") {
                  HeadImg = "/static/common/img/female.png?number=1";
                }
              }
              // 请求在线图片文件 判断是否存在
              // const imgExist = await this.doesImageExist(this.$u.http.config.imgUrl +
              //     pointData[pointKey][0].imageUrl +
              //     "?number=1");
              //
              // if (imgExist) {
              //   HeadImg =
              //       this.$u.http.config.imgUrl +
              //       pointData[pointKey][0].imageUrl +
              //       "?number=1";
              // }
              // 线上会出现奇怪的问题，所以先注释掉

              if (pointData[pointKey][0].imageUrl != "") {
                HeadImg =
                    this.$u.http.config.imgUrl +
                    pointData[pointKey][0].imageUrl +
                    "?number=1";
              }


              markerItem = {
                id: parseInt(
                    (pointData[pointKey][0].latitude -
                        -pointData[pointKey][0].longitude) *
                    100000
                ),
                latitude: pointData[pointKey][0].latitude,
                longitude: pointData[pointKey][0].longitude,
                iconPath: HeadImg,
                width: 50,
                height: 50,
                callout: {
                  content: scale == 18 ? pointData[pointKey][0].aiLabel : '',
                  display: 'ALWAYS',
                  borderRadius: 100,
                  bgColor: '#3CB5FB',
                  color: '#fff',
                  borderColor: '#3CB5FB',
                },
                label: {
                  ...this.callout,
                  width: 50,
                  height: 50,
                  content: !this.careerList[pointData[pointKey][0].workFieldName] ? `` : `<img src="${this.careerList[pointData[pointKey][0].workFieldName].minIcon}">`
                }
              };


              if (pointData[pointKey][0].userId === 0) {
                markerItem.id = '0'
                if (!pointData[pointKey][0].aiLabel) {
                  markerItem.title = '我的位置'
                }

              }
              // let iconPath = pointData[pointKey][0].ScanAndCharge == 1 ? '/img/scanMarkerIcon.png' : '/img/markerIcon.png';
              //长度大于一聚合点
            } else if (pointData[pointKey].length > 1) {
              // console.log('聚合点', pointData[pointKey]);
              // id会被转为number类型，字符类型不能触发点击时间，
              // 最后面加1是为了在结尾为0的情况时，0在转被为number不被裁剪掉，
              // 对比判断id时去掉加上的 1
              if (pointData[pointKey].length > 99) {
                pointData[pointKey] = pointData[pointKey].slice(0, 99)
              }

              markerItem = {
                id: pointKey.split(",")[0] + "." + pointKey.split(",")[1] + "1",
                latitude: pointData[pointKey][0].latitude,
                longitude: pointData[pointKey][0].longitude,
                iconPath: await this.generateGroupAvatar(pointData[pointKey]), // 使用生成的群组头像
                width: 50,
                height: 50,
                list: pointData[pointKey],
              };
            }

            resultMapArray.push(markerItem);
          }
        }
      }

      return resultMapArray;
    }
    ,
    async doesImageExist(url) {
      try {
        const response = await fetch(url, {method: 'HEAD'});
        return response.ok;
      } catch (error) {
        console.error('图片不存在或发生错误:', error);
        return false;
      }
    },
    generateGroupAvatar(users) {

      return new Promise((resolve, reject) => {
        try {
          const canvasSize = 100;
          const maxAvatars = 9;
          const filteredUsers = users.slice(0, maxAvatars);
          const total = filteredUsers.length;

          if (total === 0) {
            resolve('/static/common/img/map_icon.png');
            return;
          }

          // 缓存 key
          const userIds = filteredUsers.map(u => u.userId).join(',');
          const cacheKey = `groupAvatar_${userIds}`;
          if (this[cacheKey]) {
            resolve(this[cacheKey]);
            return;
          }

          // 创建 Canvas
          const canvas = document.createElement('canvas');
          canvas.width = canvasSize;
          canvas.height = canvasSize;
          const ctx = canvas.getContext('2d');
          ctx.fillStyle = '#ffffff';
          ctx.fillRect(0, 0, canvasSize, canvasSize);

          let drawnCount = 0;
          const padding = 2;
          const verticalPadding = 3;

          // 布局配置
          const layoutConfig = {
            1: {rows: 1, cols: 1, centeredRows: [0]},
            2: {rows: 1, cols: 2}, // 横向排列，但垂直居中
            3: {rows: 2, cols: [1, 2], centeredRows: [0]}, // 上1 下2，上居中
            4: {rows: 2, cols: 2}, // 2x2 四宫格
            5: {rows: 2, cols: [2, 3], centeredRows: [0]}, // 上2 下3，上居中
            6: {rows: 2, cols: 3}, // 上3 下3
            7: {rows: 3, cols: [1, 3, 3], centeredRows: [0]}, // 上1 中3 下3
            8: {rows: 3, cols: [2, 3, 3], centeredRows: [0]}, // 上2 中3 下3
            9: {rows: 3, cols: 3},
          };

          const config = layoutConfig[total] || layoutConfig[9];
          const {rows, cols} = config;
          const colCounts = Array.isArray(cols) ? cols : Array(rows).fill(cols);
          const centeredRows = config.centeredRows || [];

          // 计算最大列数，用于计算每个头像宽度
          const maxCols = Math.max(...colCounts);
          const avatarWidth = (canvasSize - padding * (maxCols - 1)) / maxCols;
          const rowHeight = (canvasSize - verticalPadding * (rows - 1)) / rows;


          // 绘制每个头像
          filteredUsers.forEach((user, index) => {
            const image = new Image();
            image.crossOrigin = 'anonymous';
            image.src = this.$u.http.config.imgUrl + user.imageUrl;


            // 确定当前头像属于哪一行
            let currentRow = 0;
            let count = 0;
            for (let i = 0; i < rows; i++) {
              const colCount = colCounts[i];
              if (index < count + colCount) {
                currentRow = i;
                break;
              }
              count += colCount;
            }

            const colIndex = index - count;
            const currentColCount = colCounts[currentRow];

            // 如果该行需要居中，则计算起始X坐标
            const startX = centeredRows.includes(currentRow)
                ? (canvasSize - currentColCount * (avatarWidth + padding) + padding) / 2
                : 0;

            const x = startX + colIndex * (avatarWidth + padding);
            const y = currentRow * (rowHeight + verticalPadding);

            // 固定绘制为正方形，避免拉伸
            const drawSize = Math.min(avatarWidth, rowHeight);

            // 居中绘制
            const offsetY = (rowHeight - drawSize) / 2;

            image.onload = () => {
              ctx.save();
              ctx.beginPath();
              ctx.rect(x, y + offsetY, drawSize, drawSize);
              ctx.clip();

              // 从图片中心裁剪出一个正方形
              const imgRatio = image.width / image.height;
              const cropSize = imgRatio > 1 ? image.height : image.width;
              const offsetX = (image.width - cropSize) / 2;
              const offsetYImg = (image.height - cropSize) / 2;

              ctx.drawImage(
                  image,
                  offsetX, offsetYImg, cropSize, cropSize, // 源图裁剪区域
                  x, y + offsetY, drawSize, drawSize       // 目标绘制区域
              );

              ctx.restore();

              drawnCount++;
              if (drawnCount === filteredUsers.length) {
                // 如果超过最大数量，覆盖整个画布并居中显示 "+n"
                if (users.length > maxAvatars) {
                  ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
                  ctx.beginPath();
                  ctx.rect(0, 0, canvasSize, canvasSize);
                  ctx.fill();

                  ctx.fillStyle = '#ffffff';
                  ctx.font = 'bold 40px Arial';
                  ctx.textAlign = 'center';
                  ctx.textBaseline = 'middle';
                  ctx.fillText(`+${users.length}`, canvasSize / 2, canvasSize / 2);
                }

                // 缓存结果并返回
                const result = canvas.toDataURL('image/png');
                this[cacheKey] = result;
                resolve(result); // 异步完成
              }
            };

            image.onerror = (err) => {
              image.src = "data:image/jpg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QMraHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjREMEQwRkY0RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjREMEQwRkY1RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NEQwRDBGRjJGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NEQwRDBGRjNGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAGBAQEBQQGBQUGCQYFBgkLCAYG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";
              image.onload = () => {
                ctx.save();
                ctx.beginPath();
                ctx.rect(x, y + offsetY, drawSize, drawSize);
                ctx.clip();

                // 从图片中心裁剪出一个正方形
                const imgRatio = image.width / image.height;
                const cropSize = imgRatio > 1 ? image.height : image.width;
                const offsetX = (image.width - cropSize) / 2;
                const offsetYImg = (image.height - cropSize) / 2;

                ctx.drawImage(
                    image,
                    offsetX, offsetYImg, cropSize, cropSize, // 源图裁剪区域
                    x, y + offsetY, drawSize, drawSize       // 目标绘制区域
                );

                ctx.restore();

                drawnCount++;
                if (drawnCount === filteredUsers.length) {
                  // 如果超过最大数量，覆盖整个画布并居中显示 "+n"
                  if (users.length > maxAvatars) {
                    ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
                    ctx.beginPath();
                    ctx.rect(0, 0, canvasSize, canvasSize);
                    ctx.fill();

                    ctx.fillStyle = '#ffffff';
                    ctx.font = 'bold 40px Arial';
                    ctx.textAlign = 'center';
                    ctx.textBaseline = 'middle';
                    ctx.fillText(`+${users.length}`, canvasSize / 2, canvasSize / 2);
                  }

                  // 缓存结果并返回
                  const result = canvas.toDataURL('image/png');
                  this[cacheKey] = result;
                  resolve(result); // 异步完成
                }
              }
            };
          });
        } catch (error) {
          console.error('生成聚合头像时发生异常:', error);
          resolve('/static/common/img/map_icon.png');
        }
      });
    }
    ,
    /**
     * DBSCAN 聚类算法（输出格式与 pointData 一致）
     * @param points 原始点数组 { latitude, longitude }
     * @param eps 聚类距离阈值（单位：米）
     * @returns {{}} 统一格式的 pointData 结构，key 格式为 "x,y"
     */
    dbscan(points, eps = 50) {

      function getDistanceInMeters(lat1, lon1, lat2, lon2) {
        const R = 6371; // 地球半径（公里）
        const dLat = (lat2 - lat1) * Math.PI / 180;
        const dLon = (lon2 - lon1) * Math.PI / 180;
        const a =
            Math.sin(dLat / 2) * Math.sin(dLat / 2) +
            Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
            Math.sin(dLon / 2) * Math.sin(dLon / 2);
        const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        const distanceInKm = R * c;
        const distanceInMeters = distanceInKm * 1000; // 将公里转换为米
        console.info("🚀 ~ file:index method:getDistanceInMeters line:886 -----", distanceInMeters)

        return parseInt(distanceInMeters) > 100000 ? 100000 : parseInt(distanceInMeters);
      }

      let deletedPoints = [];
      for (let key in points) {
        if (deletedPoints.includes(key)) {
          continue;
        }
        let X = key.split(',')[0]
        let Y = key.split(',')[1]
        for (let keyTwo in points) {
          let innerX = keyTwo.split(',')[0]
          let innerY = keyTwo.split(',')[1]
          if (key === keyTwo) {
            continue
          }
          if (Math.abs(X - innerX) <= 1 && Math.abs(Y - innerY) <= 1) {
            if (getDistanceInMeters(points[key][0].latitude, points[key][0].longitude, points[keyTwo][0].latitude, points[keyTwo][0].longitude) < eps) {
              points[key] = points[key].concat(points[keyTwo])
              deletedPoints.push(keyTwo)
            }
          }
        }
      }
      for (let key in points) {
        if (deletedPoints.includes(key)) {
          delete points[key]
        }
      }
      return points;
      // ===== 构造统一格式 end =====
    }

    ,
    /**
     * 将聚类结果转为类似 pointData 的结构（"x,y": []）
     * @param clusters 聚类结果二维数组
     * @param noise 噪声点
     * @returns [[]] 合并后的伪格子结构
     */
    _generateFakeGrids(clusters, noise) {
      const result = [...clusters]; // 每个 cluster 单独作为一个格子

      // 如果需要可选地将噪声点也作为一个格子加入
      if (noise.length > 0) {
        result.push(noise); // 可选
      }

      return result;
    }
    ,
    updated() {
      // console.log("渲染完成");
    }
    ,
    // 当视野发生改变
    regionchange(e) {
      // console.log("当视野发生改变");
      // 视野移动结束再获取数据
      if (e.type == "begin") return;
      // 关闭显示的窗口
      this.showInfo = false

      this.test()

      // let loadDelay = 200;
      // if (this.load) {
      // 	// console.log("等待加载");
      // } else {
      // 	this.load = true;
      // 	setTimeout(() => {
      // 		// this.getList();
      // 		this.test();
      // 	}, loadDelay);
      // }
    }
    ,
    isWechat() {
      var ua = window.navigator.userAgent.toLowerCase();
      if (ua.match(/micromessenger/i) == "micromessenger") {
        // console.log(‘是微信客户端’)
        return true;
      } else {
        // console.log(‘不是微信客户端’)
        return false;
      }
    }
    ,
    //在需要定位页面调用
    getlocation: function (callback) {
      if (!this.isWechat()) {
        //console.log('不是微信客户端')
        return;
      }
    }
    ,
    //打开位置
    openlocation: function (data) {
      if (!this.isWechat()) {
        //console.log('不是微信客户端')
        return;
      }
      jweixin.ready(function () {
        jweixin.openLocation({
          latitude: data.latitude,
          longitude: data.longitude,
          name: data.name,
          address: data.address,
          scale: 14,
        });
      });
    }
    ,
    //定位当前
    location(state) {
      var that = this;
      uni.showLoading({
        title: '正在加载...',
        mask: true
      })
      if (state && this.isWechat()) {
        const isiOS = !!navigator.userAgent.match(
            /\(i[^;]+;( U;)? CPU.+Mac OS X/
        ); //ios终端
        // 进行签名的时候  Android 不用使用之前的链接， ios 需要
        const signLink = isiOS
            ? window.entryUrl
            : window.location.href.split("#")[0];
        //获取当前url然后传递给后台获取授权和签名信息，后台需要解码才能使用
        // const url =encodeURIComponent(signLink);
        const url = signLink;
        const data = {
          url: url,
        };

        this.$u.api.GetInfoMation(data).then((res) => {
          jweixin.config({
            debug: false,
            appId: res.appId,
            timestamp: res.timestamp,
            nonceStr: res.noncestr,
            signature: res.signature,
            jsApiList: [
              //这里是需要用到的接口名称
              "getLocation", //获取位置
              "openLocation", //打开位置
            ],
          });

          // jweixin.config 执行失败时调用
          jweixin.error((err) => {
            uni.hideLoading();
            that.location(false);
            console.log("授权失败，您可能无法使用部分功能", err);
          });
          jweixin.ready(function () {
            jweixin.getLocation({
              type: "gcj02", // 默认为wgs84的gps坐标，如果要返 回直接给openLocation用的火星坐标，可传入'gcj02'
              success: (res) => {
                uni.hideLoading();
                var resdata = res;
                // console.log(res,'success');
                map.moveToLocation({
                  latitude: resdata.latitude,
                  longitude: resdata.longitude,
                });
                // alert(JSON.stringify(res))
                that.center.latitude = resdata.latitude; //纬度
                that.center.longitude = resdata.longitude; //经度

                // 更新坐标
                var data = {
                  userId: that.vuex_user.id,
                  longitude: resdata.longitude + "",
                  latitude: resdata.latitude + "",
                };
                that.$u.api.upPosition(data).then(() => {
                  that.getList(resdata.latitude, resdata.longitude);
                  that.test();
                });
              },
              fail: function (res) {
                uni.hideLoading();
                // console.log(res, "err");
              },
              complete: function (res) {
                uni.hideLoading();
                // console.log(res, "is");
              },
            });
          });
        });
      } else {
        uni.getLocation({
          // type: "wgs84 ",
          type: "gcj02 ",
          isHighAccuracy: true,
          highAccuracyExpireTime: 3000,
          success: (res) => {

            uni.hideLoading();
            // console.info("🚀 ~ file:index method:success line:497 -----", res);

            // console.log(res.latitude + "," + res.longitude, "gcj02");
            map.moveToLocation({
              latitude: res.latitude,
              longitude: res.longitude,
            });
            this.center.latitude = res.latitude; //纬度
            this.center.longitude = res.longitude; //经度

            // 更新坐标
            var data = {
              userId: this.vuex_user.id,
              longitude: res.longitude + "",
              latitude: res.latitude + "",
            };
            this.$u.api.upPosition(data).then(() => {
              this.getList(res.latitude, res.longitude);
              this.test();
            });
          },
          fail: (err) => {
            uni.hideLoading();
            console.log("地理位置获取失败", err);
          },
        });
      }
    }
    ,

    testlist() {
      // this.getList();
      this.test();
    }
    ,
    // 获取用户列表
    getList(la = 0, lo = 0) {
      var arr = [];
      map.getCenterLocation({
        success: (res) => {
          let latitude = res.latitude;
          let longitude = res.longitude;
          if (la !== 0) {
            latitude = la;
            longitude = lo;
          }


          // console.info("🚀 ~ file:index method:success line:1038 -----", latitude,longitude)
          this.latitude = latitude;
          this.longitude = longitude;
          let data = {
            userId: this.vuex_user.id,
            lat: this.center.latitude,
            lon: this.center.longitude,
            nort_lat: this.Showip?.northeast?.latitude || 0,
            nort_lon: this.Showip?.northeast?.longitude || 0,
            sout_lat: this.Showip?.southwest?.latitude || 0,
            sout_lon: this.Showip?.southwest?.longitude || 0,
          };
          if (this.timeer) {
            clearTimeout(this.timeer)
          }
          this.timeer = setTimeout(() => {
            this.$u.api.HomeMap(data).then((res) => {
              if (res) {
                res.unshift(this.center);
                // res = res.reverse();
                this.list = res;
                // this.test();
              } else {
                /* uni.showToast({
                  title: res.data.msg,
                  icon: "none",
                }); */
              }
              map.getScale({
                success: async (ress) => {
                  this.covers = await this.getFortMatMarkerList(
                      this.Showip.northeast,
                      this.Showip.southwest,
                      ress.scale,
                      this.list
                  );
                  document.querySelectorAll(
                      "#map .csssprite:nth-child(1)"
                  )[0].style.border = "none";
                },
              });
            }).catch(() => {
              this.list = [this.center];
              map.getScale({
                success: async (ress) => {
                  this.covers = await this.getFortMatMarkerList(
                      this.Showip.northeast,
                      this.Showip.southwest,
                      ress.scale,
                      this.list
                  );
                  document.querySelectorAll(
                      "#map .csssprite:nth-child(1)"
                  )[0].style.border = "none";
                },
              });
            });
          }, 500)
        },
      });
    }
    ,
    tap() {
      this.showInfo = false;
    }
    ,
    // 点击获取当前用户信息  注意：<每个 marker 点都必须要有id 不然点击maxker的事件不会触发>
    getUserDetail(i) {
      // console.info(
      //     "🚀 ~ file:index method:getUserDetail line:574 -----",
      //     i.detail.markerId
      // );

      //点击中心点时不显示
      if (i.detail.markerId == 0) return;
      // 判断是否是聚合点
      this.detailInfoList = [];
      if (String(i.detail.markerId).split(".").length > 1) {
        var pointKey = String(i.detail.markerId).replace(".", ",");
        pointKey = pointKey.slice(0, pointKey.length - 1);
        let arr = this.pointDataList[pointKey];
        let isprovince = "";
        let iscity = "";
        // 地址解析 免费 每日10000请求量
        uni.showLoading({
          title: "加载中",
        });
        this.$jsonp(
            "https://apis.map.qq.com/ws/geocoder/v1/?key=2OLBZ-OOSRQ-RYZ5A-GMCM2-DJ43O-3QFLS&location=" +
            arr[0].latitude +
            "," +
            arr[0].longitude +
            "&output=jsonp&get_poi=1"
        ).then((res) => {
          if (res.status == 0) {
            isprovince = res.result.address_component.province;
            iscity = res.result.address_component.city;
            for (let i in arr) {
              arr[i].province = isprovince ? isprovince : "未";
              arr[i].city = iscity ? iscity : "知";
            }
            this.detailInfoList = arr;
            this.isExpanded = '0vh';
            this.showPopup = true
            setTimeout(() => {
              this.isExpanded = '90vh';
            }, 10);
            // this.showList();
            uni.hideLoading();
          }
        });
      } else {

        // 根据id筛选获取用户信息
        let a = this.list.filter((item) => {

          return (
              parseInt((item.latitude - -item.longitude) * 100000) ==
              i.detail.markerId
          );
        })[0];

        if (a.userId == this.detailInfo.userId) {
          setTimeout(() => {
            this.showInfo = true;
            this.showPopup = false
          }, 100);
          return;
        }

        // 地址解析
        this.$jsonp(
            "https://apis.map.qq.com/ws/geocoder/v1/?key=2OLBZ-OOSRQ-RYZ5A-GMCM2-DJ43O-3QFLS&location=" +
            a.latitude +
            "," +
            a.longitude +
            "&output=jsonp&get_poi=1"
        ).then((res) => {
          // console.log("解析地址成功", res);
          // console.log("当前地址：", res.result.address);
          if (res.status == 0) {
            a.province = res.result.address_component.province;
            a.city = res.result.address_component.city;
          }
          this.detailInfo = a;
          setTimeout(() => {
            this.showInfo = true;
            this.showPopup = false
          }, 100);
        });
      }
    }
    ,

    togglePopup() {
      this.isExpanded = '90vh';
    }
    ,
    touchStart(e) {
      // 记录起始触摸点
      this.touchStartY = e.touches[0].clientY;
      // 记录起始滚动位置
      this.startScrollTop = e.currentTarget.scrollTop;
    }
    ,
    touchMove(e) {

      const currentY = e.touches[0].clientY;
      const diff = this.touchStartY - currentY;
      const scrollTop = e.currentTarget.scrollTop;

      // 判断是否在内容顶部或底部
      const isAtTop = scrollTop <= 0;
      const isAtBottom = scrollTop + e.currentTarget.clientHeight >= e.currentTarget.scrollHeight;

      // 在顶部向下滑动或在底部向上滑动时，阻止默认行为
      if ((isAtTop && diff < 0) || (isAtBottom && diff > 0)) {
        e.preventDefault();
      }

      // 向上滑动超过50px时展开
      if (diff > 50) {
        this.isExpanded = '90vh';
      }
      // 向下滑动超过50px时收起
      else if (diff < -50) {
        if (this.isExpanded == '40vh') {
          console.log("关闭");
          this.isExpanded = '0vh';
          setTimeout(() => {
            this.showPopup = false
          }, 100);
        } else {
          console.log("收起");
          this.isExpanded = '40vh';
        }
      }
    }
    ,
    touchMoveFn(e) {
      if (this.timeer) {
        clearTimeout(this.timeer)
      }
      this.timeer = setTimeout(() => {
        this.touchMove(e)
      }, 100)
    }
    ,
    touchEnd(e) {
      // 可以在这里添加滑动结束后的处理逻辑
    }
    ,
  },
};
</script>

<style scoped lang="scss">
.AIdescribe {
  display: block;
  font-size: 26rpx;
  color: rgba(0, 0, 0, 0.4);
  line-height: 30rpx;
  text-align: left;
  margin-top: 20rpx;
  max-width: 67vw;
  white-space: break-spaces;
}

.tags {
  gap: 10rpx;
  margin-top: 20rpx;
}

.h100 {
  height: 100%
}

.search-box {
  width: 72rpx;
  height: 72rpx;
  border-radius: 50%;
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;

  position: absolute;
  top: 50rpx;
  left: 50rpx;
  z-index: 1;
  box-shadow: 0rpx 10rpx 10rpx -6rpx rgba(0, 0, 0, 0.1),
  0rpx 16rpx 20rpx 2rpx rgba(0, 0, 0, 0.06),
  0rpx 6rpx 28rpx 4rpx rgba(0, 0, 0, 0.05);
}

::v-deep .uni-scroll-view-content {
  background: #f6f8f9 !important;
}

::v-deep #map .csssprite {
  border-radius: 50%;
  border: 2px solid #358ddf !important;
  filter: drop-shadow(0px 0px 2px #358ddf);
  transform: scale(0.8);
}

::v-deep #map > div > div > div > div > div:nth-last-child(4) > div > div {
  overflow: initial !important;
}


// ::v-deep #map>div>div>div>div>div:nth-last-child(4)>div>div:nth-child(1)>.csssprite[src=''] {
// 	border: none !important;
// }
.name-work {
  display: flex;
  flex-direction: column;
  padding-left: 20rpx;
}

.info {
  position: absolute;
  right: 0;
  left: 0;
  transform: translateY(-125%);

  .section_2 {
    padding: 0.11rem 0.18rem 0.15rem 0.21rem;
    background-color: rgb(255, 255, 255);
    box-shadow: 0px 0px 0.1rem rgba(0, 0, 0, 0.1);
    border-radius: 0.1rem;

    .text_3 {
      color: #3CB5FB;
      font-size: 26rpx;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      margin-left: 10rpx;
      vertical-align: middle;

      img {
        vertical-align: middle;
        Width: 48rpx;
      }
    }

    .group_6 {
      white-space: nowrap;
      border-top: 1px solid #F4F6F8;
      padding-top: 20rpx;
      margin-top: 20rpx;

      .text_4 {
        margin-right: 0.1rem;
        color: rgb(63, 63, 63);
        font-size: 0.14rem;
        line-height: 0.16rem;
        white-space: nowrap;
      }

      .text_5 {
        font-size: 28rpx;
        color: rgba(0, 0, 0, 0.6);
        line-height: 0.16rem;
        letter-spacing: 0.014rem;
        white-space: nowrap;
      }
    }

    .group_5 {
      color: rgb(56, 58, 63);
      font-size: 0.18rem;
      line-height: 0.17rem;
      white-space: nowrap;

      .image_5 {
        width: 0.44rem;
        height: 0.44rem;
        border-radius: 50%;
      }

      .text_1 {
        font-size: 30rpx;
        // margin-left: 0.13rem;
        //margin-top: 22rpx;
      }
    }

    .section_3 {
      padding: 20rpx 20rpx;
      color: rgb(255, 255, 255);
      font-size: 24rpx;
      white-space: nowrap;
      background-color: #3cb5fb;
      border-radius: 0.15rem;
      height: 56rpx;
      display: flex;
      align-items: center;
      justify-content: center;
      position: absolute;
      right: 0;
      top: 50%;
      transform: translateY(-50%);

      .image_6 {
        width: 32rpx;
        height: 32rpx;
      }

      .text_2 {
        margin-left: 0.055rem;
      }
    }

    // .text {
    // 	text-transform: uppercase;
    // }
  }
}

.bottom {
  position: fixed;
  z-index: 10;
  bottom: 0;
  right: 2%;
  left: 2%;
  padding-bottom: 0.48rem;

  .btn {
    display: flex;
    justify-content: center;
    margin-top: 0.22rem;
  }

  .section_4 {
    margin-right: 0.025rem;
    margin-top: 0.17rem;
    padding: 0.2rem 0.2rem 0.3rem;
    color: rgb(193, 196, 204);
    font-size: 0.14rem;
    line-height: 0.14rem;
    white-space: nowrap;
    background-color: rgb(255, 255, 255);
    box-shadow: 0px 0px 0.03rem rgba(0, 0, 0, 0.1);
    border-radius: 0.1rem 0.1rem 0 0;

    .search {
      margin-left: 0.14rem;
      margin-right: 0.1rem;
      padding: 0.14rem 0 0.13rem;
      background-color: rgb(246, 247, 250);
      border-radius: 0.05rem;

      // .text {
      // 	text-transform: uppercase;
      // }
    }
  }
}

.popup-box {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  min-height: 240rpx;
  box-shadow: 0rpx -14rpx 16rpx 0rpx rgba(0, 0, 0, 0.06);
  border-top-left-radius: 40rpx;
  border-top-right-radius: 40rpx;
  transition: all 0.3s ease;
  z-index: 100;
}


.popup-top {
  // position: fixed;
  // top: 0;
  width: 100%;
  padding-top: 20rpx;
  background: #fff;
  border-top-left-radius: 40rpx;
  border-top-right-radius: 40rpx;
  cursor: pointer; // 添加手型光标
}

.pop-top {
  width: 88rpx;
  height: 10rpx;
  background: #9ea1b9;
  border-radius: 200rpx;
  margin: 20rpx auto 0;
}

.pop-title {
  padding: 20rpx 32rpx 40rpx;
  font-weight: 600;
  font-size: 32rpx;
  color: #191919;
  background: #fff;
}

.content {
  height: calc(100% - 174rpx) !important;
  overflow-y: auto;
  background: #f6f8f9;
  padding: 30rpx 30rpx 50rpx;
  // -webkit-overflow-scrolling: touch;
}

.back-to-location {
  display: flex;
  align-items: center;
  justify-content: center;
  position: absolute;
  bottom: 180rpx;
  right: 50rpx;
  z-index: 1;
}

::v-deep #map > div:nth-child(1) > div > div:nth-child(1) > div > div:nth-child(2) {
  z-index: 999999 !important;
}

::v-deep #map a[title="到腾讯地图查看此区域"] {
  display: none !important;
}

.position-relative {
  position: relative;
}
</style>
