leaflet地图使用 vue3+ts

<div id="partyMap"></div>

        <div class="map-layer">

          <div :class="{ active: switchValue === 1 }" @click="switchLayer(1)">

            <span>矢量图</span>

          </div>

          <div :class="{ active: switchValue === 2 }" @click="switchLayer(2)">

            <span>影像图</span>

          </div>

        </div>
<div
          style="
            width: 100%;
            height: 74px;
            position: absolute;
            bottom: -2px;
            left: 0;
            z-index: 2003;
            background-color: #fff;
          "
        >
          <van-sticky :offset-bottom="10" :z-index="999" position="bottom">
            <div class="search-bottom">
              <van-row>
                <van-col span="11">
                  <van-dropdown-menu direction="up" :z-index="2666">
                    <van-dropdown-item
                      v-model="searchType"
                      :options="searchTypeList"
                      @change="handleChange"
                    />
                  </van-dropdown-menu>
                </van-col>
                <van-col span="13">
                  <van-search
                    v-model="keyword"
                    shape="round"
                    readonly
                    placeholder="请输入党组织名称"
                    input-align="center"
                    @click-input="handleInput"
                  />
                </van-col>
              </van-row>
            </div>
          </van-sticky>
        </div>
import icon from "@/assets/leaflet/marker-icon.png"; // 引入leaflet默认图标
import iconShadow from "@/assets/leaflet/marker-shadow.png";
import * as L from "leaflet";
import "leaflet/dist/leaflet.css";
import "/public/leaflet/iclient-leaflet.min.js";
import "/public/leaflet/iclient-leaflet.min.css";

<template>
  <div class="party-statistics">
    <div class="tab-top">
      <van-tabs
        v-model:active="activeName"
        color="#0076F6"
        title-active-color="#0076F6"
        style="width: 100%"
        @click-tab="handleTabs"
      >
        <van-tab title="党建信息" name="a"></van-tab>
        <!-- <van-tab title="党员信息" name="b"></van-tab> -->
        <van-tab title="党建地图" name="c"></van-tab>
        <!-- <van-tab title="组织生活" name="d"></van-tab> -->
        <van-tab title="党建教育" name="e"></van-tab>
      </van-tabs>
    </div>
    <div class="main">
      <!-- 党建信息 -->
      <PartyBuildInfo v-if="activeName == 'a'" />
      <!-- 党员信息 -->
      <PartyMemberInfo v-if="activeName == 'b'" />
      <!-- 组织生活 -->
      <PartyBuilding v-if="activeName == 'd'" />
      <!-- 党建教育 -->
      <PartyTrain v-if="activeName == 'e'" />
      <!-- 党建地图 -->
      <!-- <partyBuildingMap v-if="activeName == 'c'" /> -->

      <div v-if="activeName == 'c'" class="party-map">
        <div id="partyMap"></div>
        <div class="map-layer">
          <div :class="{ active: switchValue === 1 }" @click="switchLayer(1)">
            <span>矢量图</span>
          </div>
          <div :class="{ active: switchValue === 2 }" @click="switchLayer(2)">
            <span>影像图</span>
          </div>
        </div>
        <div
          style="
            width: 100%;
            height: 74px;
            position: absolute;
            bottom: -2px;
            left: 0;
            z-index: 2003;
            background-color: #fff;
          "
        >
          <van-sticky :offset-bottom="10" :z-index="999" position="bottom">
            <div class="search-bottom">
              <van-row>
                <van-col span="11">
                  <van-dropdown-menu direction="up" :z-index="2666">
                    <van-dropdown-item
                      v-model="searchType"
                      :options="searchTypeList"
                      @change="handleChange"
                    />
                  </van-dropdown-menu>
                </van-col>
                <van-col span="13">
                  <van-search
                    v-model="keyword"
                    shape="round"
                    readonly
                    placeholder="请输入党组织名称"
                    input-align="center"
                    @click-input="handleInput"
                  />
                </van-col>
              </van-row>
            </div>
          </van-sticky>
        </div>
        <!-- 搜索面板 -->
        <div class="search-con">
          <van-action-sheet
            :style="{ height: '56%', zIndex: 2222 }"
            v-model:show="isShowSearch"
            title="搜索"
            :overlay="false"
          >
            <van-row>
              <van-col span="11">
                <van-dropdown-menu direction="down" :z-index="2666">
                  <van-dropdown-item
                    v-model="searchType"
                    :options="searchTypeList"
                    @change="handleChange"
                  />
                </van-dropdown-menu>
              </van-col>
              <van-col span="13">
                <van-search
                  v-model="keyword"
                  placeholder="请输入党组织名称"
                  input-align="center"
                  @update:model-value="handleSearch"
                />
              </van-col>
              <van-col span="24"
                ><div class="search-list" v-if="searchList.length > 0">
                  <div
                    v-for="(item, index) in searchList"
                    :key="index"
                    @click="handlePosition(item)"
                  >
                    <div>
                      <span>{{ item.label }}</span>
                      <van-image width="16" height="16" :src="flyto" />
                    </div>
                    <van-divider />
                  </div>
                </div>
                <div
                  v-else
                  style="
                    width: 100%;
                    display: flex;
                    justify-content: center;
                    padding-top: 10%;
                  "
                >
                  <van-image width="100" height="100" :src="emptySearch" /></div
              ></van-col>
            </van-row>
          </van-action-sheet>
        </div>
        <!-- 详情面板 -->
        <van-action-sheet
          v-model:show="showActionSheet"
          title="详情"
          z-index="3333"
        >
          <div class="content" v-if="partyObj.type == 'point'">
            <div class="details-con details-con-margin">
              <span class="details-label">党组织名称:</span>
              <span class="details-value">
                {{ partyObj.partyOrganizationName || "--" }}
              </span>
            </div>
            <div class="details-con details-con-margin">
              <span class="details-label">支部书记:</span>
              <span class="details-value">
                {{ partyObj.secretaryName || "--" }}
              </span>
            </div>
            <div class="details-con details-con-margin">
              <span class="details-label">联系方式:</span>
              <span class="details-value">
                {{ partyObj.contactWay || "--" }}
              </span>
            </div>
            <div class="details-con">
              <span class="details-label">组织性质:</span>
              <span class="details-value">
                {{ partyObj.organizationalNatureName || "--" }}
              </span>
            </div>
            <div class="details-con details-con-margin">
              <span class="details-label">党员数量:</span>
              <span class="details-value">
                {{ partyObj.partyMemberCount || "0" }}
              </span>
            </div>
          </div>
          <div class="content" v-else>
            <div class="details-con details-con-margin">
              <span class="details-label">党建指导站名称:</span>
              <span class="details-value">
                {{ partyObj.partyGuidanceName || "--" }}
              </span>
            </div>
            <div class="details-con details-con-margin">
              <span class="details-label">站长姓名:</span>
              <span class="details-value">
                {{ partyObj.stationName || "--" }}
              </span>
            </div>
            <div class="details-con details-con-margin">
              <span class="details-label">成员部门:</span>
              <span class="details-value">
                {{ partyObj.memberDep || "--" }}
              </span>
            </div>
            <div class="details-con">
              <span class="details-label">区域范围:</span>
              <span class="details-value">
                {{ partyObj.areaRange || "--" }}
              </span>
            </div>
            <div class="details-con details-con-margin">
              <span class="details-label">站点地址:</span>
              <span class="details-value">
                {{ partyObj.stationAddress || "--" }}
              </span>
            </div>
          </div>
        </van-action-sheet>
      </div>
    </div>
  </div>
</template>
<script lang="ts" setup>
import { Ref } from "vue";
import { useRoute, useRouter } from "vue-router";
import PartyBuildInfo from "./components/partyBuildInfo.vue";
import PartyMemberInfo from "./components/partyMemberInfo.vue";
import PartyBuilding from "./partyBuilding.vue";
import PartyTrain from "../partyTrain/index.vue";
// 党建地图
// import PartyBuildingMap from "./partyBuildingMap.vue";
import emptySearch from "@/assets/empty_search.png";
import flyto from "@/assets/flyto.png";
import icon from "@/assets/leaflet/marker-icon.png"; // 引入leaflet默认图标
import iconShadow from "@/assets/leaflet/marker-shadow.png";
import * as L from "leaflet";
import "leaflet/dist/leaflet.css";
import "/public/leaflet/iclient-leaflet.min.js";
import "/public/leaflet/iclient-leaflet.min.css";
import {
  partyStatisticsServer,
  investmentStatisticsServer,
} from "@/api/cockpit";
const { VITE_GLOB_MAP_WMS_Server_Url, VITE_GLOB_MAP_REST_Server_Url } =
  import.meta.env;

let activeName: Ref<string> = ref("a");
const route = useRoute();
// const partyBuildingLayer: Ref<any> = ref(null); // 图层
// const partyBuildingSingleLayer: Ref<any> = ref(null); // 单个图层

//地图容器
const partyMap: Ref<any> = ref(null);
const vectorLayer: Ref<any> = ref(null); // 矢量图层
const imageLayer: Ref<any> = ref(null); // 影像图层
const imagePoiLayer: Ref<any> = ref(null); // 影像poi图层
const handleTabs = () => {
  if (activeName.value === "c") {
    if (partyMap.value != undefined) partyMap.value.remove();
    landResourceLayer.value = L.layerGroup();
    landPointLayer.value = L.layerGroup();
    nextTick(() => {
      initMap();
    });
  }
};

//初始化地图
const initMap = () => {
  partyMap.value = L.map("partyMap", {
    crs: L.CRS.EPSG4326,
    center: [38.4910380924075, 106.118078897264],
    maxZoom: 17,
    minZoom: 10,
    zoom: 11,
    attributionControl: false, // 地图底部右侧说明信息
    zoomControl: false, // 地图缩放按钮
  });
  // 矢量图层
  vectorLayer.value = L.tileLayer.wms(VITE_GLOB_MAP_WMS_Server_Url, {
    layers: "yinchuan_qs_01",
    format: "image/png",
    transparent: true,
    noWrap: true,
  });
  partyMap.value.doubleClickZoom.disable(); //禁止双击放大地图
  // 影像图层
  imageLayer.value = L.supermap.tiledMapLayer(VITE_GLOB_MAP_REST_Server_Url);
  // 影像图层poi图层
  imagePoiLayer.value = L.supermap.tiledMapLayer(
    "https://jkqzhyq-spg.nxnzt.cn/iserver/services/map-YinChuanShiJingJiKaiFaQuDiTu0530/rest/maps/yinchuan_poi_01"
  );
  // 初始化添加矢量图层
  vectorLayer.value.addTo(partyMap.value);
  partyMap.value.addLayer(landResourceLayer.value);
  partyMap.value.addLayer(landPointLayer.value);
// 查询区域
  getAreaList();
};
// 分页查询
const buildingByPage = {
  pageIndex: 1, //页码
  pageSize: 1000, //每页展示条数
  partyGuidanceId: "", //党建指导站id
  // partyOrganizationName: "", //党组织名称
};
// 党建地图点位列表
const locationList: Ref<any> = ref([]);
// 获取党建地图点位列表
const getLocationList = async () => {
  buildingByPage.partyGuidanceId = searchType.value;
  const { success, obj } =
    await partyStatisticsServer.getPartyOrganizationPageList(buildingByPage);
  if (success) {
    if (obj) {
      locationList.value = [];
      obj.items?.map((item: any) => {
        locationList.value = locationList.value.concat(item);
      });
      if (locationList.value.length > 0) {
        createMaker();
        searchList.value = locationList.value.map((item: any) => {
          return {
            ...item,
            label: item.partyOrganizationName,
          };
        });
      } else {
        searchList.value = [];
      }
    }
  }
};
// 搜索
const searchType: any = ref();
// 搜索类型列表
const searchTypeList: Ref<any> = ref([]);
// 获取类型列表获取区域
const getAreaList = async () => {
  const { success, obj } = await partyStatisticsServer.selectAll();
  if (success) {
    if (obj) {
      searchTypeList.value = obj.map((item: any) => {
        return {
          text: item.partyGuidanceName,
          value: item.partyGuidanceId,
          ...item,
        };
      });
      searchTypeList.value.unshift({
        value: "1",
        text: "全部党建指导站",
        partyGuidanceId: "1",
        areaLocation: "",
      });
      searchType.value = searchTypeList.value[0].partyGuidanceId;
      obj.forEach((item: any) => {
        if (item.areaLocation) {
          const polygon = L.polygon(JSON.parse(item.areaLocation), {
            color: "#00b042",
          });

          // 多边形点击事件;
          polygon.on(`click`, () => {
            partyMap.value.flyTo(polygon.getBounds().getCenter(), 12.5);
            // 查看详情
            handleDetails(item, "layer");
            // // 图层改变
            handleChange(item.partyGuidanceId);
          });
          polygon.addTo(partyMap.value);
        }
      });
    }
  }
};
const landPointLayer: Ref<any> = ref(null); // 土地资源图层

//点位的图标
const myIcon: Ref<any> = ref(null);
// 创建定位点
const createMaker = () => {
  // 清除
  if (landPointLayer.value) {
    landPointLayer.value.clearLayers();
  }
  myIcon.value = L.icon({
    iconUrl: icon,
    shadowUrl: iconShadow,
    iconSize: [20, 35],
    iconAnchor: [2, 29],
    popupAnchor: [-1, -121],
    shadowSize: [60, 50],
    shadowAnchor: [14, 49],
  });
  locationList.value.forEach((item: any) => {
    if (item.location == "") {
      item.location = "106.1249819;38.46439295";
    }
    if (
      item.location &&
      item.location.indexOf("106.") > -1 &&
      item.location.indexOf(",38.") > -1
    ) {
      const lat = item.location.split(",")[1];
      const lng = item.location.split(",")[0];
      const marker = L.marker([lat, lng], { icon: myIcon.value }).addTo(
        landPointLayer.value
      );
      marker.addTo(landResourceLayer.value);
      
      // 标记点击事件
      marker.on(`click`, () => {
        handleDetails(item, "point");
      });
    }
  });
};

const landResourceLayer: Ref<any> = ref(null); // 土地资源图层
const handleChange = (val: any) => {
  searchType.value = val
  // 清除
  if (landResourceLayer.value) {
    landResourceLayer.value.clearLayers();
  }
  // 不为全部
  if (val != "1") {
    searchTypeList.value.map((item) => {
      
      if (item.partyGuidanceId == val) {
        keyword.value = "";
        const polygon = L.polygon(JSON.parse(item.areaLocation), {
          color: "#ee6953",
        });
        // 多边形点击事件;
        polygon.on(`click`, () => {
          handleDetails(item, "layer");
        });
        polygon.addTo(landResourceLayer.value);
        partyMap.value.flyTo(polygon.getBounds().getCenter(), 12.5);
        // 查询标点信息
        getLocationList();
      }
    });
  } else {
    searchList.value = [];
    partyMap.value.flyTo([38.4910380924075, 106.118078897264], 11);
  }
};
// 搜索关键词
const keyword = ref("");
// 搜索内容列表
const searchList = ref([]);
// 点击搜索框
const isShowSearch = ref(false);
const handleInput = () => {
  isShowSearch.value = true;
  searchList.value = locationList.value.map((item: any) => {
    return {
      ...item,
      label: item.partyOrganizationName,
    };
  });
};
// 搜索事件
const handleSearch = () => {
  let arr: any = [];
  if (keyword.value) {
    searchList.value.forEach((item: any) => {
      if (item.label.indexOf(keyword.value) > -1) {
        arr.push(item);
      }
    });
    searchList.value = arr;
  } else {
    searchList.value = locationList.value.map((item: any) => {
      return {
        ...item,
        label: item.partyOrganizationName,
      };
    });
  }
};
// 地图定位
const handlePosition = (val: any) => {
  if (
    val.location &&
    val.location.indexOf("106.") > -1 &&
    val.location.indexOf(",38.") > -1
  ) {
    let LatLng: any = {
      lat: val.location.split(",")[1] - 0.02,
      lng: val.location.split(",")[0],
    };
    // 位移的坐标
    partyMap.value.flyTo(LatLng, 12.5);
  }
};
// 点位详情
const handleDetails = (val: any, type: any) => {
  partyObj.value = { ...val, type: type };
  showActionSheet.value = true;
  actionSheetTitle.value = val.partyOrganizationName;
};
// 详情面板
const showActionSheet: Ref<boolean> = ref(false);
const actionSheetTitle: Ref<string> = ref("");
// 详情
const partyObj: Ref<any> = ref({});

// 切换地图底图图层
const switchValue = ref(1);
const switchLayer = (val: number) => {
  switchValue.value = val;
  if (val === 1) {
    // 移除影像图层
    partyMap.value.removeLayer(imageLayer.value);
    partyMap.value.removeLayer(imagePoiLayer.value);
    // 添加矢量图层到地图
    partyMap.value.addLayer(vectorLayer.value);
  } else {
    // 移除矢量图层
    partyMap.value.removeLayer(vectorLayer.value);
    // 添加影像图层到地图
    partyMap.value.addLayer(imageLayer.value);
    partyMap.value.addLayer(imagePoiLayer.value);
  }
  // 设置地图缩放比例
  partyMap.value.setZoom(12.5);
};
onMounted(() => {
  if (route.query.statisticsType) {
    activeName.value = route.query.statisticsType;
  }
});
</script>
<style lang="scss" scoped>
.party-statistics {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  // padding-top: 50px;

  .tab-top {
    width: 100%;
    height: 50px;
    background: #ffffff;
    // margin-top: 1px;
    position: fixed;
    z-index: 10;
    top: 0;
    border-top: 2px solid #f7f7f7;
  }

  .main {
    width: 100%;
  }
  #partyMap {
    width: 100vw;
    height: calc(100vh - 50px);
  }
  .party-map {
    padding-top: 62px;
    :deep(.van-ellipsis) {
      color: #1989fa;
    }
  }
  .search-bottom {
    :deep(.van-dropdown-menu__bar) {
      height: 54px;
      box-shadow: none;
    }
    :deep(.van-dropdown-item) {
      position: fixed !important;
      z-index: 2668 !important;
      bottom: 72px !important;
    }
    :deep(.van-dropdown-item__content) {
      position: absolute !important;
    }
    :deep(.van-dropdown-menu__item){
      justify-content:left !important;
    }
  }
  .search-con {
    :deep(.van-action-sheet__content) {
      overflow-y: hidden;
    }
    :deep(.van-dropdown-menu__bar) {
      box-shadow: none;
    }
    :deep(.van-dropdown-item) {
      position: fixed !important;
      z-index: 2668 !important;
    }
    :deep(.van-dropdown-item__content) {
      position: absolute !important;
      z-index: 2999 !important;
    }
    .search-list {
      height: 43vh;
      overflow-y: auto;
      & > div {
        width: 96%;
        margin: 0 auto;
        & > div {
          display: flex;
          justify-content: space-between;
          align-items: center;
          padding: 0 12px;
          box-sizing: border-box;
          & > span {
            color: #333333;
            font-size: 12px;
          }
        }
      }
      :deep(.van-divider) {
        margin: 8px 0;
      }
    }
  }

  .content {
    height: 50vh;
    overflow: auto;
    padding: 0 10px 20px;
    box-sizing: border-box;
  }
  .details-con {
    margin: 10px 0;
    padding: 0 10px;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    & > span {
      display: inline-block;
    }
    .details-label {
      font-size: 14px;
      font-weight: 600;
      color: #333333;
      white-space: nowrap;
    }
    .details-value {
      font-size: 14px;
      color: #56585d;
    }
  }
  .details-con-margin {
    margin: 20px 0 !important;
  }
  .map-layer {
    position: absolute;
    right: 10px;
    bottom: 80px;
    z-index: 1000;
    display: flex;
    & > div {
      position: relative;
      width: 66px;
      height: 46px;
      cursor: pointer;
      border-radius: 2px;
      border: 1px solid rgba(153, 153, 153, 0.42);
      & > span {
        position: absolute;
        bottom: 0;
        right: 0;
        display: inline-block;
        height: 16px;
        padding: 0px 2px 4px 2px;
        font-size: 12px;
        color: #fff;
        background-color: rgba(51, 133, 255);
      }
    }
    & > div:hover {
      border: 1px solid #3385ff;
    }
    .active {
      border: 1px solid #3385ff !important;
    }
    & > div:nth-child(1) {
      background: url("@/assets/map_layer/vectorgraph.png") no-repeat;
      background-size: 100% 100%;
      margin-right: 10px;
    }
    & > div:nth-child(2) {
      background: url("@/assets/map_layer/influence_diagram.png") no-repeat;
      background-size: 100% 100%;
    }
  }
}
</style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值