<template> <view class="page"> <u-navbar title="地图" :is-back='false' :border-bottom="false" :background="bgc" title-color='#2E4975' title-size='36' height='45'></u-navbar> <view @touchmove.stop.prevent="() => {}"> <view class="slider"> <view class="tit"> 电量区间 </view> <view style="width: 650rpx;margin: 0 auto;"> <slider-range :value="rangeValue" :min="rangeMin" :max="rangMax" :step="1" :bar-height="3" :block-size="20" background-color="#EEEEF6" active-color="#4C97E7" :format="format" :decorationVisible="true" @change="handleRangeChange" @regionchange="onMapRegionChange"></slider-range> </view> </view> </view> <map class="map" id="map" ref="map" :scale="zoomSize" :latitude="latitude" :longitude="longitude" :circles="circles" :show-location="true" :markers="markers" :polygons="polyline" @markertap="onMarkerTap" @regionchange="onMapRegionChange"> <view class="center-marker"> <!-- https://lxnapi.ccttiot.com/bike/img/static/uZdgdHaduvMTKOpMKYxZ --> <image src="https://lxnapi.ccttiot.com/bike/img/static/uZdgdHaduvMTKOpMKYxZ" style="width: 42rpx; height: 78rpx;" v-if="showdevList" /> <!-- <image src="https://lxnapi.ccttiot.com/bike/img/static/uAwnNprackI9p9dXFg8C" style="width: 80rpx; height: 80rpx;" /> --> </view> </map> <view class="park" @click="toggleIconAndCallout"> <image src="https://lxnapi.ccttiot.com/bike/img/static/uRiYQZQEb3l2LsltEsyW" mode=""></image> </view> <view class="park" @click="showdevList=!showdevList" style="bottom: 600rpx;"> <image src="https://lxnapi.ccttiot.com/bike/img/static/uSMkyrHwO1sybH8diPuF" mode=""></image> </view> <view @touchmove.stop.prevent="() => {}"> <view class="btn_box"> <view class="btn1" @click="qecodelock()"> 车辆扫码 </view> <view class="btn2" @click="topage()"> 车辆搜索 </view> </view> <view class="decice_cont"> <!-- <view class="cont" @click="changeidx(0)"> <view class="text" :class="statusidx==0?'act1':''"> 未上架 </view> <view class="text" :class="statusidx==0?'act1':''"> 1 </view> </view> --> <view class="cont" @click="changeidx('-0')"> <view class="text" :class="statusidx=='-0'?'act1':''"> 投放中 </view> <view class="text" :class="statusidx=='-0'?'act1':''"> {{deviceNum.inOperation}} </view> </view> <view class="cont" @click="changeidx('1')"> <view class="text" :class="statusidx==1?'act1':''"> 待租 </view> <view class="text" :class="statusidx==1?'act1':''"> {{deviceNum.normalNum}} </view> </view> <view class="cont" @click="changeidx('2')" style="width: 140rpx;"> <view class="text" :class="statusidx==2?'act1':''"> 预约中 </view> <view class="text" :class="statusidx==2?'act1':''"> {{deviceNum.inAppointmentNum}} </view> </view> <view class="cont" @click="changeidx('3')"> <view class="text" :class="statusidx==3?'act1':''"> 骑行中 </view> <view class="text" :class="statusidx==3?'act1':''"> {{deviceNum.ridingNum}} </view> </view> <view class="cont" @click="changeidx('4')"> <view class="text" :class="statusidx==4?'act1':''"> 临时锁车 </view> <view class="text" :class="statusidx==4?'act1':''"> {{deviceNum.temporarilyLockNum}} </view> </view> <view class="cont" @click="changeidx('8')"> <view class="text" :class="statusidx==8?'act1':''"> 禁用中 </view> <view class="text" :class="statusidx==8?'act1':''"> {{deviceNum.disabledNum}} </view> </view> <view class="cont" @click="changeidx('9')"> <view class="text" :class="statusidx==9?'act1':''"> 离线 </view> <view class="text" :class="statusidx==9?'act1':''"> {{deviceNum.offlineNum}} </view> </view> <view class="cont" @click="changeidx('0')"> <view class="text" :class="statusidx=='0'?'act1':''"> 仓库中 </view> <view class="text" :class="statusidx=='0'?'act1':''"> {{deviceNum.inStashNum}} </view> </view> <view class="cont" @click="changeidx('7')"> <view class="text" :class="statusidx==7?'act1':''"> 全部设备 </view> <view class="text" :class="statusidx==7?'act1':''"> {{deviceNum.allNum}} </view> </view> <view class="cont" @click="changeidx('6')"> <view class="text" :class="statusidx==6?'act1':''"> 调度中 </view> <view class="text" :class="statusidx==6?'act1':''"> {{deviceNum.dispatchNum}} </view> </view> <!-- <view class="cont"> <view class="text"> 调度设备 </view> <view class="text"> 1 </view> </view> --> </view> </view> <view class="fixdivce" v-if="nearbyMarkers.length>1&&showdevList"> <view class="scrollable-content"> <view class="divce_li" v-for="(item,index) in nearbyMarkers" :key="index" @click="tapsn(item.sn)"> <!-- <view class="left_img"> <image src="https://lxnapi.ccttiot.com/bike/img/static/uEW2Zm3sO8E5eqOf2wwl" mode=""></image> </view> --> <view class="right_cont"> <view class="right_top"> <view class="right_top_right"> 牌:{{item.vehicleNum}} </view> <view class="right_top_left"> <image src=" https://lxnapi.ccttiot.com/bike/img/static/u9pggdTCxcZgUTNsEvXQ" mode="" v-if="item.remainingPower<=39"></image> <image src="https://lxnapi.ccttiot.com/bike/img/static/uu1004113wsUShxo11X9" mode="" v-if="item.remainingPower>=40&&item.remainingPower<=69"></image> <image src="https://lxnapi.ccttiot.com/bike/img/static/uRI1LMpzqfIM060BO7np" mode="" v-if="item.remainingPower>=70&&item.remainingPower<=100"></image> {{item.remainingPower}}% </view> </view> <view class="right_bot"> SN:{{item.sn}} <span>{{status(item)}}</span> </view> </view> </view> </view> </view> <tab-bar :indexs='1' style=""></tab-bar> </view> </template> <script> import TabBar from '@/pages_admin/components/tab-bar/tab-bar.vue'; import SliderRange from '@/pages_admin/components/primewind-sliderrange/index.vue' let timerId; var appMap = null; export default { data() { return { bgc: { backgroundColor: "#F7FAFE", }, latitude: 0, longitude: 0, isMap: false, zoomSize: 13, markers: [], polyline: [], polygons: [], fixdata: [], eledata: [], listData: [], infonum: {}, rangeMin: 0, rangMax: 100, rangeValue: [0, 100], status0: [], //未上架 status1: [], //正常 status2: [], //预约中 status3: [], //骑行中 status4: [], //临时锁车 status8: [], //下线 status9: [], //离线 markdata: { }, statusidx: '-0', deviceNum: {}, areaId: 0, showIconAndCallout: false, nearbyMarkers: [], showdevList: false, circles: [], // 用于存储圆形区域的数据 } }, components: { SliderRange,TabBar }, onShow() { this.$store.dispatch('userInfo', this.$u).then(() => { // 执行其他操作... }); // this.getareaid() this.getmarks() this.allVehicleNum() // this.getmarks(); }, onLoad() { if (uni.getStorageSync('adminAreaid')) { this.areaId = uni.getStorageSync('adminAreaid') this.getArea() } let that = this uni.getLocation({ type: 'wgs84', success: function(lb) { // that.latitude = Number(lb.latitude.toFixed(5)) - 0.005 // that.longitude = Number(lb.longitude.toFixed(5)) + 0.005 console.log(that.areaInfo, 'that.areaInfo'); // that.setMapScale() // that.getmarks() // }, fail: function(error) { uni.showToast({ title: '未获取到定位信息,请点击设置勾选允许位置信息,即可使用全部功能', icon: 'none', duration: 2000 }); // that.getmarks() // 在这里处理获取位置信息失败的情况 } }) }, computed: { userId() { return this.$store.getters.userId; }, }, methods: { status(item) { if (item.status == 0) { return '仓库中' } else if (item.status == 1) { return '待租' } else if (item.status == 2) { return '预约中' } else if (item.status == 3) { return '骑行中' } else if (item.status == 4) { return '临时锁车中' } else if (item.status == 6) { return '调度中' } else if (item.status == 7) { return '未绑定' } else if (item.status == 8) { return '禁用中' } }, onMapRegionChange(event) { // console.log('regionchange', event) if (event.detail.type == 'end') { this.getCenterLocation() // this.getCenter() } // 你可以在这里执行你需要的操作 }, getCenterLanLat() { let that = this uni.createMapContext("map", this).getCenterLocation({ type: 'gcj02', success: (res) => { // console.log("当前地图中心的经纬度", res) // that.deviceGps.latitude = res.latitude; // that.deviceGps.longitude = res.longitude; //其他逻辑 }, fail: (err) => {} }) }, getCenterLocation() { const mapContext = uni.createMapContext('map'); mapContext.getCenterLocation({ success: (res) => { console.log('中心点的经纬度:', res.longitude, res.latitude); this.getNearbyMarkers(res.latitude, res.longitude); }, fail: (err) => { console.error('获取中心点定位失败:', err); } }); }, getCenter: function() { var _that = this; appMap.getCurrentCenter( function(state, point) { if (0 == state) { // 反编码 var point = new plus.maps.Point(point["longitude"], point["latitude"]); plus.maps.Map.reverseGeocode(point, {}, function(event) { var address = event.address; // 转换后的地理位置 var coord = event.coord; // 转换后的坐标信息 var coordType = event.coordType; // 转换后的坐标系类型 console.log("Address:" + address); console.log("coord", coord); uni.showModal({ title: "提示", content: "确定:" + address + "?", success: function(res) { if (res.confirm) { // 业务逻辑... } else if (res.cancel) {} } }) }, function(e) { // console.log("Failed:" + JSON.stringify(e)); uni.showToast({ title: '反编码失败' + JSON.stringify(e) }); }); } else { uni.showToast({ icon: "none", title: "获取经纬度失败!" + state }) } } ); }, getNearbyMarkers(clickedLat, clickedLon) { // console.log(clickedLat, clickedLon); // 只有在 showdevList 为 true 的时候才显示圆形区域 if (this.showdevList) { const nearbyMarkers = this.listData.filter(item => { if (item.latitude && item.longitude) { const distance = this.haversineDistance( parseFloat(clickedLat), parseFloat(clickedLon), parseFloat(item.latitude), parseFloat(item.longitude) ); return distance <= 100; } return false; }); // 更新 circles 数组来绘制淡灰色的圆形区域 this.circles = [{ latitude: clickedLat, longitude: clickedLon, color: '#fff', // 圆形边框颜色(淡灰色) fillColor: '#00000010', // 圆形填充颜色(淡灰色) radius: 100, // 圆的半径(单位:米) strokeWidth: 1 }]; this.nearbyMarkers = nearbyMarkers; // console.log('Nearby markers within 100 meters:', nearbyMarkers); } else { // 当 showdevList 为 false 时,清空 circles 数组 this.circles = []; } }, haversineDistance(lat1, lon1, lat2, lon2) { const R = 6371e3; // Earth radius in meters const toRad = angle => angle * Math.PI / 180; const dLat = toRad(lat2 - lat1); const dLon = toRad(lon2 - lon1); const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return R * c; }, getareaid() { this.$u.post('/appVerify/getAreaId').then((res) => { if (res.code == 200) { // 处理接口返回的数据,将边界数据转换为地图组件需要的折线结构 // this.areaId=res.data // console.log(this.polyline); } else { this.areaId = 14 this.getArea() this.allVehicleNum() } }).catch(error => { }); }, async setMapScale(e, val) { let mapContext = uni.createMapContext('map', this); let setScale = () => { return new Promise((resolve, reject) => { mapContext.getScale({ success: r => { resolve() } }) }) }; await setScale(); mapContext.moveToLocation({ success: (res) => { const timer = setTimeout(() => { clearTimeout(timer); }, 500); }, }) }, tapsn(sn) { uni.navigateTo({ url: '/pages_admin/order/device_detail?id=' + sn }) }, qecodelock() { uni.scanCode({ onlyFromCamera: true, scanType: ['qrCode'], success: res => { let sn = null; let queryParams = res.result.split('?')[1]; if (queryParams) { let params = queryParams.split('&'); params.forEach(param => { let [key, value] = param.split('='); if (key === 'sn') { sn = value; } }); } this.sn = sn if (this.sn != '') { this.$u.get('/app/device/info?sn=' + this.sn).then((res) => { console.log(res, 'rererer'); if (res.code === 200) { // console.log(this.areaId,); if (res.data.areaId == this.areaId) { uni.navigateTo({ url: '/pages_admin/order/device_detail?id=' + this .sn }) } else { uni.showToast({ title: '无效车辆', icon: 'none', duration: 2000 }); } } else { uni.showToast({ title: res.msg, icon: 'none', duration: 2000 }); } }) } }, fail: err => { console.error('扫描失败:', err); uni.showToast({ title: '扫描失败', icon: 'none' }); } }); }, topage() { uni.navigateTo({ url: '/pages_admin/order/search_device' }) }, allVehicleNum() { let data = { powerStart: this.rangeValue[0], powerEnd: this.rangeValue[1], areaId: this.areaId } this.$u.get('/appVerify/allVehicleNum?', data).then((res) => { if (res.code === 200) { // 处理接口返回的数据,将边界数据转换为地图组件需要的折线结构 this.deviceNum = res.data // console.log(this.polyline); } }).catch(error => { console.error("Error fetching area data:", error); }); }, changeidx(ids) { this.statusidx = ids this.getmarks() }, format(val) { return val + '%' }, handleRangeChange(e) { // 每次滑动时清除之前的定时器 clearTimeout(timerId); // 设置一个新的定时器,在滑动停止后 500ms 执行 getmarks 方法 timerId = setTimeout(() => { this.rangeValue = e; this.getmarks(); }, 500); }, onMarkerTap(e) { if (e.type === 'markertap') { console.log('点击了标记:', e.markerId); // 这里可以根据需要处理点击标记的逻辑 // 阻止事件冒泡 this.sn = e.markerId for (let i = 0; i < this.listData.length; i++) { if (this.listData[i].sn == this.sn) { uni.navigateTo({ url: '/pages_admin/order/device_detail?id=' + this.sn }) } } // this.listData } }, todetail() { for (let item of this.fixdata) { if (item.sn == this.sn) { uni.navigateTo({ url: '/page_fix/repair/repair_detail?id=' + item.id }) } } for (let item of this.eledata) { if (item.sn == this.sn) { uni.navigateTo({ url: '/page_fix/repair/repair_detail?id=' + item.id }) } } }, getArea() { let id = this.areaId this.$u.get("/app/area/" + id).then((res) => { if (res.code == 200) { this.latitude = res.data.latitude this.longitude = res.data.longitude // this.areaInfo = res.data const polylines = this.convertBoundaryToPolyline(res.data.boundaryStr) this.polyline.push(polylines) setTimeout(() => { this.getParking() }, 500) } else { uni.showToast({ title: res.msg, icon: 'none', duration: 2000 }); } }); }, convertBoundaryToPolylines(boundaries, num) { const colorMap = { 1: { fillColor: "#3A7EDB10", strokeColor: "#3A7EDB" }, 2: { fillColor: "#FFF5D640", strokeColor: "#FFC107" }, 3: { fillColor: "#FFD1CF40", strokeColor: "#FF473E" } }; if (!colorMap[num]) { console.error("Invalid type number:", num); return []; } return boundaries.map(boundary => { if (!boundary) return null; let coords; try { coords = JSON.parse(boundary); } catch (error) { console.error("Error parsing boundary JSON:", error); return null; } if (!Array.isArray(coords)) { console.error("Parsed boundary is not an array:", coords); return null; } const points = coords.map(coord => ({ latitude: parseFloat(coord[1]), longitude: parseFloat(coord[0]) })); return { points: points, fillColor: colorMap[num].fillColor, strokeColor: colorMap[num].strokeColor, strokeWidth: 2, //描边宽度 zIndex: 1, //层级 }; }).filter(polyline => polyline !== null); // 过滤掉无效的折线数据 }, markstause() { // console.log(this.status9, 'aaaaaaa'); this.status0.forEach(item => { this.markers.push({ id: parseFloat(item.sn), latitude: parseFloat(item.latitude), longitude: parseFloat(item.longitude), // title: item.deviceName, width: 30, height: 34, // iconPath: 'https://lxnapi.ccttiot.com/bike/img/static/u6jBvj7S50FPgsHaHXai', iconPath: item.onlineStatus == 0 ? 'https://lxnapi.ccttiot.com/bike/img/static/uQRng4QNKA38Amk8Wgt5' : 'https://lxnapi.ccttiot.com/bike/img/static/uocjFo8Ar2BJVpzC2G2f', callout: { content: '' + item.remainingPower + '%', // 修改为你想要显示的文字内容 color: '#ffffff', // 修改为文字颜色 fontSize: 10, // 修改为文字大小 borderRadius: 10, // 修改为气泡圆角大小 bgColor: '#000000', // 修改为气泡背景颜色 padding: 1, // 修改为气泡内边距 display: 'ALWAYS', // 修改为气泡的显示策略 } }) }) // https://lxnapi.ccttiot.com/bike/img/static/u1UD93BU1vfshWFoDwgX // https://lxnapi.ccttiot.com/bike/img/static/u4UKmB47AxOj3YKIaajM this.status1.forEach(item => { this.markers.push({ id: parseFloat(item.sn), latitude: parseFloat(item.latitude), longitude: parseFloat(item.longitude), // title: item.deviceName, width: 30, // joinCluster: true, height: 34, iconPath: item.onlineStatus == 0 ? 'https://lxnapi.ccttiot.com/bike/img/static/uzhMeExOQJbMcZtrfGUV' : 'https://lxnapi.ccttiot.com/bike/img/static/uheL17wVZn24BwCwEztT', // iconPath: 'https://lxnapi.ccttiot.com/bike/img/static/uAajBTcihvOr9HttyWck', callout: { content: '' + item.remainingPower + '%', // 修改为你想要显示的文字内容 color: '#2679D1', // 修改为文字颜色 fontSize: 10, // 修改为文字大小 borderRadius: 10, // 修改为气泡圆角大小 bgColor: '#D4ECFF', // 修改为气泡背景颜色 padding: 1, // 修改为气泡内边距 display: 'ALWAYS', // 修改为气泡的显示策略 } }) }) this.status2.forEach(item => { this.markers.push({ id: parseFloat(item.sn), latitude: parseFloat(item.latitude), longitude: parseFloat(item.longitude), // title: item.deviceName, width: 30, height: 34, iconPath: item.onlineStatus == 0 ? 'https://lxnapi.ccttiot.com/bike/img/static/uR3DQEssiK62ovhh88y8' : 'https://lxnapi.ccttiot.com/bike/img/static/u460R1NKWHEpHbt0U4H7', // iconPath: 'https://lxnapi.ccttiot.com/bike/img/static/um0qXpcbA32WdwqtHbxy', callout: { content: '' + item.remainingPower + '%', // 修改为你想要显示的文字内容 color: '#2679D1', // 修改为文字颜色 fontSize: 10, // 修改为文字大小 borderRadius: 10, // 修改为气泡圆角大小 bgColor: '#D4ECFF', // 修改为气泡背景颜色 padding: 1, // 修改为气泡内边距 display: 'ALWAYS', // 修改为气泡的显示策略 } }) }) this.status3.forEach(item => { this.markers.push({ id: parseFloat(item.sn), latitude: parseFloat(item.latitude), longitude: parseFloat(item.longitude), // title: item.deviceName, width: 30, height: 34, // joinCluster: true, iconPath: item.onlineStatus == 0 ? 'https://lxnapi.ccttiot.com/bike/img/static/uG13E7BpUFF44wVYC9no' : 'https://lxnapi.ccttiot.com/bike/img/static/uHQIdWCTmtUztl49wBKU', // iconPath: 'https://lxnapi.ccttiot.com/bike/img/static/ur1ZrncDJ1WwuPJeiMG6', callout: { content: '' + item.remainingPower + '%', // 修改为你想要显示的文字内容 color: '#2679D1', // 修改为文字颜色 fontSize: 10, // 修改为文字大小 borderRadius: 10, // 修改为气泡圆角大小 bgColor: '#D4ECFF', // 修改为气泡背景颜色 padding: 1, // 修改为气泡内边距 display: 'ALWAYS', // 修改为气泡的显示策略 } }) }) this.status4.forEach(item => { this.markers.push({ id: parseFloat(item.sn), latitude: parseFloat(item.latitude), longitude: parseFloat(item.longitude), // title: item.deviceName, width: 30, height: 34, // joinCluster: true, iconPath: item.onlineStatus == 0 ? 'https://lxnapi.ccttiot.com/bike/img/static/uRod2zf3t9dAOYafWoWt' : 'https://lxnapi.ccttiot.com/bike/img/static/uZpXq3TBtM5gVgJJeImY', // iconPath: 'https://lxnapi.ccttiot.com/bike/img/static/uN4ksL0Z2HM4C07fKEOF', callout: { content: '' + item.remainingPower + '%', // 修改为你想要显示的文字内容 color: '#2679D1', // 修改为文字颜色 fontSize: 10, // 修改为文字大小 borderRadius: 10, // 修改为气泡圆角大小 bgColor: '#D4ECFF', // 修改为气泡背景颜色 padding: 1, // 修改为气泡内边距 display: 'ALWAYS', // 修改为气泡的显示策略 } }) }) this.status6.forEach(item => { this.markers.push({ id: parseFloat(item.sn), latitude: parseFloat(item.latitude), longitude: parseFloat(item.longitude), // title: item.deviceName, width: 30, height: 34, // joinCluster: true, iconPath: item.onlineStatus == 0 ? 'https://lxnapi.ccttiot.com/bike/img/static/uhZudZM3nEKj0tYKlho2' : 'https://lxnapi.ccttiot.com/bike/img/static/ujur6TezvPf4buFAqPHo', // iconPath: 'https://lxnapi.ccttiot.com/bike/img/static/uxbI6ZclpS3WQCfPO1zr', callout: { content: '' + item.remainingPower + '%', // 修改为你想要显示的文字内容 color: '#2679D1', // 修改为文字颜色 fontSize: 10, // 修改为文字大小 borderRadius: 10, // 修改为气泡圆角大小 bgColor: '#D4ECFF', // 修改为气泡背景颜色 padding: 1, // 修改为气泡内边距 display: 'ALWAYS', // 修改为气泡的显示策略 } }) }) this.status8.forEach(item => { this.markers.push({ id: parseFloat(item.sn), latitude: parseFloat(item.latitude), longitude: parseFloat(item.longitude), // title: item.deviceName, width: 30, height: 34, iconPath: item.onlineStatus == 0 ? 'https://lxnapi.ccttiot.com/bike/img/static/ucBKG3ebYRAToVweJihu' : 'https://lxnapi.ccttiot.com/bike/img/static/uyK7Vg4Lu8xb3oNVuG2l', // iconPath: 'https://lxnapi.ccttiot.com/bike/img/static/uYIFwg5IJ4Axh7TfJ7q6', callout: { content: '' + item.remainingPower + '%', // 修改为你想要显示的文字内容 color: '#ffffff', // 修改为文字颜色 fontSize: 10, // 修改为文字大小 borderRadius: 10, // 修改为气泡圆角大小 bgColor: '#000000', // 修改为气泡背景颜色 padding: 1, // 修改为气泡内边距 display: 'ALWAYS', // 修改为气泡的显示策略 } }) }) // this.status9.forEach(item => { // this.markers.push({ // id: parseFloat(item.sn), // latitude: parseFloat(item.latitude), // longitude: parseFloat(item.longitude), // // title: item.deviceName, // width: 40, // height: 40, // iconPath: 'https://lxnapi.ccttiot.com/bike/img/static/u4UKmB47AxOj3YKIaajM', // callout: { // content: '离线', // 修改为你想要显示的文字内容 // color: '#ffffff', // 修改为文字颜色 // fontSize: 14, // 修改为文字大小 // borderRadius: 10, // 修改为气泡圆角大小 // bgColor: '#000000', // 修改为气泡背景颜色 // padding: 6, // 修改为气泡内边距 // display: 'ALWAYS', // 修改为气泡的显示策略 // } // }) // }) }, getmarks() { this.markers = []; this.status0 = []; this.status1 = []; this.status2 = []; this.status3 = []; this.status4 = []; this.status8 = []; this.status9 = []; this.status6 = []; let data = { powerStart: this.rangeValue[0], powerEnd: this.rangeValue[1], sort: 'desc', areaId: this.areaId }; if (this.statusidx != 7 && this.statusidx != 9) { data.status = this.statusidx; this.$u.get(`/appVerify/allVehicleInfo?`, data).then((res) => { if (res.code == 200) { this.showmap = true; this.listData = res.data; res.data.forEach(item => { // if (item.onlineStatus == 0) { // this.status9.push(item); // } else { // } if (item.status == 0) { this.status0.push(item); } else if (item.status == 1) { this.status1.push(item); } else if (item.status == 2) { this.status2.push(item); } else if (item.status == 3) { this.status3.push(item); } else if (item.status == 4) { this.status4.push(item); } else if (item.status == 6) { this.status6.push(item); } else if (item.status == 8) { this.status8.push(item); } // console.log(this.status1,'status1status1'); }); this.markstause(); } else { // Handle API error } }).catch(error => { // Handle request error }); } else if (this.statusidx == 7) { data.status = ''; this.$u.get(`/appVerify/allVehicleInfo?`, data).then((res) => { if (res.code == 200) { this.showmap = true; this.listData = res.data; res.data.forEach(item => { if (item.status == 0) { this.status0.push(item); } else if (item.status == 1) { this.status1.push(item); } else if (item.status == 2) { this.status2.push(item); } else if (item.status == 3) { this.status3.push(item); } else if (item.status == 4) { this.status4.push(item); } else if (item.status == 6) { this.status6.push(item); } else if (item.status == 8) { this.status8.push(item); } }); this.markstause(); } else { // Handle API error } }).catch(error => { // Handle request error }); } else if (this.statusidx == 9) { data.status = '-0' data.onlineStatus = 0 this.$u.get(`/appVerify/allVehicleInfo?`, data).then((res) => { if (res.code == 200) { this.showmap = true; this.listData = res.data; res.data.forEach(item => { if (item.status == 0) { this.status0.push(item); } else if (item.status == 1) { this.status1.push(item); } else if (item.status == 2) { this.status2.push(item); } else if (item.status == 3) { this.status3.push(item); } else if (item.status == 4) { this.status4.push(item); } else if (item.status == 6) { this.status6.push(item); } else if (item.status == 8) { this.status8.push(item); } }); this.markstause(); } else { // Handle API error } }).catch(error => { // Handle request error }); } this.clusterMarkers(); // 调用聚合方法 }, clusterMarkers() { this.markers.forEach(marker => { let added = false; for (let i = 0; i < this.clusters.length; i++) { const cluster = this.clusters[i]; const distance = this.calculateDistance(cluster.latitude, cluster.longitude, marker .latitude, marker.longitude); if (distance < this.clusterRadius) { // 合并到现有聚合 cluster.markers.push(marker); cluster.latitude = (cluster.latitude * cluster.markers.length + marker.latitude) / ( cluster.markers.length + 1); cluster.longitude = (cluster.longitude * cluster.markers.length + marker.longitude) / ( cluster.markers.length + 1); added = true; break; } } if (!added) { // 创建新的聚合 this.clusters.push({ latitude: marker.latitude, longitude: marker.longitude, markers: [marker] }); } }); }, // 计算两点间的距离 calculateDistance(lat1, lon1, lat2, lon2) { const p = 0.017453292519943295; // Math.PI / 180 const c = Math.cos; const a = 0.5 - c((lat2 - lat1) * p) / 2 + c(lat1 * p) * c(lat2 * p) * (1 - c((lon2 - lon1) * p)) / 2; return 12742 * Math.asin(Math.sqrt(a)); // 2 * R; R = 6371 km }, toggleIconAndCallout() { this.showIconAndCallout = !this.showIconAndCallout; this.markers.forEach(marker => { if (marker.isParking) { marker.callout.display = this.showIconAndCallout ? 'ALWAYS' : 'BYCLICK'; } }); }, getParking() { let data = { areaId: this.areaId }; this.$u.get('/app/parking/list?', data).then((res) => { if (res.code === 200) { const newMarkers = []; const type1Data = []; const type2Data = []; const type3Data = []; res.rows.forEach(row => { if (row.type == 1) { type1Data.push(row); } else if (row.type == 2) { type2Data.push(row); } else if (row.type == 3) { type3Data.push(row); } newMarkers.push({ id: parseFloat(row.parkingId), latitude: parseFloat(row.latitude), longitude: parseFloat(row.longitude), width: 20, height: 29, iconPath: row.type == 1 ? 'https://lxnapi.ccttiot.com/bike/img/static/up2xXqAgwCX5iER600k3' : row.type == 2 ? 'https://lxnapi.ccttiot.com/bike/img/static/u53BAQcFIX3vxsCzEZ7t' : 'https://lxnapi.ccttiot.com/bike/img/static/uDNY5Q4zOiZTCBTA2Jdq', callout: { content: row.parkingName, color: '#ffffff', fontSize: 14, borderRadius: 10, bgColor: row.type == 1 ? '#3A7EDB' : row.type == 2 ? '#FFC107' : '#FF473E', padding: 6, display: 'BYCLICK' }, isParking: true }); }); this.$set(this, 'markers', [...this.markers, ...newMarkers]); const validBoundaries1 = type1Data.map(row => row.boundaryStr).filter(boundary => typeof boundary === 'string' && boundary.trim() !== ''); const polylines1 = this.convertBoundaryToPolylines(validBoundaries1, 1); const validBoundaries2 = type2Data.map(row => row.boundaryStr).filter(boundary => typeof boundary === 'string' && boundary.trim() !== ''); const polylines2 = this.convertBoundaryToPolylines(validBoundaries2, 2); const validBoundaries3 = type3Data.map(row => row.boundaryStr).filter(boundary => typeof boundary === 'string' && boundary.trim() !== ''); const polylines3 = this.convertBoundaryToPolylines(validBoundaries3, 3); this.polyline = this.polyline.concat(polylines1, polylines2, polylines3); } else { console.error("Error fetching parking data:", res); } }).catch(error => { console.error("Error fetching parking data:", error); }); }, convertBoundaryToPolyline(boundary) { if (!boundary) return null; const points = JSON.parse(boundary).map(coord => ({ latitude: coord[1], longitude: coord[0] })); const polyline = { points: points, fillColor: "#55888840", //填充颜色 strokeColor: "#22FF00", //描边颜色 strokeWidth: 2, //描边宽度 zIndex: 1, //层级 }; return polyline; }, } } </script> <style lang="scss"> page { background-color: #fff; } .page { width: 750rpx; .center-marker { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -80%); /* 定位在中心点上方 */ pointer-events: none; /* 使其不可点击 */ } .fixdivce { padding: 12rpx 22rpx 12rpx 22rpx; position: fixed; left: 0; top: 25vh; width: 280rpx; height: 40vh; background: #FFFFFF80; border-radius: 0 40rpx 40rpx 0; box-shadow: 0rpx 4rpx 10rpx 0rpx rgba(0, 0, 0, 0.3); .scrollable-content::-webkit-scrollbar { display: none; } .scrollable-content { height: 100%; overflow-y: auto; .divce_li:last-child { border-bottom: 1rpx solid #fff; } .divce_li { padding: 10rpx 0; display: flex; flex-wrap: nowrap; align-items: center; border-bottom: 1rpx solid #D8D8D8; .left_img { image { width: 44rpx; height: 70rpx; } } .right_cont { margin-left: 20rpx; display: flex; flex-wrap: wrap; font-weight: 400; font-size: 24rpx; color: #3D3D3D; .right_top { width: 100%; display: flex; flex-wrap: nowrap; align-items: center; .right_top_left { margin-left: auto; display: flex; flex-wrap: nowrap; align-items: center; image { margin-right: 6rpx; width: 12rpx; height: 26rpx; } } .right_top_right {} } .right_bot { width: 100%; display: flex; flex-wrap: nowrap; justify-content: space-between; margin-top: 8rpx; } } } } } .decice_cont { display: flex; flex-wrap: wrap; align-items: center; padding: 10rpx 28rpx; .cont:nth-child(5n) { margin-right: 0; } .cont { margin-top: 8rpx; margin-right: 9rpx; // display: flex; width: 130rpx; .text { width: 100%; text-align: center; font-weight: 500; font-size: 24rpx; line-height: 38rpx; color: #3D3D3D; } .act1 { color: #4C97E7; } } } .park { position: fixed; display: flex; align-items: center; justify-content: center; right: 30rpx; bottom: 500rpx; // background-color: #fff; border-radius: 50%; width: 82rpx; height: 82rpx; z-index: 10; .img { width: 82rpx; height: 82rpx; } } .btn_box { width: 100%; display: flex; flex-wrap: nowrap; .btn1 { display: flex; align-items: center; justify-content: center; width: 376rpx; height: 74rpx; background: #D4ECFF; font-weight: 500; font-size: 40rpx; color: #4C97E7; } .btn2 { display: flex; align-items: center; justify-content: center; width: 374rpx; height: 74rpx; background: #4C97E7; font-weight: 500; font-size: 40rpx; color: #FFFFFF; } } .slider { padding: 15rpx 0 0 15rpx; margin-bottom: 20rpx; .tit { font-weight: 500; font-size: 28rpx; color: #3D3D3D; } width: 752rpx; height:160rpx; background: #FFFFFF; // box-shadow: 0rpx 4rpx 22rpx 0rpx rgba(0, 0, 0, 0.07); border-radius: 0rpx 0rpx 0rpx 0rpx; } .map { width: 750rpx; height: 50vh; } } </style>