ly-front/src/views/contentData/headerTop/index.vue

296 lines
8.1 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="header">
<div class="header-left">
<div class="time_date">
{{ currentDate }} <span>{{ currentTime }}</span>
</div>
</div>
<div class="header-main">
<div class="textTile"></div>
</div>
<div class="header-menu">
<span>{{ leftText }}</span>
<span style="width: 20px"> | </span>
<span>{{ rightText }}</span>
</div>
<div v-if="showPermissionPrompt" class="permission-prompt">
<p>请允许地理位置权限以启用定位功能</p>
<p>您可以在浏览器地址栏设置中启用位置访问,或点击下方按钮重试</p>
<button @click="retryTracking">重试定位</button>
</div>
</div>
</template>
<script>
import { mapGetters } from "vuex";
import { HomeSyncLocation } from "@/api/home";
import Geolocation from "ol/Geolocation";
import { fromLonLat, transform } from "ol/proj";
import { Vector as VectorLayer } from "ol/layer";
import VectorSource from "ol/source/Vector";
import Point from "ol/geom/Point";
import { Style, Icon, Stroke } from "ol/style";
import Feature from "ol/Feature";
export default {
name: "header-top",
props: {
homeData: {
type: Object,
default: () => ({})
}
},
data() {
return {
currentTime: "",
currentDate: "",
isAdmins: false,
leftText: "平台已连接",
rightText: "定位正常",
latitude: "",
longitude: "",
lastUpdated: "",
timer: null,
locationTimer: null,
geolocation: null,
showPermissionPrompt: false,
retryCount: 0,
positionLayer: null
};
},
computed: {
...mapGetters(["positionPoint"])
},
mounted() {
console.log("组件挂载,启动定位");
this.isAdmins = JSON.parse(localStorage.getItem("isAdmin"));
this.updateTime();
this.timer = setInterval(() => {
this.updateTime();
}, 1000);
this.startTracking();
},
watch: {
positionPoint: {
handler(newVal) {
if (newVal) {
// this.$message.success(this.latitude + ", " + this.longitude);
console.log("位置更新", newVal, this.latitude, this.longitude);
if (newVal && this.latitude && this.longitude && window.olMap) {
const newLocation = fromLonLat(
[this.longitude, this.latitude],
"EPSG:3857"
);
this.$message.success("定位成功");
this.updateMapPosition(this.longitude, this.latitude);
const zoomLevel = 13;
window.olMap.getView().animate({
center: newLocation,
zoom: zoomLevel
});
} else {
this.$message.error("定位失败,请稍后重试");
}
this.$store.commit("SET_POSITIONPOINT", false);
}
},
deep: true
}
},
methods: {
updateMapPosition(lng, lat) {
// 移除旧的 positionLayer如果存在
if (this.positionLayer) {
window.olMap.removeLayer(this.positionLayer);
this.positionLayer = null;
}
let center = fromLonLat([lng, lat]);
var iconFeature = new Feature({
geometry: new Point(center),
name: "当前位置",
population: 4000,
rainfall: 500
});
var iconStyle = new Style({
image: new Icon({
anchor: [0.5, 46],
scale: 0.4,
anchorXUnits: "fraction",
anchorYUnits: "pixels",
src: require("@/assets/img/icon_dev.png")
})
});
iconFeature.setStyle(iconStyle);
var vectorSource = new VectorSource({
features: [iconFeature]
});
this.positionLayer = new VectorLayer({
source: vectorSource
});
window.olMap.addLayer(this.positionLayer);
},
updateTime() {
const now = new Date();
this.currentTime = now.toLocaleTimeString();
this.currentDate = now.toLocaleDateString();
},
startTracking() {
if (!window.olMap) {
console.error("OpenLayers 地图未传入,延迟重试");
setTimeout(() => this.startTracking(), 1000);
return;
}
// 清除旧的 locationTimer
if (this.locationTimer) {
clearInterval(this.locationTimer);
}
// 初始化 Geolocation
this.geolocation = new Geolocation({
trackingOptions: {
enableHighAccuracy: true,
timeout: 30000,
maximumAge: 10000
},
projection: window.olMap.getView().getProjection()
});
// 监听定位错误
this.geolocation.on("error", (error) => {
let message = "";
this.retryCount = this.retryCount || 0;
switch (error.code) {
case error.PERMISSION_DENIED:
message = "请允许地理位置权限";
this.showPermissionPrompt = true;
this.$message.error("请在浏览器设置中启用地理位置权限");
break;
case error.POSITION_UNAVAILABLE:
message = "无法获取位置信息";
if (this.retryCount < 3) {
this.retryCount++;
setTimeout(() => this.startTracking(), 5000);
} else {
this.$message.error("多次尝试后仍无法定位,请检查设备设置");
}
break;
case error.TIMEOUT:
message = "获取位置超时";
if (this.retryCount < 3) {
this.retryCount++;
setTimeout(() => this.startTracking(), 5000);
} else {
this.$message.error("定位超时,请检查网络或 GPS 信号");
}
break;
default:
message = "未知错误";
}
this.leftText = message;
this.rightText = "定位异常";
});
// 开启定位
this.geolocation.setTracking(true);
// 每 2 秒传递一次经纬度
this.locationTimer = setInterval(() => {
const coordinates = this.geolocation.getPosition();
if (coordinates) {
this.handleSuccess(coordinates);
}
}, 2000);
},
handleSuccess(coordinates) {
// 转换为 WGS84 坐标
const wgs84 = transform(coordinates, "EPSG:3857", "EPSG:4326");
this.longitude = wgs84[0];
this.latitude = wgs84[1];
this.lastUpdated = new Date().toLocaleString(); //EPSG:3857 转 EPSG:4326
this.showPermissionPrompt = false;
this.retryCount = 0;
// 传递经纬度到 API
let params = {
lat: this.latitude,
lon: this.longitude,
userId: localStorage.getItem("userId")
};
this.updateMapPosition(this.longitude, this.latitude);
// console.log("触发上报:", {
// latitude: this.latitude,
// longitude: this.longitude,
// time: this.lastUpdated
// });
HomeSyncLocation(params)
.then((res) => {
if (res.code === 0) {
this.leftText = "平台已连接";
this.rightText = "定位正常";
} else {
this.leftText = "平台连接失败";
this.rightText = "定位异常";
}
})
.catch((err) => {
this.leftText = "平台连接失败";
this.rightText = "定位异常";
});
},
retryTracking() {
this.showPermissionPrompt = false;
this.retryCount = 0;
this.startTracking();
}
},
beforeDestroy() {
if (this.geolocation) {
this.geolocation.setTracking(false);
}
if (this.timer) {
clearInterval(this.timer);
}
if (this.locationTimer) {
clearInterval(this.locationTimer);
}
}
};
</script>
<style scoped>
.logo {
font-size: 20px;
font-weight: bold;
}
.time {
font-size: 14px;
}
.actions span {
margin-left: 10px;
cursor: pointer;
}
.permission-prompt {
position: fixed;
top: 20px;
right: 20px;
background: #fff;
padding: 15px;
border: 1px solid #ddd;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
z-index: 10000;
pointer-events: auto;
}
.permission-prompt p {
margin: 0 0 10px;
}
.permission-prompt button {
padding: 5px 10px;
background: #409eff;
color: #fff;
border: none;
cursor: pointer;
}
</style>