光伏-机器人远程管控系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

188 lines
5.3 KiB

<template>
<div style="position: relative; height: 100%; width: 100%; overflow: hidden">
<div id="map" style="height: 100%; width: 100%; overflow: hidden"></div>
<div v-if="darkMask" class="dark-mask"></div>
</div>
</template>
<script>
import AMapLoader from '@amap/amap-jsapi-loader';
/**
* props.rectangles: Array<{ id, name, status, geomWkt }>
* - geomWkt: "POLYGON((lng lat,lng lat,...))"
* - status: 施工中 | 已施工 | 未施工 | 故障 | 运行中 | 停机
*/
const STATUS_STYLE = {
施工中: { stroke: 'rgba(41,169,253,1)', fill: 'rgba(41,169,253,0.45)' },
已施工: { stroke: 'rgba(82,196,26,1)', fill: 'rgba(82,196,26,0.45)' },
未施工: { stroke: 'rgba(250,173,20,1)', fill: 'rgba(250,173,20,0.45)' },
故障: { stroke: 'rgba(219,77,77,1)', fill: 'rgba(219,77,77,0.6)' },
运行中: { stroke: 'rgba(19,194,194,1)', fill: 'rgba(19,194,194,0.45)' },
停机: { stroke: 'rgba(99,99,99,1)', fill: 'rgba(0,0,0,0.45)' }
};
export default {
name: 'TaskMapPolygon',
props: {
rectangles: {
type: Array,
default: () => []
},
// 进一步压暗卫星底图的遮罩
darkMask: {
type: Boolean,
default: true
}
},
data() {
return {
map: null,
AMapIns: null,
polygons: [],
texts: [],
pointAll: { lng: [], lat: [] }
};
},
watch: {
rectangles: {
immediate: true,
deep: true,
handler(val) {
if (this.map && val?.length) {
this.clearLayers();
this.formatData(val);
}
}
}
},
mounted() {
this.initAMap();
},
beforeUnmount() {
this.map?.destroy();
},
methods: {
initAMap() {
const map_center = JSON.parse(this.$storage.get('map_center') || 'null');
let defaultCenterPoint = [121.5563, 32.107];
if (map_center) {
defaultCenterPoint = map_center.find((el) => el.key == 'default')?.value || defaultCenterPoint;
}
window._AMapSecurityConfig = { securityJsCode: '5869fe06ab3640b49006f4ec5e595e9f' };
AMapLoader.load({
key: '3758e4530242ba6282c77f96ea69262d',
version: '2.0',
plugins: ['AMap.MouseTool', 'AMap.Scale', 'AMap.Text']
})
.then((AMap) => {
this.AMapIns = AMap;
// 使用卫星图层(不叠加道路线)
const satellite = new AMap.TileLayer.Satellite();
this.map = new AMap.Map('map', {
viewMode: '2D',
zoom: 12,
center: defaultCenterPoint,
layers: [satellite]
});
if (this.rectangles?.length) {
this.formatData(this.rectangles);
}
})
.catch(console.error);
},
clearLayers() {
if (!this.map) return;
this.map.remove(this.polygons);
this.map.remove(this.texts);
this.polygons = [];
this.texts = [];
this.pointAll = { lng: [], lat: [] };
},
formatData(data = []) {
// 解析 WKT -> AMap path,并着色绘制(使用原始坐标,不做偏移转换)
const list = (data || []).map((item, index) => {
const raw = (item.geomWkt || '')
.replace(/POLYGON\(\(/i, '')
.replace(/\)\)$/i, '')
.trim();
const points = raw.split(',');
const path = [];
for (let i = 0; i < points.length; i++) {
const parts = points[i].trim().split(/\s+/);
const lng = Number(parts[0]);
const lat = Number(parts[1]);
if (isNaN(lng) || isNaN(lat)) continue;
this.pointAll.lng.push(lng);
this.pointAll.lat.push(lat);
path.push([lng, lat]);
}
return { ...item, path, index };
});
list.forEach((it) => this.createPolygon(it));
// 视野自适配:基于多边形覆盖物
if (this.polygons.length) {
// padding: [top, right, bottom, left]
this.map.setFitView(this.polygons, false, [60, 60, 60, 60]);
}
},
createPolygon(item) {
const { path, status, name } = item;
const style = STATUS_STYLE[status] || STATUS_STYLE['未施工'];
const polygon = new this.AMapIns.Polygon({
path,
strokeColor: style.stroke,
strokeWeight: 2,
strokeOpacity: 1,
strokeStyle: 'solid',
fillColor: style.fill,
fillOpacity: 0.45,
cursor: 'pointer',
zIndex: 50
});
console.log(polygon, 'polygon');
this.map.add(polygon);
this.polygons.push(polygon);
// 居中名称标签
const text = new this.AMapIns.Text({
text: name || '',
anchor: 'center',
style: { 'background-color': 'transparent', border: 'none', color: '#ffffff', 'font-size': '12px' }
});
// 计算简单中心点
const mid = path[Math.floor(path.length / 2)] || path[0];
if (mid) text.setPosition(mid);
text.setMap(this.map);
this.texts.push(text);
// hover 高亮
polygon.on('mouseover', () => {
polygon.setOptions({ fillOpacity: 0.55 });
});
polygon.on('mouseout', () => {
polygon.setOptions({ fillOpacity: 0.35 });
});
}
}
};
</script>
<style scoped lang="scss">
#map {
width: 100%;
height: 100%;
}
.dark-mask {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: rgba(0, 10, 26, 0.25);
pointer-events: none;
}
</style>