ly-front/src/views/mapControl/index.vue

532 lines
15 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>
<div class="HomeMap">
<div class="zoom-level" @click="soundAndMenu">
<img :src="zoomLevelImage" alt="" />
</div>
<div class="zoom-control">刻度尺{{ zoomControl }}</div>
<div class="btn-container" v-if="closeBtnVisible">
<el-button @click="handleClickClose()">返回</el-button>
</div>
<div id="map" ref="olMap" class="map-container"></div>
<div class="pointingNorth">
<img src="@/assets/img/user.png" alt="" @click="userOpen" />
<img src="@/assets/img/setup.png" alt="" @click="setupOpen" />
<img src="@/assets/img/query.png" alt="" @click="queryOpen" />
</div>
<div class="configuration">
<div class="refresh" @click="refreshClick">
<img src="@/assets/img/refresh.png" alt="" />
</div>
<div class="refresh" @click="positionClick">
<img src="@/assets/img/icon_postions.png" alt="" />
</div>
<div class="refresh" @click="modelClick">
<img src="@/assets/img/icon_model.png" alt="" />
</div>
</div>
<el-dialog
title="设置"
:visible.sync="dialogVisible"
width="50%"
:before-close="handleClose"
append-to-body
class="custom-class"
>
<div class="block">
<span class="demonstration">预警声音设置</span>
<el-slider v-model="value2"></el-slider>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="determine"> </el-button>
</span>
</el-dialog>
<el-dialog
title="查询"
:visible.sync="dialogQueryVisible"
width="90%"
:before-close="handleClose"
append-to-body
class="custom-table"
>
<AlertDialog />
</el-dialog>
</div>
</template>
<script>
import { mapGetters } from "vuex";
import Map from "ol/Map";
import View from "ol/View";
import TileLayer from "ol/layer/Tile";
import { fromLonLat } from "ol/proj";
import XYZ from "ol/source/XYZ";
import { Feature, Overlay } from "ol";
import { Point, MultiPolygon } from "ol/geom";
import { Vector as VectorLayer } from "ol/layer";
import { Vector as VectorSource } from "ol/source";
import { Style, Fill, Stroke, Circle } from "ol/style";
import GeoJSON from "ol/format/GeoJSON";
import LayerGroup from "ol/layer/Group";
import AlertDialog from "../menuData/AlertDialog.vue";
import { devPositionList } from "@/api/position.js";
export default {
name: "HomeMap",
components: {
AlertDialog
},
data() {
return {
map: null,
zoomLevel: null,
isZoomedIn: true,
isZoomedOut: false,
showPermissionPrompt: false,
dialogVisible: false,
value2: 0,
currentBaseMap: "gaode",
dialogQueryVisible: false,
closeBtnVisible: false,
zoomControl: 0,
toggleMap: false
};
},
created() {
// 清空控制台(可选)
// console.clear();
},
mounted() {
this.initMap();
},
computed: {
...mapGetters(["statePage", "cityCode", "checkFlag"]),
zoomLevelImage() {
return this.isZoomedIn
? require("@/assets/img/sound.png")
: require("@/assets/img/mute.png");
}
},
watch: {
checkFlag: {
handler(newVal) {
this.closeBtnVisible = newVal;
this.dialogQueryVisible = false;
},
deep: true
}
},
methods: {
handleClickClose() {
this.$store.commit("SET_CHECKFLAG", false);
this.$store.commit("SET_CLEARTRAJECTORY", true);
},
initPositon() {
let positionIds = {
pageNum: 1,
pageSize: 10000
};
devPositionList(positionIds).then((devRes) => {
if (devRes.code === 0) {
let positionRes = localStorage.getItem("PositionIds");
this.positionList = devRes.data.items;
const matchedList = this.positionList.filter((item) =>
positionRes.includes(item.id)
);
this.loadGeoJson(matchedList);
}
});
},
// 加载 GeoJSON 数据并绘制
loadGeoJson(value) {
// 清空已有图层
this.clearLayer();
// 创建矢量源
const source = new VectorSource();
// 解析 GeoJSON 数据
const geojsonFormat = new GeoJSON();
value.forEach((item) => {
// 解析 regionJson 为 OpenLayers 特征
const feature = geojsonFormat.readFeature(JSON.parse(item.regionJson), {
dataProjection: "EPSG:4326", // 输入数据为 WGS84
featureProjection: "EPSG:3857" // 转换为地图投影
});
// 设置多边形样式:透明蓝色填充,蓝色边框
feature.setStyle(
new Style({
fill: new Fill({
color: "rgba(0, 0, 255, 0.3)" // 透明蓝色填充
}),
stroke: new Stroke({
color: "#0000FF", // 蓝色边框
width: 2
})
})
);
// 添加多边形到源
source.addFeature(feature);
// 添加中心点
const centerFeature = new Feature({
geometry: new Point(fromLonLat([item.lon, item.lat]))
});
// 设置中心点样式:红色圆点
centerFeature.setStyle(
new Style({
image: new Circle({
radius: 6,
fill: new Fill({
color: "#FF0000" // 红色填充
}),
stroke: new Stroke({
color: "#FFFFFF", // 白色边框
width: 1
})
})
})
);
// 添加中心点到源
source.addFeature(centerFeature);
});
// 创建矢量图层
this.vectorLayer = new VectorLayer({
source: source,
zIndex: 10 // 设置图层优先级
});
// 添加到父组件的地图
window.olMap.addLayer(this.vectorLayer);
// 跳转到 GeoJSON 数据区域
if (source.getFeatures().length > 0) {
const extent = source.getExtent(); // 获取所有特征的边界框
window.olMap.getView().fit(extent, {
padding: [50, 50, 50, 50], // 四周留白(像素)
maxZoom: 15, // 最大缩放级别
duration: 500 // 动画持续时间(毫秒)
});
}
},
// 清空图层
clearLayer() {
if (this.vectorLayer) {
window.olMap.removeLayer(this.vectorLayer);
this.vectorLayer = null;
}
},
refreshClick() {
// 刷新页面
window.location.reload();
},
positionClick() {
console.log("位置点击");
this.$store.commit("SET_POSITIONPOINT", true);
},
modelClick() {
// 切换底图
this.toggleMap = !this.toggleMap;
window.olMap.getLayers().forEach((layer) => {
if (layer.get("title") === "白色底图组") {
layer.setVisible(this.toggleMap);
} else if (layer.get("title") === "暗色底图组") {
layer.setVisible(!this.toggleMap);
}
});
},
soundAndMenu() {
this.isZoomedIn = !this.isZoomedIn;
this.$store.commit("SET_ISZOOMEDIN", this.isZoomedIn);
},
initMap() {
// 初始化 OpenLayers 地图
this.map = new Map({
target: "map", // 替换为 this.$refs.olMap 如果在 Vue 中
layers: [
// 白色底图 + 默认注记
new LayerGroup({
title: "白色底图组",
layers: [
this.createTiandituLayer("vec", "天地图矢量底图"), // 白色底图
this.createTiandituLayer("cia", "天地图默认注记") // 默认注记
],
visible: true // 默认显示白色底图
}),
// 暗色底图 + 白色注记
new LayerGroup({
title: "暗色底图组",
layers: [
this.createTiandituLayer(
"vec",
"天地图暗色底图",
"grayscale(98%) invert(100%) sepia(20%) hue-rotate(180deg) saturate(1600%) brightness(80%) contrast(90%)"
), // 暗色底图
this.createTiandituLayer(
"cia",
"天地图白色注记",
"grayscale(100%) brightness(150%) contrast(120%)"
) // 白色注记
],
visible: false // 默认隐藏暗色底图
})
],
view: new View({
projection: "EPSG:3857",
center: fromLonLat([117.337103, 39.040924]), // 经纬度转投影坐标
zoom: 10,
minZoom: 0,
maxZoom: 18,
constrainRotation: false
})
});
// 保存地图实例到全局(与 Mars3D 的 window.marsMap 类似)
window.olMap = this.map;
// 处理地图加载完成后的逻辑
this.onMapLoad(this.map);
// 绑定点击事件
this.map.on("click", this.mapClickHandler);
// 绑定缩放/移动结束事件
this.map.getView().on("change:resolution", this.mapZoomHandler);
this.map.getView().on("change:center", this.mapZoomHandler);
},
mapClickHandler(event) {
// 处理地图点击事件
console.log("地图点击:", event);
},
mapZoomHandler() {
// 获取当前缩放等级
this.zoomLevel = Math.round(this.map.getView().getZoom());
},
createTiandituLayer(layerType, title, filter = null) {
let tiandituKey = "a78289a00ac2e57e0e7abe1d8560d644";
return new TileLayer({
visible: true,
name: title,
source: new XYZ({
url: `http://t{0-7}.tianditu.gov.cn/${layerType}_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=${layerType}&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${tiandituKey}`,
tileLoadFunction: filter
? (imageTile, src) => {
const img = new Image();
img.setAttribute("crossOrigin", "anonymous");
img.onload = function () {
const canvas = document.createElement("canvas");
const w = img.width;
const h = img.height;
canvas.width = w;
canvas.height = h;
const context = canvas.getContext("2d");
context.filter = filter;
context.drawImage(img, 0, 0, w, h, 0, 0, w, h);
imageTile.getImage().src = canvas.toDataURL("image/png");
};
img.src = src;
}
: undefined
}),
title: title
});
},
onMapLoad(map) {
setTimeout(() => {
this.initPositon();
}, 2000);
// 地图加载完成后的处理
const camera = window.mapConfig || {};
if (camera.isCamera) {
// 设置视角约束
map
.getView()
.setCenter(
fromLonLat([camera.cameraLon || 0, camera.cameraLat || 0])
);
map.getView().setMinZoom(3); // 最小缩放等级
map.getView().setMaxZoom(18); // 最大缩放等级
}
// 监听缩放级别变化
const view = map.getView();
this.zoomControl = view.getZoom();
view.on("change:resolution", () => {
this.zoomControl = Math.round(view.getZoom());
console.log(this.zoomControl, "缩放级别已更改");
});
},
handleClose() {
this.dialogVisible = false;
this.dialogQueryVisible = false;
},
userOpen() {
this.$confirm("是否退出登录?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$router.push({ name: "login" });
localStorage.removeItem("setToken");
localStorage.removeItem("expires");
localStorage.removeItem("userId");
localStorage.removeItem("isAdmin");
localStorage.removeItem("PositionIds");
})
.catch(() => {
this.$message({
type: "info",
message: "已取消退出登录"
});
});
},
setupOpen() {
this.dialogVisible = true;
const media = this.$refs.uavAudio;
const savedVolume = localStorage.getItem("soundValue");
if (savedVolume !== null) {
this.value2 = Number(savedVolume);
} else {
this.value2 = media.volume * 100;
}
localStorage.setItem("soundValue", this.value2);
},
determine() {
// 确定时保存音量到 localStorage
localStorage.setItem("soundValue", this.value2);
this.$store.commit("SET_SILDERVALUE", this.value2);
this.dialogVisible = false; // 可选:关闭弹窗
},
queryOpen() {
this.dialogQueryVisible = true;
},
headdenForm(value, type) {
let params = {};
if (type === "search") {
params = JSON.parse(JSON.stringify(this.$refs.myForm.ruleForm));
if (params.dateRange && params.dateRange.length === 2) {
params.strartDate = moment(params.dateRange[0]).format("YYYY-MM-DD");
params.endDate = moment(params.dateRange[1]).format("YYYY-MM-DD");
}
this.$delete(params, "dateRange");
params.pageNum = this.paginationParam.currentPage;
params.pageSize = this.paginationParam.size;
alarmList(params).then((res) => {
if (res.code === 0) {
this.tableData = res.data.items.map((item) => {
const { isWhitelist, duration, frequency, ...rest } = item;
return {
...rest,
isattacked: item.isattacked ? "是" : "否",
duration: String(item.duration),
frequency: String(item.frequency)
};
});
this.paginationParam.total = res.data.total;
}
});
}
},
handleSizeChange(value) {
console.log(value);
this.paginationParam.size = value;
this.headdenForm({}, "search");
},
handlePageChange(value) {
console.log(value);
this.paginationParam.currentPage = value;
this.headdenForm({}, "search");
}
}
};
</script>
<style scoped lang="scss">
.HomeMap {
width: 100%;
height: 100%;
position: relative;
.zoom-level {
position: absolute;
top: 60px;
right: 40px;
z-index: 1000;
color: #fff;
img {
width: 48px;
height: 48px;
}
}
.zoom-control {
position: absolute;
left: 60px;
bottom: 30px;
z-index: 1000;
color: #fff;
img {
width: 48px;
height: 48px;
}
}
.btn-container {
position: absolute;
top: 70px;
right: 100px;
z-index: 1000;
color: #fff;
}
.configuration {
position: absolute;
bottom: 32px;
right: 40px;
z-index: 1000;
color: #fff;
width: 50px;
height: 200px;
background-color: rgba(209, 242, 255, 0.9);
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
.refresh {
width: 100%;
height: 30%;
line-height: 60px;
img {
width: 32px;
height: 32px;
margin-top: 30%;
}
}
}
.map-container {
width: 100%;
height: 100%;
}
.pointingNorth {
width: 236px;
height: 52px;
position: absolute;
bottom: 37px;
left: 50%;
transform: translateX(-50%);
z-index: 1000;
display: flex;
align-items: center;
justify-content: space-between;
img {
width: 52px;
height: 52px;
}
}
}
</style>