<!-- 地图 -->
|
<template>
|
<!-- 地图容器 -->
|
<view class="page-container theme-dark">
|
<view id="map" class="map" :prop="setSelectMapLayerKey" :location="location" :change:prop="leaflet.initLayer"
|
:change:location="leaflet.setView"></view>
|
|
<view class="weather-box">
|
<up-icon customPrefix="xyicon" name="tuceng" size="24" color="#000"></up-icon>
|
</view>
|
|
<view class="layer-btn" @click="show = true">
|
<up-icon customPrefix="xyicon" name="tuceng" size="24" color="#000"></up-icon>
|
</view>
|
|
<view class="location-btn" @click="setMapLocation">
|
<up-icon customPrefix="xyicon" name="dingwei" size="24" color="#000"></up-icon>
|
</view>
|
|
<drag-ele>
|
<template #searchBox>
|
<u-input placeholder="搜索" border="surround" v-model="value" @change="change" color="#fff">
|
<template #prefix>
|
<view class="search-left-box">
|
<u-icon color="#fff" name="arrow-left"></u-icon>
|
|
<up-tooltip ref="addressTooltip" text="text5" color="#fff" bgColor="#333" popupBgColor="#333"
|
triggerMode="click" :forcePosition="{right: '0px', top: '0px'}" direction="top">
|
<template #trigger>
|
<up-button iconColor="transparent" color="transparent" :hairline="false" size="mini" :stop="false"
|
type="text">{{ searchModeTextType === 0 ? '地址' : '机巢'}}</up-button>
|
</template>
|
<template #content>
|
<view style="padding: 8rpx 0; text-align: right;">
|
<!-- 按钮1 -->
|
<up-button type="text" size="mini" @click="selectAddress"
|
style="margin: 4rpx 0; width: 100%; text-align: center;">{{ searchModeTextType === 0 ? '机巢' : '地址'}}</up-button>
|
</view>
|
</template>
|
</up-tooltip>
|
</view>
|
</template>
|
|
<template #suffix>
|
<view class="search-right-box">
|
<u-icon color="#fff" name="scan" @click="scanCode"></u-icon>
|
</view>
|
</template>
|
</u-input>
|
|
</template>
|
<template #content>
|
<view class="search-content">
|
|
</view>
|
</template>
|
</drag-ele>
|
|
<up-popup v-model:show="show">
|
<view class="popup-container">
|
<view class="header">
|
<view class="title">图层</view>
|
<view class="close" @click="show = false">
|
<u-icon color="#000" name="close"></u-icon>
|
</view>
|
</view>
|
<view class="content">
|
<view class="layer-box" :class="{on: setSelectMapLayerKey === item.key}" v-for="(item, ind) in layers"
|
:key="ind" @click="setMapLayer(item)">
|
<view class="image">
|
<up-image :src="item.src" width="100%" height="100%"></up-image>
|
</view>
|
<view class="label">{{item.name}}</view>
|
</view>
|
</view>
|
</view>
|
</up-popup>
|
</view>
|
</template>
|
|
<script setup>
|
import DragEle from './drag.vue'
|
import {
|
useMapStore
|
} from "@/store/index.js"
|
|
const mapStore = useMapStore()
|
|
const layers = [{
|
src: "/static/images/sl.png",
|
name: '标准地图',
|
key: 1,
|
},
|
{
|
src: "/static/images/yx.png",
|
name: '卫星地图',
|
key: 2,
|
}
|
]
|
|
const addressTooltip = ref(null)
|
const show = ref(false)
|
|
const value = ref('')
|
|
const change = () => {
|
|
}
|
|
const setSelectMapLayerKey = computed(() => mapStore.getSelectMapLayerKey)
|
const setMapLayer = (item) => {
|
mapStore.setSelectMapLayerKey(item.key)
|
}
|
|
const location = ref('')
|
const setMapLocation = () => {
|
// 获取定位信息
|
uni.getLocation({
|
type: 'wgs84', // 返回的经纬度是 WGS84 坐标系(适合地图定位)
|
isHighAccuracy: true,
|
success: function(res) {
|
location.value = res
|
},
|
fail: function(err) {
|
console.log('定位失败:', err);
|
}
|
});
|
}
|
|
const searchModeTextType = ref(0)
|
|
const selectAddress = () => {
|
searchModeTextType.value = searchModeTextType.value === 0 ? 1 : 0
|
addressTooltip.value.showTooltip = false
|
}
|
|
const scanCode = () => {
|
// 只允许通过相机扫码
|
uni.scanCode({
|
onlyFromCamera: true,
|
success: function(res) {
|
console.log('条码类型:' + res.scanType);
|
console.log('条码内容:' + res.result);
|
|
// 获取扫码结果
|
let url = res.result;
|
|
// 跳转到B页面,并传递URL参数
|
uni.navigateTo({
|
url: '/subPackages/browser/index?url=' + encodeURIComponent(url)
|
});
|
},
|
fail: function(err) {
|
console.log('扫码失败:', err);
|
uni.showToast({
|
title: '扫码失败',
|
icon: 'none'
|
});
|
}
|
});
|
}
|
|
const createWorkOrder = (id) => {
|
console.log(`创建工单:标注 ID 为 ${id}`);
|
// 在这里添加工单创建逻辑
|
}
|
|
onShow(() => {
|
// #ifdef APP-PLUS
|
// plus.screen.lockOrientation("landscape-primary");
|
// #endif
|
});
|
|
onHide(() => {
|
// #ifdef APP-PLUS
|
// plus.screen.lockOrientation("portrait-primary");
|
// #endif
|
});
|
</script>
|
|
<script module="leaflet" lang="renderjs">
|
import L from 'leaflet'
|
|
var basemapLayer0 = L.tileLayer(
|
'http://t1.tianditu.com/vec_c/wmts?layer=vec&style=default&tilematrixset=c&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk=e110584a27d506da2740edca951683f4', {
|
maxZoom: 20,
|
minZoom: 1,
|
tileSize: 256,
|
zoomOffset: 1
|
});
|
var basemapLayer1 = L.tileLayer(
|
'http://t1.tianditu.com/cva_c/wmts?layer=cva&style=default&tilematrixset=c&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk=e110584a27d506da2740edca951683f4', {
|
maxZoom: 20,
|
minZoom: 1,
|
tileSize: 256,
|
zoomOffset: 1
|
});
|
var basemapLayer2 = L.tileLayer(
|
'http://t1.tianditu.com/img_c/wmts?layer=img&style=default&tilematrixset=c&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk=e110584a27d506da2740edca951683f4', {
|
maxZoom: 20,
|
minZoom: 1,
|
tileSize: 256,
|
zoomOffset: 1
|
});
|
var basemapLayer3 = L.tileLayer(
|
'http://t1.tianditu.com/cia_c/wmts?layer=cia&style=default&tilematrixset=c&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk=e110584a27d506da2740edca951683f4', {
|
maxZoom: 20,
|
minZoom: 1,
|
tileSize: 256,
|
zoomOffset: 1
|
});
|
var basemap0 = L.layerGroup([basemapLayer0, basemapLayer1]);
|
var basemap1 = L.layerGroup([basemapLayer2, basemapLayer3]);
|
|
let map = null
|
|
const layers = [{
|
src: "/static/images/sl.png",
|
name: '标准地图',
|
key: 1,
|
map: basemap0
|
},
|
{
|
src: "/static/images/yx.png",
|
name: '卫星地图',
|
key: 2,
|
map: basemap1
|
}
|
]
|
|
export default {
|
data() {
|
return {
|
curSelectMapLayerKey: 1
|
}
|
},
|
|
computed: {
|
|
},
|
|
mounted() {
|
this.initMap()
|
|
this.initDronePositions()
|
},
|
|
methods: {
|
initMap() {
|
if (map) return
|
|
map = L.map('map', {
|
preferCanvas: true,
|
crs: L.CRS.EPSG4326,
|
zoomControl: false,
|
attributionControl: false,
|
doubleClickZoom: false,
|
editable: true //绘制控件
|
}).setView([25.992338, 114.823254], 13);
|
},
|
|
initLayer(value) {
|
this.initMap()
|
|
this.$nextTick(() => {
|
map.removeLayer(layers.find(i => i.key === this.curSelectMapLayerKey).map);
|
|
map.addLayer(layers.find(i => i.key === value).map);
|
|
this.curSelectMapLayerKey = value
|
})
|
},
|
|
setView(res) {
|
if (!res) return
|
|
this.initMap()
|
|
this.$nextTick(() => {
|
map.setView([res.latitude, res.longitude], 16, {
|
animate: false // 使用动画过渡
|
});
|
})
|
},
|
|
// 初始化无人机位置
|
initDronePositions() {
|
// 假设你有一个包含多个标注位置的数组
|
const markersData = [{
|
lat: 25.992338,
|
lng: 114.823254,
|
id: 1
|
},
|
{
|
lat: 26,
|
lng: 114.823255,
|
id: 2
|
},
|
{
|
lat: 25.992338,
|
lng: 115,
|
id: 3
|
},
|
];
|
|
// 创建一个自定义的图片图标
|
const customIcon = L.icon({
|
iconUrl: './static/images/logo.png', // 替换为你的图片路径
|
iconSize: [32, 32], // 图标大小
|
iconAnchor: [16, 16], // 图标的锚点(设置图片的底部中心)
|
});
|
|
// 批量添加标注
|
const markersLayer = L.layerGroup().addTo(map); // 创建一个标注层,便于管理和移除
|
|
markersData.forEach((data) => {
|
const marker = L.marker([data.lat, data.lng], {
|
icon: customIcon
|
}).addTo(markersLayer);
|
|
marker.on('click', () => {
|
marker.unbindPopup();
|
|
const popupContent = `
|
<view>
|
<button data-type="addWork">创建工单</button>
|
</view>
|
`;
|
|
marker.bindPopup(popupContent).openPopup();
|
|
marker.getPopup()._contentNode.addEventListener("click", e => {
|
if (e.target.dataset.type === 'addWork') {
|
// 跳转到tabBar页面
|
uni.switchTab({
|
url: '/pages/work/index', // 需要跳转的tabBar页面的路径
|
});
|
|
marker.closePopup();
|
marker.unbindPopup();
|
}
|
})
|
});
|
|
// 使用 marker 的 id 作为标识符
|
marker.options.id = data.id;
|
});
|
|
this.buildCirclePolygon(25.992338, 114.823254, 'rgba(255, 0, 0, 1)').addTo(map)
|
},
|
|
buildCirclePolygon(lat, lng, color) {
|
var radius = 5000 / 100460; // 5000米转为大约的纬度差(纬度上的1度大约是111km)
|
var parts = [];
|
|
for (var i = 0; i < 360; i++) {
|
var radians = (i + 1) * Math.PI / 180;
|
|
// 计算新的点
|
var circlePoint = [
|
Math.cos(radians) * radius + lat, // 纬度偏移
|
Math.sin(radians) * radius + lng // 经度偏移,需考虑纬度的影响
|
];
|
|
parts[i] = circlePoint;
|
}
|
|
// 生成多边形,近似圆形
|
var polygon = L.polygon(parts, {
|
color: color
|
});
|
|
return polygon;
|
|
}
|
}
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
.page-container {
|
position: relative;
|
width: 100%;
|
height: 100%;
|
|
.u-input {
|
margin-left: 16rpx;
|
width: calc(100% - 32rpx);
|
height: 64rpx;
|
box-sizing: border-box;
|
background: rgba(0, 0, 0, .4);
|
|
.search-left-box {
|
display: flex;
|
align-items: center;
|
color: $u-main-color;
|
}
|
|
.search-right-box {
|
color: $u-main-color;
|
}
|
}
|
|
.search-content {
|
width: 100%;
|
height: 360rpx;
|
background: #fff;
|
box-shadow: 0 -80rpx 80rpx -80rpx #fff;
|
}
|
|
.weather-box {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
position: absolute;
|
top: 16rpx;
|
left: 16rpx;
|
width: 64rpx;
|
height: 64rpx;
|
background: #fff;
|
z-index: 996;
|
border-radius: 8rpx;
|
}
|
|
.location-btn,
|
.layer-btn {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
position: absolute;
|
right: 16rpx;
|
width: 64rpx;
|
height: 64rpx;
|
background: #fff;
|
z-index: 996;
|
border-radius: 8rpx;
|
}
|
|
.layer-btn {
|
bottom: 236rpx;
|
}
|
|
.location-btn {
|
bottom: 156rpx;
|
}
|
}
|
|
/* Leaflet 默认容器要有高度 */
|
.map {
|
width: 100%;
|
height: 100%;
|
}
|
|
.popup-container {
|
padding: 20rpx;
|
background: #D3D3D3;
|
border-radius: 32rpx 32rpx 0 0;
|
|
.header {
|
padding: 0 20rpx;
|
display: flex;
|
justify-content: space-between;
|
height: 56rpx;
|
}
|
|
.content {
|
padding: 20rpx;
|
display: flex;
|
background: #fff;
|
border-radius: 32rpx;
|
|
.layer-box {
|
margin-left: 16rpx;
|
width: calc(100% / 3);
|
|
&:first-child {
|
margin-left: 0;
|
}
|
|
&.on {
|
.image {
|
border: 1px solid #0055ff;
|
}
|
|
.label {
|
color: #0055ff;
|
}
|
}
|
|
.image {
|
width: 100%;
|
height: 96rpx;
|
border-radius: 16rpx;
|
overflow: hidden;
|
box-sizing: border-box;
|
border: 1px solid transparent;
|
}
|
|
.label {
|
line-height: 48rpx;
|
text-align: center;
|
font-size: 16rpx;
|
}
|
}
|
}
|
}
|
</style>
|