FenXiNspUniapp/pages/maps/index.vue

787 lines
19 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="filteredMarkers"
:longitude="center.longitude" :latitude="center.latitude" show-location show-compass show-scale
@markertap="markertap">
</map>
<view class="zdxq">
<view class="zdxqitem" :class="{ active: activeType === 'livestock' }" @click="switch2Change('livestock')">
<image src="../../static/zhandian_xuqin_dingwei.png" mode=""></image>
<view class="textss">
畜禽污染监测站
</view>
</view>
<view class="zdxqitem" :class="{ active: activeType === 'orient' }" @click="switch2Change('orient')">
<image src="../../static/zhandian_nongtian_dingwei.png" mode=""></image>
<view class="textss">
农田污染监测站
</view>
</view>
<!-- 企业点位 -->
<view class="zdxqitem" :class="{ active: activeType === 'enterprise' }" @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" v-if="enterprisePics.length > 0">
<text class="label">企业照片:</text>
<view class="pic-list">
<image
v-for="(pic, index) in enterprisePics"
:key="index"
class="pic-item"
:src="pic"
mode="widthFix"
@click="previewImage(index)"
></image>
</view>
</view>
<view class="info-item">
<text class="label">企业简介:</text>
<text class="value">{{ currentEnterprise.entIntro || '暂无简介' }}</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: 35.604,
longitude: 110.983
},
mapScale: 13,
markers: [],
markersZIndex: 1,
lastTap: '',
stationList: [],
cusLocationList: [],
soilStationList: [],
allStationList: [],
stationTwoList: [],
mapCtx: null,
// 企业相关
enterpriseList: [],
showEnterprisePopup: false,
currentEnterprise: {},
currentMarkerId: null,
maxMarkerId: 0,
// 当前筛选类型:'' 表示显示全部
activeType: '',
hasLoaded: false
};
},
computed: {
// 根据 activeType 过滤要显示的 marker
filteredMarkers() {
if (!this.activeType) {
return this.markers;
}
return this.markers.filter(item => item.stationType === this.activeType);
},
// 企业照片列表
enterprisePics() {
const raw = this.currentEnterprise.entPics || '';
if (!raw) return [];
return raw.split(',').map(p => p.trim()).filter(p => p).map(p => {
if (/^https?:\/\//.test(p)) return p;
return this.baseUrl.replace(/\/$/, '') + '/' + p.replace(/^\//, '');
});
}
},
onLoad() {},
onReady() {
this.mapCtx = uni.createMapContext('map', this);
},
onShow() {
api.checkLogin(() => {
if (this.hasLoaded) return // 已经加载过,不再重复请求
this.$nextTick(() => {
this.getList()
this.hasLoaded = true
})
}, () => {
uni.reLaunch({
url: '/packDetail/pages/login/login'
})
})
},
methods: {
getList() {
this.markers = []
this.stationList = []
this.cusLocationList = []
this.soilStationList = []
this.allStationList = []
this.stationTwoList = []
this.enterpriseList = []
this.maxMarkerId = 0
this.activeType = ''
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
// 记录已用的最大 id避免与企业 marker 冲突
this.maxMarkerId = this.allStationList.length + 1;
// 渲染所有标记
this.stationRender();
this.monitorRender();
this.enterpriseRender();
// 使用增强的视野调整方法
this.ensureAllMarkersVisible();
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);
})
},
previewImage(index) {
const urls = this.enterprisePics;
const current = urls[index];
uni.previewImage({
urls: urls,
current: current,
indicator: 'default',
loop: true
});
},
// 渲染企业标记(自动过滤掉无有效坐标的企业)
renderEnterpriseMarkers() {
if (!this.enterpriseList || this.enterpriseList.length === 0) {
console.warn('企业列表为空');
return;
}
// 过滤出有有效坐标的企业
const validEnterpriseList = this.enterpriseList.filter((item) => {
const lat = Number(item.entLat);
const lng = Number(item.entLong);
return !isNaN(lat) && !isNaN(lng) && lat !== 0 && lng !== 0;
});
const invalidCount = this.enterpriseList.length - validEnterpriseList.length;
if (invalidCount > 0) {
console.log(`已过滤 ${invalidCount} 个缺少坐标的企业`);
}
validEnterpriseList.forEach((item) => {
const lat = Number(item.entLat);
const lng = Number(item.entLong);
const markerId = ++this.maxMarkerId;
let iconPath = '/static/qiyebzIcon.png';
if (item.entMapIcon) {
iconPath = this.baseUrl.replace(/\/$/, '') + '/' + item.entMapIcon.replace(/^\//, '');
}
const markerItem = {
id: markerId,
iconPath: iconPath,
latitude: lat,
longitude: lng,
width: 20,
height: 25,
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: 1,
enterpriseData: item,
callout: {
content: item.entName || '企业',
color: '#FFFFFF',
fontSize: 12,
borderRadius: 10,
bgColor: '#007AFF',
padding: 4,
display: 'ALWAYS'
}
};
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) {
console.warn('没有有效的坐标点');
if (this.center.latitude && this.center.longitude) {
this.mapCtx.moveToLocation({
latitude: this.center.latitude,
longitude: this.center.longitude,
scale: 10
});
}
return;
}
console.log('有效坐标点数量:', validPoints.length);
try {
this.mapCtx.includePoints({
points: validPoints,
padding: [120, 120, 120, 120],
success: () => {
console.log('地图视野调整成功');
},
fail: (err) => {
console.error('includePoints失败:', err);
this.fallbackAdjustMap(validPoints);
}
});
} catch (e) {
console.error('调整地图视野异常:', e);
this.fallbackAdjustMap(validPoints);
}
setTimeout(() => {
if (this.mapCtx) {
try {
this.mapCtx.includePoints({
points: validPoints,
padding: [150, 150, 150, 150]
});
} catch (e) {
console.error('第二次调整失败:', e);
}
}
}, 500);
setTimeout(() => {
if (this.mapCtx) {
try {
this.mapCtx.includePoints({
points: validPoints,
padding: [180, 160, 160, 160]
});
} catch (e) {
console.error('第三次调整失败:', e);
}
}
}, 1000);
},
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;
console.log('备用方案 - 中心点:', centerLat, centerLng, '缩放:', scale);
this.mapCtx.moveToLocation({
latitude: centerLat,
longitude: centerLng,
scale: scale
});
} catch (e) {
console.error('备用方案失败:', e);
}
},
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: item.id || `enterprise_${i}`,
iconPath: '/static/qiyeIcon.png',
latitude: lat,
longitude: lng,
width: 17,
height: 26,
customCallout: {
anchorY: 0,
anchorX: 0,
display: 'ALWAYS'
},
stationType: item.stationType,
stationName: item.stationName,
stationCode: item.stationCode,
joinCluster: false,
zIndex: 1,
};
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: item.id || `station_${i}`,
iconPath: this.baseUrl + '/' + item.stationIcon,
latitude: lat,
longitude: lng,
width: 239,
height: 186,
customCallout: {
anchorY: 0,
anchorX: 0,
display: 'ALWAYS'
},
stationType: item.stationType,
stationName: item.stationName,
stationCode: item.stationCode,
joinCluster: false,
zIndex: 100,
};
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: item.id || `device_${index}`,
iconPath: iconPath,
latitude: lat,
longitude: lng,
width: width,
height: height,
customCallout: {
anchorY: 0,
anchorX: 0,
display: 'ALWAYS'
},
stationType: 'device',
stationName: item.name,
stationCode: item.ids,
deviceType: item.type,
joinCluster: false,
zIndex: 20,
};
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 (['orient', 'livestock'].includes(marker.stationType)) {
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;
},
// 图例点击:只显示对应类型,再点一次恢复全部
switch2Change(name) {
if (this.activeType === name) {
// 再次点击 → 取消过滤,显示全部
this.activeType = '';
} else {
// 点击其他 → 只显示该类型
this.activeType = name;
}
// 视野聚焦到当前显示的 marker
this.$nextTick(() => {
this.adjustMapToVisibleMarkers();
});
},
// 根据当前显示的 marker 调整视野
adjustMapToVisibleMarkers() {
const list = this.filteredMarkers;
if (!list || list.length === 0) {
return;
}
const points = list
.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 (points.length === 0 || !this.mapCtx) return;
this.mapCtx.includePoints({
points: points,
padding: [100, 100, 100, 100]
});
}
}
}
</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;
transition: all 0.2s ease;
}
/* 选中高亮 */
.zdxqitem.active {
background: rgba(0, 122, 255, 0.75);
border-color: #007AFF;
box-shadow: 0 0 12rpx rgba(0, 122, 255, 0.6);
}
.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;
}
.pic-item {
width: 380rpx;
height: auto;
border-radius: 8rpx;
}
</style>