shuishen
2025-10-13 b182939168e70be66733b6b483d466d0c0e6949d
feat:map页面外嵌处理
1 files modified
1 files added
1022 ■■■■ changed files
src/pages/map/index copy.vue 510 ●●●●● patch | view | raw | blame | history
src/pages/map/index.vue 512 ●●●●● patch | view | raw | blame | history
src/pages/map/index copy.vue
New file
@@ -0,0 +1,510 @@
<!-- 地图 -->
<template>
  <!-- 地图容器 -->
  <view class="page-container theme-dark">
    <view id="map" class="map" :prop="setSelectMapLayerKey" :location="location" :change:prop="leaflet.initLayer"
      :change:location="leaflet.setView"></view>
    <view class="weather-box">
      <up-icon customPrefix="xyicon" name="tuceng" size="24" color="#000"></up-icon>
    </view>
    <view class="layer-btn" @click="show = true">
      <up-icon customPrefix="xyicon" name="tuceng" size="24" color="#000"></up-icon>
    </view>
    <view class="location-btn" @click="setMapLocation">
      <up-icon customPrefix="xyicon" name="dingwei" size="24" color="#000"></up-icon>
    </view>
    <drag-ele :isSelectInput="isSelectInput" :searchVal="searchVal">
      <template #searchBox>
        <u-input placeholder="搜索" border="surround" v-model="searchVal" @change="change" color="#fff"
         @focus="isSelectInput = true"
         @blur="isSelectInput = false">
          <template #prefix>
            <view class="search-left-box">
              <u-icon color="#fff" name="arrow-left"></u-icon>
              <up-tooltip ref="addressTooltip" text="text5" color="#fff" bgColor="#333" popupBgColor="#333"
                triggerMode="click" :forcePosition="{right: '0px', top: '0px'}" direction="top">
                <template #trigger>
                  <up-button iconColor="transparent" color="transparent" :hairline="false" size="mini" :stop="false"
                    type="text">{{ searchModeTextType === 0 ? '地址' : '机巢'}}</up-button>
                </template>
                <template #content>
                  <view style="padding: 8rpx 0; text-align: right;">
                    <!-- 按钮1 -->
                    <up-button type="text" size="mini" @click="selectAddress"
                      style="margin: 4rpx 0; width: 100%; text-align: center;">{{ searchModeTextType === 0 ? '机巢' : '地址'}}</up-button>
                  </view>
                </template>
              </up-tooltip>
            </view>
          </template>
          <template #suffix>
            <view class="search-right-box">
              <u-icon color="#fff" name="scan" @click="scanCode"></u-icon>
            </view>
          </template>
        </u-input>
      </template>
      <template #content>
        <view class="search-content">
        </view>
      </template>
    </drag-ele>
    <up-popup v-model:show="show">
      <view class="popup-container">
        <view class="header">
          <view class="title">图层</view>
          <view class="close" @click="show = false">
            <u-icon color="#000" name="close"></u-icon>
          </view>
        </view>
        <view class="content">
          <view class="layer-box" :class="{on: setSelectMapLayerKey === item.key}" v-for="(item, ind) in layers"
            :key="ind" @click="setMapLayer(item)">
            <view class="image">
              <up-image :src="item.src" width="100%" height="100%"></up-image>
            </view>
            <view class="label">{{item.name}}</view>
          </view>
        </view>
      </view>
    </up-popup>
  </view>
</template>
<script setup>
  import DragEle from './drag.vue'
  import {
    useMapStore
  } from "@/store/index.js"
  const mapStore = useMapStore()
  const layers = [{
      src: "/static/images/sl.png",
      name: '标准地图',
      key: 1,
    },
    {
      src: "/static/images/yx.png",
      name: '卫星地图',
      key: 2,
    }
  ]
  const addressTooltip = ref(null)
  const show = ref(false)
  const isSelectInput = ref(false)
  const searchVal = ref('')
  const change = () => {
  }
  const setSelectMapLayerKey = computed(() => mapStore.getSelectMapLayerKey)
  const setMapLayer = (item) => {
    mapStore.setSelectMapLayerKey(item.key)
  }
  const location = ref('')
  const setMapLocation = () => {
    // 获取定位信息
    uni.getLocation({
      type: 'wgs84', // 返回的经纬度是 WGS84 坐标系(适合地图定位)
      isHighAccuracy: true,
      success: function(res) {
        location.value = res
      },
      fail: function(err) {
        console.log('定位失败:', err);
      }
    });
  }
  const searchModeTextType = ref(0)
  const selectAddress = () => {
    searchModeTextType.value = searchModeTextType.value === 0 ? 1 : 0
    addressTooltip.value.showTooltip = false
  }
  const scanCode = () => {
    // 只允许通过相机扫码
    uni.scanCode({
      onlyFromCamera: true,
      success: function(res) {
        console.log('条码类型:' + res.scanType);
        console.log('条码内容:' + res.result);
        // 获取扫码结果
        let url = res.result;
        // 跳转到B页面,并传递URL参数
        uni.navigateTo({
          url: '/subPackages/browser/index?url=' + encodeURIComponent(url)
        });
      },
      fail: function(err) {
        console.log('扫码失败:', err);
        uni.showToast({
          title: '扫码失败',
          icon: 'none'
        });
      }
    });
  }
  const createWorkOrder = (id) => {
    console.log(`创建工单:标注 ID 为 ${id}`);
    // 在这里添加工单创建逻辑
  }
  onShow(() => {
    // #ifdef APP-PLUS
    // plus.screen.lockOrientation("landscape-primary");
    // #endif
  });
  onHide(() => {
    // #ifdef APP-PLUS
    // plus.screen.lockOrientation("portrait-primary");
    // #endif
  });
</script>
<script module="leaflet" lang="renderjs">
  import L from 'leaflet'
  var basemapLayer0 = L.tileLayer(
    'http://t1.tianditu.com/vec_c/wmts?layer=vec&style=default&tilematrixset=c&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk=e110584a27d506da2740edca951683f4', {
      maxZoom: 20,
      minZoom: 1,
      tileSize: 256,
      zoomOffset: 1
    });
  var basemapLayer1 = L.tileLayer(
    'http://t1.tianditu.com/cva_c/wmts?layer=cva&style=default&tilematrixset=c&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk=e110584a27d506da2740edca951683f4', {
      maxZoom: 20,
      minZoom: 1,
      tileSize: 256,
      zoomOffset: 1
    });
  var basemapLayer2 = L.tileLayer(
    'http://t1.tianditu.com/img_c/wmts?layer=img&style=default&tilematrixset=c&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk=e110584a27d506da2740edca951683f4', {
      maxZoom: 20,
      minZoom: 1,
      tileSize: 256,
      zoomOffset: 1
    });
  var basemapLayer3 = L.tileLayer(
    'http://t1.tianditu.com/cia_c/wmts?layer=cia&style=default&tilematrixset=c&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk=e110584a27d506da2740edca951683f4', {
      maxZoom: 20,
      minZoom: 1,
      tileSize: 256,
      zoomOffset: 1
    });
  var basemap0 = L.layerGroup([basemapLayer0, basemapLayer1]);
  var basemap1 = L.layerGroup([basemapLayer2, basemapLayer3]);
  let map = null
  const layers = [{
      src: "/static/images/sl.png",
      name: '标准地图',
      key: 1,
      map: basemap0
    },
    {
      src: "/static/images/yx.png",
      name: '卫星地图',
      key: 2,
      map: basemap1
    }
  ]
  export default {
    data() {
      return {
        curSelectMapLayerKey: 1
      }
    },
    computed: {
    },
    mounted() {
      this.initMap()
      this.initDronePositions()
    },
    methods: {
      initMap() {
        if (map) return
        map = L.map('map', {
          preferCanvas: true,
          crs: L.CRS.EPSG4326,
          zoomControl: false,
          attributionControl: false,
          doubleClickZoom: false,
          editable: true //绘制控件
        }).setView([25.992338, 114.823254], 13);
      },
      initLayer(value) {
        this.initMap()
        this.$nextTick(() => {
          map.removeLayer(layers.find(i => i.key === this.curSelectMapLayerKey).map);
          map.addLayer(layers.find(i => i.key === value).map);
          this.curSelectMapLayerKey = value
        })
      },
      setView(res) {
        if (!res) return
        this.initMap()
        this.$nextTick(() => {
          map.setView([res.latitude, res.longitude], 16, {
            animate: false // 使用动画过渡
          });
        })
      },
      // 初始化无人机位置
      initDronePositions() {
        // 假设你有一个包含多个标注位置的数组
        const markersData = [{
            lat: 25.992338,
            lng: 114.823254,
            id: 1
          },
          {
            lat: 26,
            lng: 114.823255,
            id: 2
          },
          {
            lat: 25.992338,
            lng: 115,
            id: 3
          },
        ];
        // 创建一个自定义的图片图标
        const customIcon = L.icon({
          iconUrl: './static/images/logo.png', // 替换为你的图片路径
          iconSize: [32, 32], // 图标大小
          iconAnchor: [16, 16], // 图标的锚点(设置图片的底部中心)
        });
        // 批量添加标注
        const markersLayer = L.layerGroup().addTo(map); // 创建一个标注层,便于管理和移除
        markersData.forEach((data) => {
          const marker = L.marker([data.lat, data.lng], {
            icon: customIcon
          }).addTo(markersLayer);
          marker.on('click', () => {
            marker.unbindPopup();
            const popupContent = `
              <view>
                <button data-type="addWork">创建工单</button>
              </view>
             `;
            marker.bindPopup(popupContent).openPopup();
            marker.getPopup()._contentNode.addEventListener("click", e => {
              if (e.target.dataset.type === 'addWork') {
                // 跳转到tabBar页面
                uni.switchTab({
                  url: '/pages/work/index', // 需要跳转的tabBar页面的路径
                });
                marker.closePopup();
                marker.unbindPopup();
              }
            })
          });
          // 使用 marker 的 id 作为标识符
          marker.options.id = data.id;
        });
        this.buildCirclePolygon(25.992338, 114.823254, 'rgba(255, 0, 0, 1)').addTo(map)
      },
      buildCirclePolygon(lat, lng, color) {
        var radius = 5000 / 100460; // 5000米转为大约的纬度差(纬度上的1度大约是111km)
        var parts = [];
        for (var i = 0; i < 360; i++) {
          var radians = (i + 1) * Math.PI / 180;
          // 计算新的点
          var circlePoint = [
            Math.cos(radians) * radius + lat, // 纬度偏移
            Math.sin(radians) * radius + lng // 经度偏移,需考虑纬度的影响
          ];
          parts[i] = circlePoint;
        }
        // 生成多边形,近似圆形
        var polygon = L.polygon(parts, {
          color: color
        });
        return polygon;
      }
    }
  }
</script>
<style lang="scss" scoped>
  .page-container {
    position: relative;
    width: 100%;
    height: 100%;
    .u-input {
      margin-left: 16rpx;
      width: calc(100% - 32rpx);
      height: 64rpx;
      box-sizing: border-box;
      background: rgba(0, 0, 0, .4);
      .search-left-box {
        display: flex;
        align-items: center;
        color: $u-main-color;
      }
      .search-right-box {
        color: $u-main-color;
      }
    }
    .search-content {
      width: 100%;
      height: 360rpx;
      background: #fff;
      box-shadow: 0 -80rpx 80rpx -80rpx #fff;
    }
    .weather-box {
      display: flex;
      justify-content: center;
      align-items: center;
      position: absolute;
      top: 16rpx;
      left: 16rpx;
      width: 64rpx;
      height: 64rpx;
      background: #fff;
      z-index: 996;
      border-radius: 8rpx;
    }
    .location-btn,
    .layer-btn {
      display: flex;
      justify-content: center;
      align-items: center;
      position: absolute;
      right: 16rpx;
      width: 64rpx;
      height: 64rpx;
      background: #fff;
      z-index: 996;
      border-radius: 8rpx;
    }
    .layer-btn {
      bottom: 236rpx;
    }
    .location-btn {
      bottom: 156rpx;
    }
  }
  /* Leaflet 默认容器要有高度 */
  .map {
    width: 100%;
    height: 100%;
  }
  .popup-container {
    padding: 20rpx;
    background: #D3D3D3;
    border-radius: 32rpx 32rpx 0 0;
    .header {
      padding: 0 20rpx;
      display: flex;
      justify-content: space-between;
      height: 56rpx;
    }
    .content {
      padding: 20rpx;
      display: flex;
      background: #fff;
      border-radius: 32rpx;
      .layer-box {
        margin-left: 16rpx;
        width: calc(100% / 3);
        &:first-child {
          margin-left: 0;
        }
        &.on {
          .image {
            border: 1px solid #0055ff;
          }
          .label {
            color: #0055ff;
          }
        }
        .image {
          width: 100%;
          height: 96rpx;
          border-radius: 16rpx;
          overflow: hidden;
          box-sizing: border-box;
          border: 1px solid transparent;
        }
        .label {
          line-height: 48rpx;
          text-align: center;
          font-size: 16rpx;
        }
      }
    }
  }
</style>
src/pages/map/index.vue
@@ -1,510 +1,22 @@
<!-- 地图 -->
<template>
  <!-- 地图容器 -->
  <view class="page-container theme-dark">
    <view id="map" class="map" :prop="setSelectMapLayerKey" :location="location" :change:prop="leaflet.initLayer"
      :change:location="leaflet.setView"></view>
    <view class="weather-box">
      <up-icon customPrefix="xyicon" name="tuceng" size="24" color="#000"></up-icon>
    </view>
    <view class="layer-btn" @click="show = true">
      <up-icon customPrefix="xyicon" name="tuceng" size="24" color="#000"></up-icon>
    </view>
    <view class="location-btn" @click="setMapLocation">
      <up-icon customPrefix="xyicon" name="dingwei" size="24" color="#000"></up-icon>
    </view>
    <drag-ele :isSelectInput="isSelectInput" :searchVal="searchVal">
      <template #searchBox>
        <u-input placeholder="搜索" border="surround" v-model="searchVal" @change="change" color="#fff"
         @focus="isSelectInput = true"
         @blur="isSelectInput = false">
          <template #prefix>
            <view class="search-left-box">
              <u-icon color="#fff" name="arrow-left"></u-icon>
              <up-tooltip ref="addressTooltip" text="text5" color="#fff" bgColor="#333" popupBgColor="#333"
                triggerMode="click" :forcePosition="{right: '0px', top: '0px'}" direction="top">
                <template #trigger>
                  <up-button iconColor="transparent" color="transparent" :hairline="false" size="mini" :stop="false"
                    type="text">{{ searchModeTextType === 0 ? '地址' : '机巢'}}</up-button>
                </template>
                <template #content>
                  <view style="padding: 8rpx 0; text-align: right;">
                    <!-- 按钮1 -->
                    <up-button type="text" size="mini" @click="selectAddress"
                      style="margin: 4rpx 0; width: 100%; text-align: center;">{{ searchModeTextType === 0 ? '机巢' : '地址'}}</up-button>
                  </view>
                </template>
              </up-tooltip>
            </view>
          </template>
          <template #suffix>
            <view class="search-right-box">
              <u-icon color="#fff" name="scan" @click="scanCode"></u-icon>
            </view>
          </template>
        </u-input>
      </template>
      <template #content>
        <view class="search-content">
        </view>
      </template>
    </drag-ele>
    <up-popup v-model:show="show">
      <view class="popup-container">
        <view class="header">
          <view class="title">图层</view>
          <view class="close" @click="show = false">
            <u-icon color="#000" name="close"></u-icon>
          </view>
        </view>
        <view class="content">
          <view class="layer-box" :class="{on: setSelectMapLayerKey === item.key}" v-for="(item, ind) in layers"
            :key="ind" @click="setMapLayer(item)">
            <view class="image">
              <up-image :src="item.src" width="100%" height="100%"></up-image>
            </view>
            <view class="label">{{item.name}}</view>
          </view>
        </view>
      </view>
    </up-popup>
  <view class="page-wrap">
    <web-view ref="sWebViewRef" :src="`${viewUrl}`" />
  </view>
</template>
<script setup>
  import DragEle from './drag.vue'
  import {
    useMapStore
  } from "@/store/index.js"
import { useUserStore } from "@/store/index.js";
  const mapStore = useMapStore()
const sWebViewRef = ref(null);
const userStore = useUserStore();
const viewUrl = `http://192.168.1.194:5174/drone-app-web-view/#/webViewWrapper/defaultMap?params=${JSON.stringify(userStore?.userInfo)}`;
  const layers = [{
      src: "/static/images/sl.png",
      name: '标准地图',
      key: 1,
    },
    {
      src: "/static/images/yx.png",
      name: '卫星地图',
      key: 2,
    }
  ]
  const addressTooltip = ref(null)
  const show = ref(false)
  const isSelectInput = ref(false)
  const searchVal = ref('')
  const change = () => {
  }
  const setSelectMapLayerKey = computed(() => mapStore.getSelectMapLayerKey)
  const setMapLayer = (item) => {
    mapStore.setSelectMapLayerKey(item.key)
  }
  const location = ref('')
  const setMapLocation = () => {
    // 获取定位信息
    uni.getLocation({
      type: 'wgs84', // 返回的经纬度是 WGS84 坐标系(适合地图定位)
      isHighAccuracy: true,
      success: function(res) {
        location.value = res
      },
      fail: function(err) {
        console.log('定位失败:', err);
      }
    });
  }
  const searchModeTextType = ref(0)
  const selectAddress = () => {
    searchModeTextType.value = searchModeTextType.value === 0 ? 1 : 0
    addressTooltip.value.showTooltip = false
  }
  const scanCode = () => {
    // 只允许通过相机扫码
    uni.scanCode({
      onlyFromCamera: true,
      success: function(res) {
        console.log('条码类型:' + res.scanType);
        console.log('条码内容:' + res.result);
        // 获取扫码结果
        let url = res.result;
        // 跳转到B页面,并传递URL参数
        uni.navigateTo({
          url: '/subPackages/browser/index?url=' + encodeURIComponent(url)
        });
      },
      fail: function(err) {
        console.log('扫码失败:', err);
        uni.showToast({
          title: '扫码失败',
          icon: 'none'
        });
      }
    });
  }
  const createWorkOrder = (id) => {
    console.log(`创建工单:标注 ID 为 ${id}`);
    // 在这里添加工单创建逻辑
  }
  onShow(() => {
    // #ifdef APP-PLUS
    // plus.screen.lockOrientation("landscape-primary");
    // #endif
  });
  onHide(() => {
    // #ifdef APP-PLUS
    // plus.screen.lockOrientation("portrait-primary");
    // #endif
  });
onLoad(() => {
});
</script>
<script module="leaflet" lang="renderjs">
  import L from 'leaflet'
  var basemapLayer0 = L.tileLayer(
    'http://t1.tianditu.com/vec_c/wmts?layer=vec&style=default&tilematrixset=c&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk=e110584a27d506da2740edca951683f4', {
      maxZoom: 20,
      minZoom: 1,
      tileSize: 256,
      zoomOffset: 1
    });
  var basemapLayer1 = L.tileLayer(
    'http://t1.tianditu.com/cva_c/wmts?layer=cva&style=default&tilematrixset=c&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk=e110584a27d506da2740edca951683f4', {
      maxZoom: 20,
      minZoom: 1,
      tileSize: 256,
      zoomOffset: 1
    });
  var basemapLayer2 = L.tileLayer(
    'http://t1.tianditu.com/img_c/wmts?layer=img&style=default&tilematrixset=c&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk=e110584a27d506da2740edca951683f4', {
      maxZoom: 20,
      minZoom: 1,
      tileSize: 256,
      zoomOffset: 1
    });
  var basemapLayer3 = L.tileLayer(
    'http://t1.tianditu.com/cia_c/wmts?layer=cia&style=default&tilematrixset=c&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk=e110584a27d506da2740edca951683f4', {
      maxZoom: 20,
      minZoom: 1,
      tileSize: 256,
      zoomOffset: 1
    });
  var basemap0 = L.layerGroup([basemapLayer0, basemapLayer1]);
  var basemap1 = L.layerGroup([basemapLayer2, basemapLayer3]);
  let map = null
  const layers = [{
      src: "/static/images/sl.png",
      name: '标准地图',
      key: 1,
      map: basemap0
    },
    {
      src: "/static/images/yx.png",
      name: '卫星地图',
      key: 2,
      map: basemap1
    }
  ]
  export default {
    data() {
      return {
        curSelectMapLayerKey: 1
      }
    },
    computed: {
    },
    mounted() {
      this.initMap()
      this.initDronePositions()
    },
    methods: {
      initMap() {
        if (map) return
        map = L.map('map', {
          preferCanvas: true,
          crs: L.CRS.EPSG4326,
          zoomControl: false,
          attributionControl: false,
          doubleClickZoom: false,
          editable: true //绘制控件
        }).setView([25.992338, 114.823254], 13);
      },
      initLayer(value) {
        this.initMap()
        this.$nextTick(() => {
          map.removeLayer(layers.find(i => i.key === this.curSelectMapLayerKey).map);
          map.addLayer(layers.find(i => i.key === value).map);
          this.curSelectMapLayerKey = value
        })
      },
      setView(res) {
        if (!res) return
        this.initMap()
        this.$nextTick(() => {
          map.setView([res.latitude, res.longitude], 16, {
            animate: false // 使用动画过渡
          });
        })
      },
      // 初始化无人机位置
      initDronePositions() {
        // 假设你有一个包含多个标注位置的数组
        const markersData = [{
            lat: 25.992338,
            lng: 114.823254,
            id: 1
          },
          {
            lat: 26,
            lng: 114.823255,
            id: 2
          },
          {
            lat: 25.992338,
            lng: 115,
            id: 3
          },
        ];
        // 创建一个自定义的图片图标
        const customIcon = L.icon({
          iconUrl: './static/images/logo.png', // 替换为你的图片路径
          iconSize: [32, 32], // 图标大小
          iconAnchor: [16, 16], // 图标的锚点(设置图片的底部中心)
        });
        // 批量添加标注
        const markersLayer = L.layerGroup().addTo(map); // 创建一个标注层,便于管理和移除
        markersData.forEach((data) => {
          const marker = L.marker([data.lat, data.lng], {
            icon: customIcon
          }).addTo(markersLayer);
          marker.on('click', () => {
            marker.unbindPopup();
            const popupContent = `
              <view>
                <button data-type="addWork">创建工单</button>
              </view>
             `;
            marker.bindPopup(popupContent).openPopup();
            marker.getPopup()._contentNode.addEventListener("click", e => {
              if (e.target.dataset.type === 'addWork') {
                // 跳转到tabBar页面
                uni.switchTab({
                  url: '/pages/work/index', // 需要跳转的tabBar页面的路径
                });
                marker.closePopup();
                marker.unbindPopup();
              }
            })
          });
          // 使用 marker 的 id 作为标识符
          marker.options.id = data.id;
        });
        this.buildCirclePolygon(25.992338, 114.823254, 'rgba(255, 0, 0, 1)').addTo(map)
      },
      buildCirclePolygon(lat, lng, color) {
        var radius = 5000 / 100460; // 5000米转为大约的纬度差(纬度上的1度大约是111km)
        var parts = [];
        for (var i = 0; i < 360; i++) {
          var radians = (i + 1) * Math.PI / 180;
          // 计算新的点
          var circlePoint = [
            Math.cos(radians) * radius + lat, // 纬度偏移
            Math.sin(radians) * radius + lng // 经度偏移,需考虑纬度的影响
          ];
          parts[i] = circlePoint;
        }
        // 生成多边形,近似圆形
        var polygon = L.polygon(parts, {
          color: color
        });
        return polygon;
      }
    }
  }
</script>
<style lang="scss" scoped>
  .page-container {
    position: relative;
    width: 100%;
    height: 100%;
    .u-input {
      margin-left: 16rpx;
      width: calc(100% - 32rpx);
      height: 64rpx;
      box-sizing: border-box;
      background: rgba(0, 0, 0, .4);
      .search-left-box {
        display: flex;
        align-items: center;
        color: $u-main-color;
      }
      .search-right-box {
        color: $u-main-color;
      }
    }
    .search-content {
      width: 100%;
      height: 360rpx;
      background: #fff;
      box-shadow: 0 -80rpx 80rpx -80rpx #fff;
    }
    .weather-box {
      display: flex;
      justify-content: center;
      align-items: center;
      position: absolute;
      top: 16rpx;
      left: 16rpx;
      width: 64rpx;
      height: 64rpx;
      background: #fff;
      z-index: 996;
      border-radius: 8rpx;
    }
    .location-btn,
    .layer-btn {
      display: flex;
      justify-content: center;
      align-items: center;
      position: absolute;
      right: 16rpx;
      width: 64rpx;
      height: 64rpx;
      background: #fff;
      z-index: 996;
      border-radius: 8rpx;
    }
    .layer-btn {
      bottom: 236rpx;
    }
    .location-btn {
      bottom: 156rpx;
    }
  }
  /* Leaflet 默认容器要有高度 */
  .map {
    width: 100%;
    height: 100%;
  }
  .popup-container {
    padding: 20rpx;
    background: #D3D3D3;
    border-radius: 32rpx 32rpx 0 0;
    .header {
      padding: 0 20rpx;
      display: flex;
      justify-content: space-between;
      height: 56rpx;
    }
    .content {
      padding: 20rpx;
      display: flex;
      background: #fff;
      border-radius: 32rpx;
      .layer-box {
        margin-left: 16rpx;
        width: calc(100% / 3);
        &:first-child {
          margin-left: 0;
        }
        &.on {
          .image {
            border: 1px solid #0055ff;
          }
          .label {
            color: #0055ff;
          }
        }
        .image {
          width: 100%;
          height: 96rpx;
          border-radius: 16rpx;
          overflow: hidden;
          box-sizing: border-box;
          border: 1px solid transparent;
        }
        .label {
          line-height: 48rpx;
          text-align: center;
          font-size: 16rpx;
        }
      }
    }
  }
<style scoped lang="scss">
.page-wrap {
  font-size: 20px;
}
</style>