279 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Vue
		
	
	
	
			
		
		
	
	
			279 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Vue
		
	
	
	
<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 { fromLonLat } 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 } 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,
 | 
						|
      showPermissionPrompt: false,
 | 
						|
      retryCount: 0,
 | 
						|
      positionLayer: null
 | 
						|
    };
 | 
						|
  },
 | 
						|
  computed: {
 | 
						|
    ...mapGetters(["positionPoint"])
 | 
						|
  },
 | 
						|
  mounted() {
 | 
						|
    this.isAdmins = JSON.parse(localStorage.getItem("isAdmin"));
 | 
						|
    this.updateTime();
 | 
						|
    this.timer = setInterval(() => {
 | 
						|
      this.updateTime();
 | 
						|
    }, 1000);
 | 
						|
    this.startTracking();
 | 
						|
  },
 | 
						|
  watch: {
 | 
						|
    positionPoint: {
 | 
						|
      handler(newVal) {
 | 
						|
        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);
 | 
						|
          window.olMap.getView().animate({
 | 
						|
            center: newLocation,
 | 
						|
            zoom: 13
 | 
						|
          });
 | 
						|
          this.$store.commit("SET_POSITIONPOINT", false);
 | 
						|
        }
 | 
						|
      },
 | 
						|
      deep: true
 | 
						|
    }
 | 
						|
  },
 | 
						|
  methods: {
 | 
						|
    updateMapPosition(lng, lat) {
 | 
						|
      // Remove existing position layer
 | 
						|
      if (this.positionLayer) {
 | 
						|
        window.olMap.removeLayer(this.positionLayer);
 | 
						|
        this.positionLayer = null;
 | 
						|
      }
 | 
						|
 | 
						|
      const center = fromLonLat([lng, lat], "EPSG:3857");
 | 
						|
      const iconFeature = new Feature({
 | 
						|
        geometry: new Point(center),
 | 
						|
        name: "当前位置"
 | 
						|
      });
 | 
						|
 | 
						|
      const 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);
 | 
						|
      const 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.AMap) {
 | 
						|
        console.error("高德地图 SDK 未加载,延迟重试");
 | 
						|
        this.$message.error("高德地图 SDK 加载失败");
 | 
						|
        setTimeout(() => this.startTracking(), 1000);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      // Clear existing location timer
 | 
						|
      if (this.locationTimer) {
 | 
						|
        clearInterval(this.locationTimer);
 | 
						|
      }
 | 
						|
 | 
						|
      // Initialize AMap Geolocation
 | 
						|
      AMap.plugin("AMap.Geolocation", () => {
 | 
						|
        const geolocation = new AMap.Geolocation({
 | 
						|
          enableHighAccuracy: true,
 | 
						|
          timeout: 30000,
 | 
						|
          maximumAge: 10000,
 | 
						|
          zoomToAccuracy: true
 | 
						|
        });
 | 
						|
 | 
						|
        // Handle geolocation errors
 | 
						|
        geolocation.on("error", (error) => {
 | 
						|
          let message = "";
 | 
						|
          this.retryCount = this.retryCount || 0;
 | 
						|
 | 
						|
          switch (error.info) {
 | 
						|
            case "PERMISSION_DENIED":
 | 
						|
              message = "请允许地理位置权限";
 | 
						|
              this.showPermissionPrompt = true;
 | 
						|
              this.$message.error("请在浏览器设置中启用地理位置权限");
 | 
						|
              break;
 | 
						|
            case "POSITION_UNAVAILABLE":
 | 
						|
              message = "无法获取位置信息";
 | 
						|
              if (this.retryCount < 3) {
 | 
						|
                this.retryCount++;
 | 
						|
                setTimeout(() => this.startTracking(), 5000);
 | 
						|
              } else {
 | 
						|
                this.$message.error("多次尝试后仍无法定位,请检查设备设置");
 | 
						|
              }
 | 
						|
              break;
 | 
						|
            case "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 = "定位异常";
 | 
						|
        });
 | 
						|
 | 
						|
        // Start continuous tracking
 | 
						|
        this.locationTimer = setInterval(() => {
 | 
						|
          geolocation.getCurrentPosition((status, result) => {
 | 
						|
            if (status === "complete") {
 | 
						|
              this.handleSuccess(result.position);
 | 
						|
            }
 | 
						|
          });
 | 
						|
        }, 2000);
 | 
						|
      });
 | 
						|
    },
 | 
						|
    handleSuccess(position) {
 | 
						|
      this.longitude = position.lng;
 | 
						|
      this.latitude = position.lat;
 | 
						|
      this.lastUpdated = new Date().toLocaleString();
 | 
						|
      this.showPermissionPrompt = false;
 | 
						|
      this.retryCount = 0;
 | 
						|
 | 
						|
      this.updateMapPosition(this.longitude, this.latitude);
 | 
						|
 | 
						|
      const params = {
 | 
						|
        lat: this.latitude,
 | 
						|
        lon: this.longitude,
 | 
						|
        userId: localStorage.getItem("userId")
 | 
						|
      };
 | 
						|
 | 
						|
      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.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>
 |