罗广辉
2025-10-10 b15a3c0dc35c6a9c6bea1f0826a69ebaaac5ba0c
Merge remote-tracking branch 'origin/master'
6 files modified
3 files added
440 ■■■■ changed files
package.json 2 ●●● patch | view | raw | blame | history
src/pages/login/index.vue 2 ●●● patch | view | raw | blame | history
src/pages/map/index.vue 378 ●●●● patch | view | raw | blame | history
src/plugins/ui.js 26 ●●●● patch | view | raw | blame | history
src/static/images/sl.png patch | view | raw | blame | history
src/static/images/yx.png patch | view | raw | blame | history
src/static/styles/common.scss 5 ●●●● patch | view | raw | blame | history
src/store/index.js 3 ●●●● patch | view | raw | blame | history
src/store/modules/map/index.js 24 ●●●●● patch | view | raw | blame | history
package.json
@@ -141,4 +141,4 @@
      "stylelint --fix"
    ]
  }
}
}
src/pages/login/index.vue
@@ -58,7 +58,7 @@
  ).then(res => {
    userStore.setUserInfo(res.data)
    uni.switchTab({
      url: '/pages/user/index'
      url: '/'
    })
  })
}
src/pages/map/index.vue
@@ -1,81 +1,331 @@
<!-- 地图 -->
<template>
  <!-- 地图容器 -->
  <view id="map" class="map" style="width: 100%; height: 80vh"></view>
  <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="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>
    <u-input placeholder="搜索" border="surround" v-model="value" @change="change" color="#fff">
      <template #prefix>
        <view class="search-left-box">
          <u-icon color="#fff" name="arrow-left"></u-icon> 地址
        </view>
      </template>
      <template #suffix>
        <view class="search-right-box">
          <u-icon color="#fff" name="scan"></u-icon>
        </view>
      </template>
    </u-input>
    <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>
onShow(() => {
  // #ifdef APP-PLUS
  import {
    useMapStore
  } from "@/store/index.js"
  // plus.screen.lockOrientation("landscape-primary");
  // #endif
});
  const mapStore = useMapStore()
onHide(() => {
  // #ifdef APP-PLUS
  // plus.screen.lockOrientation("portrait-primary");
  // #endif
});
  const layers = [{
      src: "/static/images/sl.png",
      name: '标准地图',
      key: 1,
    },
    {
      src: "/static/images/yx.png",
      name: '卫星地图',
      key: 2,
    }
  ]
  const show = ref(false)
  const value = 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);
      }
    });
  }
  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'
import {
  onBeforeUnmount,
  onMounted
} from 'vue';
  import L from 'leaflet'
export default {
  mounted() {
    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: 18,
        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: 18,
        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: 18,
        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: 18,
        minZoom: 1,
        tileSize: 256,
        zoomOffset: 1
      });
    var basemap0 = L.layerGroup([basemapLayer0, basemapLayer1]);
    var basemap1 = L.layerGroup([basemapLayer2, basemapLayer3]);
  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: 18,
      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: 18,
      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: 18,
      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: 18,
      minZoom: 1,
      tileSize: 256,
      zoomOffset: 1
    });
  var basemap0 = L.layerGroup([basemapLayer0, basemapLayer1]);
  var basemap1 = L.layerGroup([basemapLayer2, basemapLayer3]);
    let map = L.map('map', {
      preferCanvas: true,
      crs: L.CRS.EPSG4326,
      layers: [basemap1],
      zoomControl: false,
      attributionControl: false,
      doubleClickZoom: false,
      editable: true //绘制控件
    }).setView([25.992338, 114.823254], 13);
  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 {
        setSelectMapLayerKey: 1
      }
    },
    computed: {
    },
    mounted() {
      this.initMap()
    },
    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.setSelectMapLayerKey).map);
          map.addLayer(layers.find(i => i.key === value).map);
          this.setSelectMapLayerKey = value
        })
      },
      setView(res) {
        if (!res) return
        this.initMap()
        this.$nextTick(() => {
          map.setView([res.latitude, res.longitude], 16, {
            animate: false // 使用动画过渡
          });
        })
      }
    }
  }
}
</script>
<style scoped>
/* Leaflet 默认容器要有高度 */
.map {
  width: 100%;
  height: 100%;
}
<style lang="scss" scoped>
  .page-container {
    position: relative;
    width: 100%;
    height: 100%;
    .u-input {
      position: absolute;
      left: 16rpx;
      bottom: 16rpx;
      width: calc(100% - 32rpx);
      height: 64rpx;
      z-index: 999;
      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;
      }
    }
    .location-btn,
    .layer-btn {
      display: flex;
      justify-content: center;
      align-items: center;
      position: absolute;
      right: 16rpx;
      width: 64rpx;
      height: 64rpx;
      background: #fff;
      z-index: 999;
      border-radius: 8rpx;
    }
    .layer-btn {
      bottom: 176rpx;
    }
    .location-btn {
      bottom: 96rpx;
    }
  }
  /* 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/plugins/ui.js
@@ -1,6 +1,8 @@
import uviewPlus, { setConfig } from "uview-plus"
import uviewPlus, {
  setConfig
} from "uview-plus"
function setupUI (app) {
function setupUI(app) {
  // 下面的在特殊场景下才需要配置,通常不用配置即可直接使用uview-plus框架。
  // 调用setConfig方法,方法内部会进行对象属性深度合并,可以放心嵌套配置
  // 需要在app.use(uview-plus)之后执行
@@ -8,7 +10,7 @@
    // 修改$u.config对象的属性
    config: {
      // 修改默认单位为rpx,相当于执行 uni.$u.config.unit = 'rpx'
      unit: "px"
      unit: "rpx"
    },
    // 修改$u.props对象的属性
    props: {
@@ -21,7 +23,23 @@
    }
  })
  app.use(uviewPlus)
  app.use(uviewPlus, () => {
    return {
      options: {
        // 修改config对象的属性
        config: {
          customIcon: {
            family: 'xyicon',
            url: 'https://at.alicdn.com/t/c/font_5036193_7g86rzw8srl.ttf?t=1760003919145'
          },
          customIcons: {
            'tuceng': '\uea2d',
            'dingwei': '\ue610',
          },
        }
      }
    }
  })
}
export default setupUI
src/static/images/sl.png
src/static/images/yx.png
src/static/styles/common.scss
@@ -2,4 +2,7 @@
  font-size: $u-font-base;
  color: $u-main-color;
  background-color: $u-bg-color;
}
  height: 100%;
}
src/store/index.js
@@ -5,6 +5,7 @@
// 导入子模块
import useAppStore from "./modules/app"
import useUserStore from "./modules/user"
import useMapStore from "./modules/map"
// 安装pinia状态管理插件
function setupStore (app) {
@@ -22,5 +23,5 @@
}
// 导出模块
export { useAppStore, useUserStore }
export { useAppStore, useUserStore, useMapStore }
export default setupStore
src/store/modules/map/index.js
New file
@@ -0,0 +1,24 @@
import {
  defineStore
} from 'pinia'
const useMapStore = defineStore('map', {
  state: () => ({
    selectMapLayerKey: 1 // 默认展示地图
  }),
  actions: {
    setSelectMapLayerKey(selectMapLayerKey) {
      this.selectMapLayerKey = selectMapLayerKey
    },
  },
  getters: {
    getSelectMapLayerKey(state) {
      return state.selectMapLayerKey
    },
  },
  persist: true //持久化
})
export default useMapStore