FenXiNspUniapp/pages/maps/index.vue

703 lines
17 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container">
<map id="map" ref="map" style="width: 100%; height: calc(100vh + 50rpx);" :scale="mapScale" :markers="markers"
longitude="112.83100231396601" latitude="36.872032399813556" show-location show-compass show-scale
@markertap="markertap">
</map>
<view class="zdxq">
<view class="zdxqitem" @click="switch2Change('livestock')">
<image src="../../static/zhandian_xuqin_dingwei.png" mode=""></image>
<view class="textss">
畜禽污染监测站
</view>
</view>
<view class="zdxqitem" @click="switch2Change('enterprise')">
<image src="../../static/qiyebzIcon.png" mode="" style="width: 40rpx; height: 40rpx;"></image>
<view class="textss">
企业点位
</view>
</view>
</view>
<!-- 企业信息弹出框 -->
<view class="enterprise-popup" v-if="showEnterprisePopup" @click="closePopup">
<view class="popup-content" @click.stop>
<view class="popup-header">
<text class="popup-title">{{ currentEnterprise.entName || '企业信息' }}</text>
<text class="popup-close" @click="closePopup">×</text>
</view>
<view class="popup-body">
<view class="info-item">
<text class="label">企业简称:</text>
<text class="value">{{ currentEnterprise.entShortName || '-' }}</text>
</view>
<view class="info-item">
<text class="label">负责人:</text>
<text class="value">{{ currentEnterprise.entCharge || '-' }}</text>
</view>
<view class="info-item">
<text class="label">统一信用代码:</text>
<text class="value">{{ currentEnterprise.entCredit || '-' }}</text>
</view>
<view class="info-item">
<text class="label">企业编号:</text>
<text class="value">{{ currentEnterprise.entCode || '-' }}</text>
</view>
<view class="info-item">
<text class="label">企业简介:</text>
<text class="value">{{ currentEnterprise.entIntro || '暂无简介' }}</text>
</view>
<view class="info-item">
<text class="label">联系电话:</text>
<text class="value">{{ currentEnterprise.entPhone || '暂无' }}</text>
</view>
<view class="info-item">
<text class="label">创建时间:</text>
<text class="value">{{ currentEnterprise.createTime || '-' }}</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import api from '@/api/api'
import configService from '@/common/service/config.service.js';
export default {
data() {
return {
baseUrl: configService.staticDomainURL,
center: {
latitude: 36.5,
longitude: 111.7
},
mapScale: 13,
markers: [],
markersZIndex: 1,
lastTap: '',
stationList: [],
cusLocationList: [],
soilStationList: [],
allStationList: [],
stationTwoList: [],
enterpriseList: [],
mapCtx: null,
showEnterprisePopup: false,
currentEnterprise: {},
currentMarkerId: null,
maxMarkerId: 0,
debugMode: true
};
},
onLoad() {},
onReady() {
this.mapCtx = uni.createMapContext('map', this);
},
onShow() {
api.checkLogin(() => {
this.$nextTick(() => {
this.getList()
})
}, () => {
uni.reLaunch({
url: '/packDetail/pages/login/login'
})
})
},
methods: {
getList() {
this.markers = []
this.stationList = []
this.cusLocationList = []
this.soilStationList = []
this.allStationList = []
this.stationTwoList = []
this.enterpriseList = []
uni.showLoading({
title: '加载中'
});
// 获取监测站数据
this.$http.get('/applet/survStationInfo/stationMap').then(res => {
this.stationList = [...res.data.data.stationInfo];
this.cusLocationList = [...res.data.data.cusLocation];
this.soilStationList = [...res.data.data.deviceList];
this.allStationList.push(...this.stationList);
this.allStationList.push(...this.cusLocationList);
this.allStationList.push(...this.soilStationList);
this.allStationList.forEach((item, index) => {
item.id = index + 1;
});
this.issscd = false
this.isssscd = false
this.isSoilShow = false
this.maxMarkerId = this.allStationList.length + 1;
this.enterpriseRender();
this.stationRender();
this.monitorRender()
uni.hideLoading();
}).catch(err => {
uni.hideLoading();
uni.showToast({
title: '数据加载失败',
icon: 'none'
});
console.error('加载地图数据失败:', err);
})
// 获取企业列表
this.$http.get('/applet/wxclient/getEntList').then(res => {
if (res.data.data && res.data.data.result) {
this.enterpriseList = res.data.data.result;
this.renderEnterpriseMarkers();
// 数据加载完成后调整地图视野显示全部点位
this.$nextTick(() => {
this.ensureAllMarkersVisible();
});
}
uni.hideLoading();
}).catch(err => {
uni.hideLoading();
uni.showToast({
title: '企业数据加载失败',
icon: 'none'
});
console.error('加载企业数据失败:', err);
})
},
renderEnterpriseMarkers() {
if (!this.enterpriseList || this.enterpriseList.length === 0) {
console.warn('企业列表为空');
return;
}
this.enterpriseList.forEach((item, index) => {
const lat = Number(item.entLat);
const lng = Number(item.entLong);
if (isNaN(lat) || isNaN(lng) || lat === 0 || lng === 0) {
console.warn('企业坐标无效:', item.entName, lat, lng);
return;
}
const markerId = ++this.maxMarkerId;
let iconPath = '/static/qiyeIcon.png';
if (item.entMapIcon) {
iconPath = this.baseUrl + '/' + item.entMapIcon;
}
const markerItem = {
id: markerId,
iconPath: iconPath,
latitude: lat,
longitude: lng,
width: 40,
height: 50,
stationType: 'enterprise',
stationName: item.entName,
entShortName: item.entShortName,
entCharge: item.entCharge,
entCredit: item.entCredit,
entCode: item.entCode,
entIntro: item.entIntro,
entPhone: item.entPhone,
createTime: item.createTime,
entId: item.id,
joinCluster: false,
zIndex: this.markersZIndex++,
enterpriseData: item,
callout: {
content: item.entName || '企业',
color: '#FFFFFF',
fontSize: 14,
borderRadius: 10,
bgColor: '#007AFF',
padding: 8,
display: 'ALWAYS'
}
};
this.markers.push(markerItem);
});
},
markertap(e) {
const index = e.detail.markerId;
const marker = this.markers.find(m => Number(m.id) === Number(index));
if (!marker) {
console.warn('未找到对应的marker, ID:', index);
return;
}
if (marker.stationType === 'enterprise') {
this.currentEnterprise = marker.enterpriseData || {
entName: marker.stationName || '企业名称',
entShortName: marker.entShortName || '',
entCharge: marker.entCharge || '',
entCredit: marker.entCredit || '',
entCode: marker.entCode || '',
entIntro: marker.entIntro || '暂无简介',
entPhone: marker.entPhone || '暂无',
createTime: marker.createTime || ''
};
this.currentMarkerId = marker.id;
this.showEnterprisePopup = true;
return;
}
// 监测站逻辑
if (marker.stationType === 'livestock') {
uni.navigateTo({
url: `/packDetail/pages/Site/detail?item=${encodeURIComponent(JSON.stringify(marker))}`
})
} else if (marker.stationType === 'device') {
uni.navigateTo({
url: `/packDetail/pages/vidio/soilindex`
})
}
},
closePopup() {
this.showEnterprisePopup = false;
this.currentEnterprise = {};
this.currentMarkerId = null;
},
enterpriseRender() {
for (let i = 0; i < this.cusLocationList.length; i++) {
const item = this.cusLocationList[i];
const lat = Number(item.stationLatitude);
const lng = Number(item.stationLongitude);
if (isNaN(lat) || isNaN(lng) || lat === 0 || lng === 0) {
console.warn('企业点位坐标无效:', item.stationName, lat, lng);
continue;
}
const markerItem = {
id: ++this.maxMarkerId,
iconPath: '/static/qiyeIcon.png',
latitude: lat,
longitude: lng,
width: 35,
height: 52,
stationType: item.stationType,
stationName: item.stationName,
stationCode: item.stationCode,
joinCluster: false,
zIndex: this.markersZIndex,
};
this.markers.push(markerItem);
}
},
stationRender() {
if (!this.issscd) {
for (let i = 0; i < this.stationList.length; i++) {
const item = this.stationList[i];
const lat = Number(item.stationLatitude);
const lng = Number(item.stationLongitude);
if (isNaN(lat) || isNaN(lng) || lat === 0 || lng === 0) {
console.warn('站房点位坐标无效:', item.stationName, lat, lng);
continue;
}
const markerItem = {
id: ++this.maxMarkerId,
iconPath: this.baseUrl + '/' + item.stationIcon,
latitude: lat,
longitude: lng,
width: 239,
height: 186,
stationType: item.stationType,
stationName: item.stationName,
stationCode: item.stationCode,
joinCluster: false,
zIndex: this.markersZIndex,
};
this.markers.push(markerItem);
}
}
},
monitorRender() {
this.soilStationList.forEach((item, index) => {
const lat = Number(item.latitude);
const lng = Number(item.longitude);
if (isNaN(lat) || isNaN(lng) || lat === 0 || lng === 0) {
console.warn('监测点位坐标无效:', item.name, lat, lng);
return;
}
let iconPath = '';
let width = 35;
let height = 35;
switch (item.type) {
case 'soil':
iconPath = this.baseUrl + '/icon/device/soil.png';
width = 32;
height = 47;
break;
case 'camera':
iconPath = this.baseUrl + '/icon/device/cam.png';
width = 45;
height = 45;
break;
default:
iconPath = this.baseUrl + '/icon/device/default.png';
}
const markerItem = {
id: ++this.maxMarkerId,
iconPath: iconPath,
latitude: lat,
longitude: lng,
width: width,
height: height,
stationType: 'device',
stationName: item.name,
stationCode: item.ids,
deviceType: item.type,
joinCluster: false,
zIndex: this.markersZIndex,
};
this.markers.push(markerItem);
});
},
ensureAllMarkersVisible() {
if (!this.mapCtx) {
this.mapCtx = uni.createMapContext('map', this);
}
const validPoints = this.markers
.filter(item => {
const lat = Number(item.latitude);
const lng = Number(item.longitude);
return !isNaN(lat) && !isNaN(lng) && lat !== 0 && lng !== 0;
})
.map(item => ({
latitude: Number(item.latitude),
longitude: Number(item.longitude)
}));
if (validPoints.length === 0) {
if (this.center.latitude && this.center.longitude) {
this.mapCtx.moveToLocation({
latitude: this.center.latitude,
longitude: this.center.longitude,
scale: 10
});
}
return;
}
try {
this.mapCtx.includePoints({
points: validPoints,
padding: [120, 120, 120, 120]
});
} catch (e) {
console.error('调整地图视野异常:', e);
this.fallbackAdjustMap(validPoints);
}
},
fallbackAdjustMap(validPoints) {
if (!validPoints || validPoints.length === 0) return;
try {
const lats = validPoints.map(p => p.latitude);
const lngs = validPoints.map(p => p.longitude);
const minLat = Math.min(...lats);
const maxLat = Math.max(...lats);
const minLng = Math.min(...lngs);
const maxLng = Math.max(...lngs);
const centerLat = (minLat + maxLat) / 2;
const centerLng = (minLng + maxLng) / 2;
const latDiff = maxLat - minLat;
const lngDiff = maxLng - minLng;
const maxDiff = Math.max(latDiff, lngDiff);
let scale = 13;
if (maxDiff > 2) scale = 6;
else if (maxDiff > 1) scale = 8;
else if (maxDiff > 0.5) scale = 10;
else if (maxDiff > 0.2) scale = 11;
else if (maxDiff > 0.1) scale = 12;
else scale = 13;
this.mapCtx.moveToLocation({
latitude: centerLat,
longitude: centerLng,
scale: scale
});
} catch (e) {
console.error('备用方案失败:', e);
}
},
switch2Change(name) {
let that = this;
if (name === that.lastTap) {
that.adjustMapToFitAllMarkers();
that.lastTap = '';
} else {
that.adjustMapToRegion(name);
that.lastTap = name;
}
},
adjustMapToFitAllMarkers() {
if (this.mapCtx && this.markers.length > 0) {
this.mapCtx.includePoints({
points: this.markers.map(item => ({
latitude: item.latitude,
longitude: item.longitude
})),
padding: [60, 60, 60, 60]
});
}
},
adjustMapToRegion(regionName) {
let that = this;
let points = [];
let markers = [];
if (regionName === 'enterprise') {
markers = this.markers.filter(item => item.stationType === 'enterprise');
} else if (regionName === 'livestock') {
markers = this.markers.filter(item => item.stationType === regionName);
} else if (regionName === 'soil') {
markers = this.markers.filter(item => item.type === 'soil' || item.deviceType === 'soil');
}
if (markers.length > 0) {
points = markers.map(item => {
item.zIndex = (that.markersZIndex++);
return {
latitude: Number(item.latitude || item.stationLatitude),
longitude: Number(item.longitude || item.stationLongitude)
}
});
}
if (points.length > 0 && this.mapCtx) {
this.mapCtx.includePoints({
points: points,
padding: [80, 110, 80, 110]
});
}
},
}
}
</script>
<style lang="scss">
.bgimg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.customCallout {
width: 349rpx;
height: 49rpx;
color: #fff;
font-size: 24rpx;
text-shadow: 1rpx 2rpx 0rpx #0D1934;
font-weight: bold;
background-repeat: no-repeat;
background-size: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.customCallout1 {
width: 349rpx;
height: 49rpx;
color: #fff;
font-size: 24rpx;
text-shadow: 1rpx 2rpx 0rpx #0D1934;
font-weight: bold;
background-repeat: no-repeat;
background-size: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.zdxq {
position: fixed;
left: 33rpx;
bottom: 36rpx;
}
.zdxqitem {
padding: 8rpx 0 7rpx 17rpx;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 22rpx;
font-family: Source Han Sans SC;
font-weight: 500;
color: #FFFFFF;
text-shadow: 0rpx 1rpx 0rpx rgba(4, 49, 52, 0.55);
width: 240rpx;
background: rgba(0, 0, 0, 0.52);
border: 1px solid #4B677C;
border-radius: 6rpx;
margin-bottom: 10rpx;
position: relative;
}
.crildon {
width: 10rpx;
height: 10rpx;
border-radius: 50%;
margin-right: 15rpx;
}
.zdxqitem:last-child {
margin-bottom: 0;
}
.zdxqitem image {
width: 33rpx;
height: 50rpx;
margin-right: 15rpx;
}
.zdxqitem:first-child image {
width: 30rpx;
height: 40rpx;
margin-right: 15rpx;
}
.textss {
flex: 1;
text-align: left;
}
.imgs {
position: absolute;
width: 100%;
height: 100%;
z-index: -9;
}
.switchs {
position: fixed;
top: 36rpx;
right: 40rpx;
display: flex;
align-items: center;
}
.enterprise-popup {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
}
.popup-content {
width: 600rpx;
max-height: 70vh;
background: #FFFFFF;
border-radius: 20rpx;
overflow: hidden;
display: flex;
flex-direction: column;
}
.popup-header {
padding: 30rpx 30rpx 20rpx;
border-bottom: 1px solid #eee;
display: flex;
justify-content: space-between;
align-items: center;
}
.popup-title {
font-size: 34rpx;
font-weight: bold;
color: #333;
flex: 1;
}
.popup-close {
font-size: 48rpx;
color: #999;
padding: 0 10rpx;
cursor: pointer;
}
.popup-body {
padding: 20rpx 30rpx;
overflow-y: auto;
flex: 1;
}
.info-item {
display: flex;
padding: 12rpx 0;
font-size: 28rpx;
border-bottom: 1px solid #f5f5f5;
}
.info-item .label {
color: #666;
width: 160rpx;
flex-shrink: 0;
}
.info-item .value {
color: #333;
flex: 1;
word-break: break-all;
}
.popup-footer {
padding: 20rpx 30rpx 30rpx;
border-top: 1px solid #eee;
}
.btn-detail {
width: 100%;
height: 80rpx;
line-height: 80rpx;
background: #007AFF;
color: #FFFFFF;
font-size: 30rpx;
border-radius: 40rpx;
border: none;
}
</style>