const api = require('../../../api/index.js'); Page({ data: { // 地图中心坐标 longitude: 0, latitude: 0, // 标记点(包含起点、终点) markers: [], // 轨迹线(实际轨迹)- 核心修改:将颜色改为红色(#ff0000) polyline: [{ points: [], color: "#999999", // 已走过的路线颜色:灰色 width: 6, dottedLine: false }], // 规划路线 - 优化:改为灰色(#999999),与已走路线形成对比 plannedRoute: [{ points: [], color: "#2f693c", // 未走的规划路线颜色:绿色 width: 4, dottedLine: false, arrowLine: true }], // 追踪状态 isTracking: false, // 信息提示文本 infoText: "", // 位置更新计时器 locationTimer: null, // 终点位置 destination: null, // 路线规划状态 routePlanned: false, // 腾讯位置服务Key qqMapKey: 'VRGBZ-ZFRHB-SKIUP-NHHJ3-TXGJT-ZIFG3', // 偏离阈值(米)和偏离状态 deviationThreshold: 50, // 超过50米视为偏离 isDeviated: false, // 重新规划相关 isReplanning: false, // 是否正在重新规划 deviationCount: 0, // 连续偏离计数 replanThreshold: 3, // 连续偏离多少次后重新规划 orderdata:{}, optionsid:'', showVerification: false, phoneNumber: "138****6789", userdata:[] }, onLoad(options) { this.setData({ userdata:wx.getStorageSync('user') }) console.log(options); this.setData({ optionsid:options.id }) // 初始化地图,获取当前位置 this.getworkorder() // 引入SDK核心类 this.qqmapsdk = require('../../../libs/qqmap-wx-jssdk.min.js'); // 初始化SDK this.mapSdk = new this.qqmapsdk({ key: this.data.qqMapKey }); }, getworkorder(){ let data = { workorderId:this.data.optionsid } api.request(`/sysworkorder/selectworkorderId`, 'post',data,{ isPublic: false }) .then((data) => { console.log(data.data); if (data.code==200) { this.setData({ orderdata:data.data }) this.initMap(); } }) .catch((err) => { console.error('请求失败:', err); }); }, onUnload() { // 页面卸载时停止追踪 this.stopTracking(); }, // 初始化地图 initMap() { const that = this; // 获取用户当前位置 wx.getLocation({ type: 'gcj02', // 腾讯地图坐标体系 success(res) { const longitude = res.longitude; const latitude = res.latitude; // 设置地图中心为当前位置 that.setData({ longitude, latitude, // 初始化起点标记 markers: [{ id: 0, longitude, latitude, iconPath: "https://esos-iot.bjdexn.cn/myminio/project/0b0593293af54ea097b168cea479c25c.png", width: 30, height: 30, title: "起点" }], // 初始化轨迹线起点(颜色已在data中设置为红色) polyline: [{ points: [{longitude, latitude}], color: "#ff0000", // 与data中保持一致,确保初始颜色正确 width: 6, dottedLine: false }] }); that.showInfo("已获取当前位置"); that.setDestination(); }, fail(err) { console.error("获取位置失败:", err); that.showInfo("请授权位置权限以使用地图功能"); // 引导用户开启权限 wx.openSetting({ success(res) { if (res.authSetting['scope.userLocation']) { that.initMap(); } } }); } }); }, // 规划路线 - 通用方法,可被初始规划和重新规划调用 planRoute(isReplan = false) { const that = this; const { longitude, latitude, destination } = this.data; if (!destination) { this.showInfo("请先设置终点"); return; } // 如果是重新规划,更新状态 if (isReplan) { this.setData({ isReplanning: true }); this.showInfo("正在重新规划路线..."); } else { this.showInfo("正在规划路线..."); } // 调用腾讯地图路线规划API this.mapSdk.direction({ mode: 'driving', // 驾车模式,可选值:'driving', 'walking', 'transit' policy:'REAL_TRAFFIC', from: { latitude: latitude, longitude: longitude }, to: { latitude: destination.latitude, longitude: destination.longitude }, success(res) { console.log("路线规划结果:", res); if (res.status === 0 && res.result.routes.length > 0) { var result = res.result var route = result.routes[0] // 提取路线点 var coors = route.polyline, pl = []; //坐标解压(返回的点串坐标,通过前向差分进行压缩) var kr = 1000000; for (var i = 2; i < coors.length; i++) { coors[i] = Number(coors[i - 2]) + Number(coors[i]) / kr; } //将解压后的坐标放入点串数组pl中 for (var i = 0; i < coors.length; i += 2) { pl.push({ latitude: coors[i], longitude: coors[i + 1] }) } // 更新路线数据(规划路线颜色已设为灰色) that.setData({ plannedRoute: [{ name: that.data.orderdata.addressName, points: pl, color: '#2f693c', // 与data中保持一致,确保规划路线颜色正确 width: 6, borderColor: '#2f693c', borderWidth: 1 }], routePlanned: true, isReplanning: false, deviationCount: 0 // 重置偏离计数 }); // 显示规划结果 const message = isReplan ? `已重新规划路线,距离${(result.routes[0].distance/1000).toFixed(1)}公里,约${Math.ceil(result.routes[0].duration)}分钟` : `路线规划完成,距离${(result.routes[0].distance/1000).toFixed(1)}公里,约${Math.ceil(result.routes[0].duration)}分钟`; that.showInfo(message); } else { that.setData({ isReplanning: false }); that.showInfo("路线规划失败,请重试"); } }, fail(err) { console.error("路线规划失败:", err); that.setData({ isReplanning: false }); that.showInfo("路线规划失败,请检查网络"); } }); }, // 设置终点位置 setDestination() { // 更新终点标记 const newMarkers = [...this.data.markers.filter(marker => marker.id !== 1)]; newMarkers.push({ name: this.data.orderdata.addressName, id: 1, latitude: this.data.orderdata.latitude, // 终点纬度 longitude: this.data.orderdata.longitude, // 终点经度 iconPath: "https://esos-iot.bjdexn.cn/myminio/project/6dc37b15321b462f9ab59c47263dd224.png", width: 30, height: 30, title: "终点" }); this.setData({ markers: newMarkers, destination: { longitude: this.data.orderdata.longitude, latitude: this.data.orderdata.latitude } }); this.showInfo("已设置终点位置"); this.planRoute(); // 初始规划路线 // this.startTracking(); // 实时监控位置 }, // 显示信息提示 showInfo(text) { this.setData({ infoText: text }); // 3秒后自动隐藏非状态类信息 if (!text.includes("正在") && !text.includes("距离") && !text.includes("偏离")) { setTimeout(() => { this.setData({ infoText: "" }); }, 3000); } }, // 导航功能 navigation(){ // 使用在腾讯位置服务申请的key const key = this.data.qqMapKey; // 调用插件的app的名称 const referer = '晟运智慧运维'; // 是否启用智能规划 const enableAI = true; // 是否开启导航功能 const navigation = 1; // 终点(建议替换为orderdata中的实际终点,当前为示例值) const endPoint = JSON.stringify({ name: this.data.orderdata.addressName || '目的地', latitude: this.data.orderdata.latitude, longitude: this.data.orderdata.longitude, }); // 个性化图层 const layerStyle = 1; wx.navigateTo({ url: `plugin://route-plan/index?key=${key}&referer=${referer}&endPoint=${endPoint}&enableAI=${enableAI}&navigation=${navigation}&layerStyle=${layerStyle}`, }); }, // 开始追踪位置 startTracking() { if (this.data.isTracking) return; const that = this; this.setData({ isTracking: true }); // 定期获取位置并检查是否偏离路线 this.setData({ locationTimer: setInterval(() => { wx.getLocation({ type: 'gcj02', success(res) { const newPoint = { longitude: res.longitude, latitude: res.latitude }; // 更新当前位置和轨迹(颜色保持红色) const updatedPolyline = [...that.data.polyline]; updatedPolyline[0].points.push(newPoint); // 更新起点标记位置 const updatedMarkers = [...that.data.markers]; updatedMarkers[0] = { ...updatedMarkers[0], longitude: res.longitude, latitude: res.latitude }; that.setData({ longitude: res.longitude, latitude: res.latitude, polyline: updatedPolyline, markers: updatedMarkers }); // 检查是否偏离规划路线 if (that.data.routePlanned && !that.data.isReplanning) { that.checkDeviation(newPoint); } }, fail(err) { console.error("获取位置失败:", err); that.showInfo("位置获取失败,请检查权限"); } }); }, 3000) // 每3秒更新一次位置 }); this.showInfo("开始追踪位置"); }, // 停止追踪 stopTracking() { if (this.data.locationTimer) { clearInterval(this.data.locationTimer); this.setData({ locationTimer: null, isTracking: false }); this.showInfo("已停止追踪"); } }, // 检查是否偏离路线 checkDeviation(currentPoint) { const { plannedRoute, deviationThreshold, deviationCount, replanThreshold } = this.data; const routePoints = plannedRoute[0].points; if (!routePoints || routePoints.length < 2) return; // 计算当前位置到路线的最短距离 let minDistance = Infinity; // 检查当前点到路线上每一段线段的距离 for (let i = 0; i < routePoints.length - 1; i++) { const distance = this.calculateDistanceToLine( currentPoint, routePoints[i], routePoints[i + 1] ); if (distance < minDistance) { minDistance = distance; } } // 判断是否偏离 const isDeviated = minDistance > deviationThreshold; if (isDeviated) { // 增加连续偏离计数 const newDeviationCount = deviationCount + 1; this.setData({ isDeviated, deviationCount: newDeviationCount }); // 显示偏离信息 this.showInfo(`已偏离路线 ${minDistance.toFixed(1)} 米,连续偏离 ${newDeviationCount}/${replanThreshold} 次`); // 播放提示音 wx.playBackgroundAudio({ dataUrl: 'http://ws.stream.qqmusic.qq.com/M500001VfvsJ21xFqb.mp3?guid=ffffffff82def4af4b12b3cd9337d38&uin=346897220&vkey=6292F51C65348166B851686B2C059D76205E4241C44E5823713D649EF6471BA681DC27D5269A1E&fromtag=46', title: '偏离提醒', coverImgUrl: '' }); // 达到重新规划阈值,且不在重新规划中 if (newDeviationCount >= replanThreshold && !this.data.isReplanning) { this.planRoute(true); // 重新规划路线,传入true标识 } } else { // 回到路线上,重置偏离计数 this.setData({ isDeviated, deviationCount: 0 }); if (this.data.isDeviated) { this.showInfo("已回到规划路线"); } } }, // 计算点到线段的距离(米) calculateDistanceToLine(point, lineStart, lineEnd) { // 经纬度转弧度 const toRadians = (degree) => degree * Math.PI / 180; // 地球半径(米) const R = 6371000; // 转换为弧度 const lat1 = toRadians(point.latitude); const lon1 = toRadians(point.longitude); const lat2 = toRadians(lineStart.latitude); const lon2 = toRadians(lineStart.longitude); const lat3 = toRadians(lineEnd.latitude); const lon3 = toRadians(lineEnd.longitude); // 计算线段长度 const a = this.haversineDistance(lat1, lon1, lat2, lon2); const b = this.haversineDistance(lat1, lon1, lat3, lon3); const c = this.haversineDistance(lat2, lon2, lat3, lon3); // 如果点在线段延长线上,返回最近端点的距离 if (b * b >= a * a + c * c) { return a; } if (a * a >= b * b + c * c) { return b; } // 计算点到线段的垂直距离 const s = (a + b + c) / 2; const area = Math.sqrt(Math.abs(s * (s - a) * (s - b) * (s - c))); return (2 * area) / c; }, // 使用haversine公式计算两点间距离(米) haversineDistance(lat1, lon1, lat2, lon2) { const R = 6371000; // 地球半径(米) const dLat = lat2 - lat1; const dLon = lon2 - lon1; const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon / 2) * Math.sin(dLon / 2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return R * c; }, // 显示验证码弹窗 showVerificationPopup() { this.setData({ showVerification: true }); }, // 关闭弹窗 onPopupClose() { this.setData({ showVerification: false }); setTimeout(() => { const slideComponent = this.selectComponent("#mySlideConfirm"); // 2. 调用组件的reset方法 slideComponent.reset(); }, 1000); }, // 确认验证码 onCodeConfirm(e) { console.log("确认验证码:", e.detail.code); // 验证逻辑... this.setData({ showVerification: false }); }, // 重新发送验证码 onResendCode() { console.log("重新发送验证码"); // 重新发送逻辑... }, // 验证码输入完成 onCodeComplete(e) { console.log("验证码输入完成:", e.detail.code); // 自动验证逻辑... let data = { carId:this.data.optionsid, verifyCode: e.detail.code, workorderId:this.data.orderdata.workorderId } api.request(`/sysworkorder/submitworkorder`, 'post',data,{ isPublic: false }) .then((data) => { console.log(data.data); if (data.code==200) { this.getworkorder(); setTimeout(() => { const slideComponent = this.selectComponent("#mySlideConfirm"); // 2. 调用组件的reset方法 slideComponent.reset(); }, 5000); } }) .catch((err) => { setTimeout(() => { const slideComponent = this.selectComponent("#mySlideConfirm"); // 2. 调用组件的reset方法 slideComponent.reset(); }, 5000); console.error('请求失败:', err); }); }, onSlideSuccess(e){ console.log(e.currentTarget.dataset.type); // 3. 更新页面状态,隐藏按钮和提示 let data = { carId:this.data.optionsid, verifyCode:'MNBJ4H', workorderId:this.data.orderdata.workorderId } api.request(`/sysworkorder/submitworkorder`, 'post',data,{ isPublic: false }) .then((data) => { console.log(data.data); if (data.code==200) { if (e.currentTarget.dataset.type==2) { let objdata ={ workorderId:this.data.orderdata.workorderId } api.request(`/sysworkorder/createverify`, 'post',objdata,{ isPublic: false }) .then((data) => { console.log(data.data); if (data.code==200) { } }) .catch((err) => { console.error('请求失败:', err); }); } this.getworkorder(); setTimeout(() => { const slideComponent = this.selectComponent("#mySlideConfirm"); // 2. 调用组件的reset方法 slideComponent.reset(); }, 5000); } }) .catch((err) => { setTimeout(() => { const slideComponent = this.selectComponent("#mySlideConfirm"); // 2. 调用组件的reset方法 slideComponent.reset(); }, 5000); console.error('请求失败:', err); }); }, ontelephone(e){ console.log(e.currentTarget.dataset.phone); const phoneNumber = e.currentTarget.dataset.phone; wx.showModal({ title: '确认拨打电话', content: '是否拨打' + phoneNumber + '?', success: (res) => { if (res.confirm) { wx.makePhoneCall({ phoneNumber: phoneNumber }); } } }); } });