<template>
<view class="wrap">
<view class="header">私车公用 · 定位轨迹</view>
<view class="card">
<view class="status">{{ running ? '? 定位中' : '⚪ 已停止' }}</view>
<!-- 定位失败状态 在这里显示 -->
<view class="gps-status" :class="gpsStatusClass">{{ gpsStatusText }}</view>
<view class="distance">{{ (totalDistance / 1000).toFixed(2) }} km</view>
<view class="info">
<view>用时:{{ formatTime(useTime) }}</view>
<view>精度:{{ accuracy }} 米</view>
<view>轨迹点:{{ path.length }} 个</view>
</view>
</view>
<view class="btns">
<button v-if="!running" type="primary" @click="start">开始行程</button>
<button v-else type="warn" @click="stop">结束行程</button>
</view>
<button v-if="path.length > 0" @click="playback" type="primary" style="margin:20rpx 0;">
轨迹回放
</button>
<canvas v-if="showCanvas" canvas-id="trackCanvas" class="canvas"></canvas>
</view>
</template>
<script>
export default {
data() {
return {
running: false,
lat: 0,
lng: 0,
accuracy: 999,
totalDistance: 0,
lastPoint: null,
startTime: null,
useTime: 0,
timer: null,
gpsStatusText: '未开始',
gpsStatusClass: 'normal',
path: [],
showCanvas: false,
playIndex: 0,
playTimer: null
}
},
onUnload() {
this.stop()
},
methods: {
start() {
this.running = true
this.startTime = Date.now()
this.lastPoint = null
this.totalDistance = 0
this.useTime = 0
this.path = []
this.showCanvas = false
this.gpsStatusText = "正在启动GPS定位..."
this.gpsStatusClass = "weak"
// 计时
this.timer = setInterval(() => {
this.useTime = Math.floor((Date.now() - this.startTime) / 1000)
}, 1000)
// ==============================================
// 定位启动 + 失败状态 全部写在这里
// ==============================================
uni.startLocationUpdate({
enableHighAccuracy: true,
success: () => {
let timeout = setTimeout(() => {
// 15秒拿不到坐标 → 判定定位失败
if (this.accuracy > 500) {
this.gpsStatusText = "❌ 定位失败:请检查GPS/高精度/权限"
this.gpsStatusClass = "bad"
}
}, 15000)
uni.onLocationChange((res) => {
if (!this.running) return
// 有坐标 → 清除失败超时
clearTimeout(timeout)
this.lat = res.latitude
this.lng = res.longitude
this.accuracy = res.accuracy || 999
// GPS状态判断
if (this.accuracy > 100) {
this.gpsStatusText = "? 室内无卫星 / 信号差"
this.gpsStatusClass = "bad"
} else if (this.accuracy > 30) {
this.gpsStatusText = "? GPS信号弱"
this.gpsStatusClass = "weak"
} else {
this.gpsStatusText = "? GPS正常,记录中"
this.gpsStatusClass = "good"
}
// 记录轨迹
if (this.accuracy < 100) {
this.path.push({ lat: this.lat, lng: this.lng })
}
// 计算里程
if (this.lastPoint && this.accuracy < 100) {
let dis = this.getDistance(
this.lastPoint.lat, this.lastPoint.lng,
this.lat, this.lng
)
if (dis > 1.5) this.totalDistance += dis
}
this.lastPoint = { lat: this.lat, lng: this.lng }
})
},
// ==============================================
// 启动失败 → 直接显示失败状态
// ==============================================
fail: (err) => {
this.gpsStatusText = "❌ 定位启动失败:" + err.errMsg
this.gpsStatusClass = "bad"
console.error("定位失败:", err)
}
})
},
stop() {
this.running = false
clearInterval(this.timer)
uni.stopLocationUpdate()
this.gpsStatusText = "已停止"
this.gpsStatusClass = "normal"
},
playback() {
if (this.path.length < 2) {
uni.showToast({ title: '轨迹点不足', icon: 'none' })
return
}
this.showCanvas = true
this.playIndex = 0
clearInterval(this.playTimer)
const ctx = uni.createCanvasContext('trackCanvas')
let minLat = Math.min(...this.path.map(p => p.lat))
let maxLat = Math.max(...this.path.map(p => p.lat))
let minLng = Math.min(...this.path.map(p => p.lng))
let maxLng = Math.max(...this.path.map(p => p.lng))
let w = 680, h = 400
this.playTimer = setInterval(() => {
if (this.playIndex >= this.path.length) {
clearInterval(this.playTimer)
return
}
let p = this.path[this.playIndex]
let x = ((p.lng - minLng) / (maxLng - minLng || 1)) * w
let y = h - ((p.lat - minLat) / (maxLat - minLat || 1)) * h
ctx.beginPath()
ctx.arc(x, y, 6, 0, 2 * Math.PI)
ctx.setFillStyle('#007aff')
ctx.fill()
ctx.draw(true)
this.playIndex++
}, 80)
},
getDistance(lat1, lng1, lat2, lng2) {
const rad = Math.PI / 180
const R = 6371000
let dLat = (lat2 - lat1) * rad
let dLng = (lng2 - lng1) * rad
let a = Math.sin(dLat / 2) ** 2 + Math.cos(lat1 * rad) * Math.cos(lat2 * rad) * Math.sin(dLng / 2) ** 2
return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
},
formatTime(s) {
const m = Math.floor(s / 60)
const sec = s % 60
return `${m}分${sec}秒`
}
}
}
</script>
<style scoped>
.wrap { padding: 30rpx; background: #f5f7fa; min-height: 100vh; }
.header { font-size: 36rpx; font-weight: bold; text-align: center; margin: 20rpx 0; }
.card { background: #fff; border-radius: 20rpx; padding: 30rpx; margin-bottom: 20rpx; }
.status { font-size: 28rpx; color: #007aff; text-align: center; margin-bottom: 10rpx; }
.gps-status {
text-align: center;
padding: 12rpx;
border-radius: 10rpx;
font-size: 26rpx;
margin-bottom: 20rpx;
}
.gps-status.normal { background: #f5f7fa; color: #333; }
.gps-status.weak { background: #fff4e4; color: #f57c00; }
.gps-status.bad { background: #ffeaea; color: #d32f2f; }
.gps-status.good { background: #e6f7e6; color: #2e7d32; }
.distance { font-size: 54rpx; font-weight: bold; color: #02c266; text-align: center; margin: 20rpx 0; }
.info { font-size: 24rpx; color: #666; line-height: 40rpx; }
.btns { display: flex; justify-content: center; gap: 30rpx; }
.canvas { width: 680rpx; height: 400rpx; background: #fff; border: 1rpx solid #eee; margin: 20rpx auto; }
</style>
3***@qq.com
- 发布:2026-05-25 22:45
- 更新:2026-05-25 22:46
- 阅读:40
1 个回复
Ask小助手 - Ask社区AI助手
根据你提供的代码和问题描述,定位获取不成功但权限已经配置了,可能有以下几个原因:
1. 权限申请时机问题
虽然你在
manifest.json中配置了权限,但在部分平台上(特别是微信小程序和鸿蒙),还需要在代码中主动调用授权。建议在start方法中,先调用uni.authorize确保权限已授权:2. 微信小程序特殊处理
如果是微信小程序,需要注意:
manifest.json中配置微信小程序的定位权限描述3. 不同平台的定位 API 差异
根据知识库中的信息,不同平台可能需要不同的处理方式:
鸿蒙平台:
harmony-mp-configs/entry/src/main/module.json5中添加权限配置:uni.authorize请求用户授权4. 定位启动延迟问题
你在代码中使用了 15 秒超时判断,但实际环境中 GPS 冷启动可能需要更长时间。建议:
5. 真机调试建议
6. 优化后的代码示例
如果以上方法都不能解决问题,建议提供具体的运行平台(iOS/Android/微信小程序/鸿蒙等)和环境信息,以便进一步排查。
要回复问题请先登录或注册
公告
更多>相关问题