![](https://img-blog.csdnimg.cn/direct/41a519813b954cdb8bbc11d7adbb03e1.png)
<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>