| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333 |
- const api = require('../../../api/index.js');
- const app = getApp(); // 在文件顶部获取app实例
- Page({
- data: {
- // 地图中心坐标
- longitude: 0,
- latitude: 0,
-
- // 标记点(包含起点、终点)
- markers: [],
-
- // 轨迹线(实际轨迹)
- polyline: [{
- points: [],
- color: "#ff0000", // 已走过的路线颜色:红色
- width: 6,
- dottedLine: false
- }],
-
- // 规划路线
- 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: '',
- showpayment: false, // 结算弹窗显示状态
- showCodePopup: false, // 验证码弹窗显示状态
- countdown: 60, // 验证码倒计时
- canResend: false, // 是否可重新发送
- userdata: [],
- moretype: false,
- // 拖动
- cardHeight: 'min', // 初始高度档位:min/mid/max
- currentHeight: 0, // 当前实际高度(px)
- startY: 0, // 触摸起始Y坐标
- maskOpacity: 0.3, // 遮罩透明度
- windowHeight: 0, // 屏幕可用高度(px)
- // 三个固定高度(max改为屏幕高度)
- heightConfig: {
- min: 400, // 最低高度(仅显示价格和路线简要)
- mid: 520, // 中间高度(显示行程详情)
- max: 0 // 占位,将在onLoad中设置为屏幕高度
- },
- costdetails: false,
- trackPoints: [],
- distance: '',
- obtainindex: 0,
- driverLocation: {}, // 司机位置(对象)
- mapInitialized: false, // 标记地图是否初始化
- isDriver: false // 标记是否为司机角色
-
- },
- onReady() {
- // 创建地图上下文
- this.mapCtx = wx.createMapContext('map');
- },
-
- onLoad(options) {
- // 监听WebSocket消息
- wx.$on('wsMessage', this.detailsWsMessage);
-
- // 获取屏幕可用高度(不含导航栏)
- const systemInfo = wx.getSystemInfoSync();
- const windowHeight = systemInfo.windowHeight;
-
- // 更新heightConfig,max设为屏幕高度
- this.setData({
- windowHeight,
- heightConfig: {
- ...this.data.heightConfig,
- max: windowHeight
- },
- currentHeight: this.data.heightConfig.min, // 初始高度为min档
- isDriver: wx.getStorageSync('user').operationRole == 4 // 初始化司机角色标记
- });
-
- this.setData({
- userdata: wx.getStorageSync('user') || {},
- optionsid: options.id
- });
-
- console.log('司机端模式:', this.data.isDriver);
-
- // 引入SDK核心类
- this.qqmapsdk = require('../../../libs/qqmap-wx-jssdk.min.js');
- // 初始化SDK
- this.mapSdk = new this.qqmapsdk({
- key: this.data.qqMapKey
- });
-
- // 初始化地图,获取当前位置和工单信息
- this.getoneworkorderdetailss();
- // this.getoneworkorderdetails();
-
- },
-
- onUnload() {
- // 移除WebSocket消息监听
- wx.$off('wsMessage', this.detailsWsMessage);
-
- // 页面卸载时清理资源
- if (this.data.locationTimer) {
- clearInterval(this.data.locationTimer);
- }
-
- // 如果是司机角色,停止后台定位
- if (this.data.isDriver) {
-
- // wx.stopLocationUpdateBackground().catch(err => console.error('停止后台定位失败', err));
- // wx.offLocationChange(); // 移除位置监听
- }
- },
-
- /**
- * 处理接收到的 WebSocket 消息
- * @param {Object} message 从 app.js 广播过来的消息对象
- */
- // 可用,位置,容量-
- detailsWsMessage(message) {
- console.log('收到 WebSocket 消息:', message);
-
- if (!message || !message.api) {
- console.warn('无效的WebSocket消息:', message);
- return;
- }
-
- // 根据消息的api字段进行不同的处理
- switch (message.api) {
- case '/sysworkorder/selectworkorderId':
- // 收到工单列表更新的消息,刷新当前工单信息
- // 这个消息通常意味着工单状态可能发生了变化(如分配、完成等)
- this.getoneworkorderdetails();
- break;
-
- case '/sysworkorder/selectworkorderredis':
- // 收到坐标上传的消息,意味着司机位置有更新
- // 这个消息可以由司机自己发出,也可以由服务器推送给乘客
- // 为了数据一致性,直接刷新轨迹
- this.historytrajectory();
- break;
-
- case '/sysworkorder/selectworkorderId':
- // 收到工单状态更新的消息(例如,乘客确认上车、到达目的地等)
- // 刷新工单信息以获取最新状态
- this.getoneworkorderdetails();
- break;
-
- // 你可以根据实际的业务需求,添加更多的case
- // case 'other_api_path':
- // // 处理其他类型的消息
- // break;
-
- default:
- // 对于未知类型的消息,可以打印日志以便调试
- console.log('收到未知类型的WebSocket消息, api:', message.api);
- // 作为一个备选方案,也可以默认刷新工单信息,确保数据最新
- // this.getoneworkorderdetails();
- break;
- }
- },
- getoneworkorderdetailss() {
- const 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
- });
- // 保存旧的工单类型,用于比较状态变化
- const oldWorkorderType = this.data.orderdata.workorderType;
- // **核心修改点:调用 app.js 的方法来控制定位上传**
- if (this.data.isDriver) {
- // 如果工单状态变为进行中 (1-4),且之前未在上传,则启动上传
- if (data.data.workorderType >= 1 && data.data.workorderType <= 2) {
- app.startDriverLocationUpload(this.data.optionsid);
- this.showInfo('已开启实时位置上传');
- }
- }
- this.initMap();
- }
- })
- .catch((err) => {
- this.showInfo('获取工单信息失败');
- });
- },
-
- getoneworkorderdetails() {
- const 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.setDestination();
-
- // this.setData({
- // markers: [],
- // polyline: [{ points: [] }],
- // plannedRoute: [{ points: [] }],
- // driverLocation: {}
- // });
-
- }
- })
- .catch((err) => {
- console.error('获取工单信息失败:', err);
- this.showInfo('获取工单信息失败');
- });
- },
-
- // 初始化地图(优化司机端逻辑)
- initMap() {
- // 获取用户当前位置(司机端优先使用自身位置作为地图中心)
- wx.getLocation({
- type: 'gcj02', // 腾讯地图坐标体系
- success: (res) => {
- const { longitude, latitude } = res;
-
- this.setData({
- longitude,
- latitude,
- });
-
- // 司机端逻辑:仅在工单已分配时开启后台定位(workorderType >= 1)
- if (this.data.isDriver && this.data.orderdata.workorderType >= 1) {
- this.setData({
- driverLocation: { longitude, latitude } // 司机端初始化自身位置
- })
- this.historytrajectory(); // 主动加载历史轨迹
- }
-
- this.setDestination();
- },
- fail: (err) => {
- console.error("获取位置失败:", err);
- this.showInfo(this.data.isDriver ? "司机定位权限未授权,请开启" : "请授权位置权限以使用地图功能");
-
- // 引导用户开启权限
- wx.openSetting({
- success: (res) => {
- if (res.authSetting['scope.userLocation']) {
- this.initMap();
- }
- }
- });
- }
- });
- },
-
- // 设置终点位置(核心修改:未分配工单时隐藏司机标记和轨迹)-
- setDestination() {
- const ICON_PATH = {
- start: "https://esos-iot.com/myminio/project/0b0593293af54ea097b168cea479c25c.png",
- end: "https://esos-iot.com/myminio/project/6dc37b15321b462f9ab59c47263dd224.png",
- driver: "https://esos-iot.com/myminio/project/f6fba6c83b2d4864a73f5f1d83cda416.png"
- };
- const MARKER_SIZE = { width: 30, height: 30 };
- const MAP_PADDING = [100, 100, 100, 100];
- const ROUTE_COLOR = "#ff0000";
- const ROUTE_WIDTH = 6;
-
- const requestData = {
- workorderId: this.data.optionsid
- };
-
- api.request(`/sysworkorder/selectworkorderredis`, 'post', requestData, { isPublic: false })
- .then((response) => {
-
-
- if (response.code !== 200 || response.code==[]) {
- this.showInfo("暂无轨迹数据");
- return;
- }
-
- if (!this.data.orderdata) {
- this.showInfo("工单信息加载中...");
- return;
- }
- response.data = [...response.data].reverse();
- console.log('Redis轨迹数据:', response.data);
-
- // 关键判断:工单是否处于进行中状态(1-4)
- const isWorkorderAssigned = this.data.orderdata.workorderType >= 1 && this.data.orderdata.workorderType <= 2;
- // 初始化司机位置为 null
- let driverPoint = null;
-
- // 如果工单处于进行中状态
- if (isWorkorderAssigned) {
- // 优先从最新的响应数据中获取司机位置
- // 只有当 response.data 是一个非空数组时,才取第一个元素
- if (response.data && Array.isArray(response.data) && response.data.length > 0) {
- driverPoint = response.data[response.data.length-1];
- } else {
- // 如果响应数据为空或格式不正确,则使用页面上已缓存的司机位置
- driverPoint = null;
- }
- }else{
- const markers = [];
- const endPoint = this.data.orderdata;
- if (response.data.length>0) {
- // 已分配工单时才显示起点
- markers.push({
- id: 0,
- longitude: response.data[0].longitude,
- latitude: response.data[0].latitude,
- iconPath: ICON_PATH.start,
- ...MARKER_SIZE,
- title: "起点"
- });
- }
-
-
- // 始终添加终点标记
- markers.push({
- id: 1,
- longitude: endPoint.longitude,
- latitude: endPoint.latitude,
- iconPath: ICON_PATH.end,
- ...MARKER_SIZE,
- title: "终点",
- name: endPoint.poiName
- });
- this.setData({
- markers,
- plannedRoute: [{
- points: response.data,
- color: "#2f693c", // 未走的规划路线颜色:绿色
- width: 4,
- dottedLine: false,
- arrowLine: true
- }]
- })
- this.mapCtx.includePoints({
- points: response.data,
- padding: MAP_PADDING
- });
- return
- }
-
- // 对于工单状态为 5 (已完成) 或其他状态,driverPoint 保持为 null
- const startPoint = isWorkorderAssigned ? (response.data && response.data.length > 0 ? response.data[0] : null) : null;
- const endPoint = this.data.orderdata;
- console.log(driverPoint);
- // 构建标记点(未分配时不添加司机标记)
- const markers = [];
-
- // 已分配工单时才显示起点
- if (isWorkorderAssigned && startPoint) {
- markers.push({
- id: 0,
- longitude: startPoint.longitude,
- latitude: startPoint.latitude,
- iconPath: ICON_PATH.start,
- ...MARKER_SIZE,
- title: "起点"
- });
- }
-
- // 始终添加终点标记
- markers.push({
- id: 1,
- longitude: endPoint.longitude,
- latitude: endPoint.latitude,
- iconPath: ICON_PATH.end,
- ...MARKER_SIZE,
- title: "终点",
- name: endPoint.poiName
- });
- console.log(driverPoint);
- // 已分配工单且有司机位置时,才添加司机标记
- if (isWorkorderAssigned && driverPoint) {
- markers.push({
- id: 2,
- longitude: driverPoint.longitude,
- latitude: driverPoint.latitude,
- iconPath: ICON_PATH.driver,
- width: 35,
- height: 35,
- title: this.data.isDriver ? "我的位置" : "司机正在赶来",
- callout: {
- content: this.data.isDriver ? "我的位置" : "司机正在赶来",
- display: "BYCLICK"
- }
- });
- }
-
- // 构建轨迹线(未分配时不显示轨迹线)
- const polyline = [];
- if (isWorkorderAssigned) {
- if (response.data && response.data.length > 1) {
- const trackPoints = response.data.map(point => ({
- longitude: point.longitude,
- latitude: point.latitude
- }));
- polyline.push({
- points: trackPoints,
- color: ROUTE_COLOR,
- width: ROUTE_WIDTH,
- dottedLine: false
- });
- } else if (startPoint && endPoint) {
- polyline.push({
- points: [
- { longitude: startPoint.longitude, latitude: startPoint.latitude },
- { longitude: endPoint.longitude, latitude: endPoint.latitude }
- ],
- color: ROUTE_COLOR,
- width: ROUTE_WIDTH,
- dottedLine: false
- });
- }
- }
-
- // 更新页面数据
- this.setData({
- markers,
- startPoint: isWorkorderAssigned ? startPoint : null,
- destination: { longitude: endPoint.longitude, latitude: endPoint.latitude },
- polyline
- });
-
- // 提示信息区分工单状态
- // if (isWorkorderAssigned) {
- // if (startPoint) {
- // this.showInfo(this.data.isDriver ? "已加载起点、终点和我的位置" : "已设置起点和终点位置");
- // } else {
- // this.showInfo(this.data.isDriver ? "已加载终点和我的位置(等待起点更新)" : "已加载终点位置(等待起点更新)");
- // }
- // } else {
- // this.showInfo("工单未分配,暂未显示司机信息");
- // }
-
- // 地图视野初始化(未分配时仅显示终点)
- if (this.mapCtx && !this.data.mapInitialized) {
- const includePoints = [{
- longitude: endPoint.longitude,
- latitude: endPoint.latitude
- }];
-
- // 已分配工单时才包含起点和司机位置
- if (isWorkorderAssigned) {
- if (startPoint) includePoints.push({ longitude: startPoint.longitude, latitude: startPoint.latitude });
- if (driverPoint) includePoints.push({ longitude: driverPoint.longitude, latitude: driverPoint.latitude });
- }
- console.log(includePoints);
- this.mapCtx.includePoints({
- points: includePoints,
- padding: MAP_PADDING
- });
-
-
-
- this.setData({ mapInitialized: true });
- }
-
- // 已分配工单且有起点终点时,才规划路线
- if (isWorkorderAssigned && startPoint && endPoint && !this.data.routePlanned) {
- this.planRoute();
-
- }
- })
- .catch((err) => {
- console.error('请求轨迹数据失败:', err);
- this.showInfo("网络请求失败,请检查网络");
- });
- },
-
- planRoute(isReplan = false) {
- const { startPoint, destination } = this.data;
-
- if (!startPoint || !destination) {
- this.showInfo("无法规划路线:起点或终点信息不完整");
- return;
- }
-
- if (isReplan) {
- this.setData({ isReplanning: true });
- this.showInfo("正在重新规划路线...");
- } else {
- this.showInfo("正在规划路线...");
- }
-
- this.mapSdk.direction({
- mode: 'driving',
- policy: 'REAL_TRAFFIC',
- from: { latitude: startPoint.latitude, longitude: startPoint.longitude },
- to: { latitude: destination.latitude, longitude: destination.longitude },
- success: (res) => {
- console.log("路线规划结果:", res);
-
- if (res.status == 0 && res.result.routes.length > 0) {
- const result = res.result;
- const route = result.routes[0];
- // 计算预计到达时间
- const durationMinutes = Math.ceil(result.routes[0].duration);
- const now = new Date();
- now.setMinutes(now.getMinutes() + durationMinutes);
-
- // 格式化时间(HH:MM)
- const estimatedArrivalTime = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`;
- const estimatedDuration = `${durationMinutes}分钟`;
-
- // 提取路线点
- const coors = route.polyline;
- const pl = [];
-
- // 坐标解压(返回的点串坐标,通过前向差分进行压缩)
- const kr = 1000000;
- for (let i = 2; i < coors.length; i++) {
- coors[i] = Number(coors[i - 2]) + Number(coors[i]) / kr;
- }
-
- // 将解压后的坐标放入点串数组pl中
- for (let i = 0; i < coors.length; i += 2) {
- pl.push({
- latitude: coors[i],
- longitude: coors[i + 1]
- });
- }
-
- // 更新路线数据
- const distance = (result.routes[0].distance / 1000).toFixed(1);
-
- this.setData({
- estimatedArrivalTime,
- estimatedDuration,
- plannedRoute: [{
- name: this.data.orderdata.poiName,
- points: pl,
- color: '#2f693c',
- width: 6,
- borderColor: '#2f693c',
- borderWidth: 1,
- arrowLine: true
- }],
- routePlanned: true,
- isReplanning: false,
- deviationCount: 0,
- distance
- });
-
- // 显示规划结果(区分司机/用户端提示)
- const message = this.data.isDriver
- ? (isReplan ? `已重新规划路线,距离${distance}公里,预计${estimatedDuration}后到达` : `距离${distance}公里,预计${estimatedDuration}后到达`)
- : (isReplan ? `已重新规划路线,距离${distance}公里,约${Math.ceil(result.routes[0].duration)}分钟` : `距离${distance}公里,约${Math.ceil(result.routes[0].duration)}分钟`);
-
- console.log(message);
- this.showInfo(message);
- } else {
- this.setData({ isReplanning: false });
- this.showInfo("路线规划失败,请重试");
- }
- },
- fail: (err) => {
- console.error("路线规划失败:", err);
- this.setData({ isReplanning: false });
- this.showInfo("路线规划失败,请检查网络");
- }
- });
- },
-
- // 获取历史轨迹线(司机端主动更新自身轨迹)
- historytrajectory() {
- // 工单未分配时不获取轨迹
- if (this.data.orderdata.workorderType < 1) return;
-
- const data = {
- workorderId: this.data.optionsid
- };
-
- api.request(`/sysworkorder/selectworkorderredis`, 'post', data, { isPublic: false })
- .then((response) => {
-
- // 兼容处理:检查返回数据是否有效
- if (!response.data || response.data.length === 0) {
- console.log('未获取到轨迹数据或轨迹数据为空');
- this.handleEmptyTrajectory();
- return;
- }
-
- if (response.code == 200 && response.data.length > 0) {
- response.data = [...response.data].reverse();
- console.log('历史轨迹:', response.data);
- // 司机端和用户端统一从[0]获取最新位置
- this.updateDriverLocation(response.data[response.data.length-1]);
-
- // 如果有多个轨迹点,更新轨迹线
- if (response.data.length > 0) {
- const trackPoints = response.data.map(point => ({
- longitude: point.longitude*1,
- latitude: point.latitude*1
- }));
-
- this.setData({
- polyline: [{
- points: trackPoints,
- color: "#ff0000",
- width: 6,
- dottedLine: false
- }]
- });
- console.log(trackPoints);
- if (trackPoints.length<2) {
- this.mapCtx.includePoints({
- points:[this.data.destination,...trackPoints],
- padding: [100, 100, 100, 100] // 适配屏幕边距
- });
- }
-
- } else {
- // 如果只有一个轨迹点(通常是司机的当前位置),则只更新司机位置,不绘制轨迹线-
- console.log('只有一个轨迹点,不绘制轨迹线');
- this.setData({
- polyline: [{ points: [] }] // 清空轨迹线
- });
- }
- } else {
- // 服务器返回非200状态码或数据格式不正确
- // console.warn('获取轨迹数据失败,服务器返回:', response);
- this.handleEmptyTrajectory();
- }
- })
- .catch((err) => {
- console.error('获取历史轨迹失败:', err);
- // 司机端额外提示
- if (this.data.isDriver) {
- this.showInfo("轨迹更新失败,已自动重试");
- }
- });
- },
-
- /**
- * 处理空轨迹数据的情况
- */
- handleEmptyTrajectory() {
- // 清空轨迹线,避免显示旧的轨迹
- this.setData({
- polyline: [{ points: [] }]
- });
-
- // 根据角色给出不同的提示
- if (this.data.isDriver) {
- // 司机端:可能是刚接单,还未开始上传位置
- this.showInfo("尚未记录轨迹,请开始行驶或检查定位");
- } else {
- // 用户端:司机可能还未出发或未上传位置
- this.showInfo("司机尚未开始行驶或位置信息未更新");
- }
- },
-
- updateDriverLocation(newDriverLocation) {
- // 工单未分配时不更新司机位置
- if (this.data.orderdata.workorderType < 1) return;
-
- if (!newDriverLocation) return;
-
- // 更新司机位置数据
- this.setData({
- driverLocation: newDriverLocation
- });
-
- // 获取当前标记数组
- const markers = [...this.data.markers];
- // 找到司机标记(id:2)并更新位置
- const driverMarkerIndex = markers.findIndex(marker => marker.id == 2);
-
- if (driverMarkerIndex !== -1) {
- // 更新司机标记位置
- markers[driverMarkerIndex] = {
- ...markers[driverMarkerIndex],
- longitude: newDriverLocation.longitude,
- latitude: newDriverLocation.latitude
- };
- this.setData({ markers });
- } else {
- // 如果司机标记不存在,很可能是地图还没初始化好
- // 可以选择重新设置目的地来创建标记,或者给出提示
- console.warn('司机标记不存在,尝试重新设置目的地');
- // 这里可以加一个防抖(debounce),避免短时间内多次调用
- if (!this.setDestinationTimer) {
- this.setDestinationTimer = setTimeout(() => {
- this.setDestination();
- this.setDestinationTimer = null;
- }, 500);
- }
- }
- },
-
- // 显示信息提示(区分司机/用户端)
- showInfo(text) {
- this.setData({ infoText: text });
-
- // 3秒后自动隐藏非状态类信息(司机端状态类信息保留更久)
- const delay = this.data.isDriver && (text.includes("定位") || text.includes("轨迹") || text.includes("到达")) ? 5000 : 3000;
-
- if (!text.includes("正在") && !text.includes("距离") && !text.includes("偏离")) {
- setTimeout(() => {
- if (this.data.infoText == text) {
- this.setData({ infoText: "" });
- }
- }, delay);
- }
- },
-
- // 导航功能(司机端默认开启导航)
- navigation() {
- if (!this.data.destination) {
- this.showInfo("目的地尚未设置");
- return;
- }
-
- // 使用在腾讯位置服务申请的key
- const key = this.data.qqMapKey;
- const referer = '电速宝';
- const enableAI = true;
- const navigation = 1; // 强制开启导航
- const endPoint = JSON.stringify({
- name: this.data.orderdata.poiName || '目的地',
- 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}`,
- fail: (err) => {
- console.error('导航启动失败', err);
- // 1. 判断失败原因:插件未安装/不存在(核心逻辑)
- const isPluginNotExist = err.errMsg.includes('plugin not found') || err.errMsg.includes('找不到插件') || err.errMsg.includes('navigateTo:fail');
-
- if (isPluginNotExist) {
- // 2. 提示用户下载腾讯地图
- wx.showModal({
- title: '提示',
- content: '未检测到腾讯地图应用,是否前往应用商店下载?',
- confirmText: '去下载',
- cancelText: '取消',
- success: (res) => {
- if (res.confirm) {
- // 3. 跳转到腾讯地图下载页(区分iOS/Android)
- // iOS下载链接(App Store)
- const iosUrl = 'https://apps.apple.com/cn/app/%E8%85%BE%E8%AE%AF%E5%9C%B0%E5%9B%BE/id414478124';
- // Android下载链接(腾讯应用宝,也可换应用宝/华为应用市场等)
- const androidUrl = 'https://a.app.qq.com/o/simple.jsp?pkgname=com.tencent.map';
-
- wx.navigateToMiniProgram({
- // 备选方案:直接打开外部下载链接(需小程序配置业务域名)
- // 优先用openURL,兼容更多场景
- url: '',
- fail: () => {
- wx.openURL({
- url: wx.getSystemInfoSync().system.includes('iOS') ? iosUrl : androidUrl,
- fail: () => {
- this.showInfo('下载链接打开失败,请手动前往应用商店搜索“腾讯地图”下载');
- }
- });
- }
- });
- } else {
- // 用户取消下载,提示手动导航
- this.showInfo(this.data.isDriver ? "导航启动失败,请手动开启腾讯地图导航" : "导航启动失败");
- }
- }
- });
- } else {
- // 非插件未安装的其他失败原因(如参数错误、网络问题)
- this.showInfo(this.data.isDriver ? "导航启动失败,请手动开启" : "导航启动失败");
- }
- }
- });
- },
-
- // 封装的提示方法(保持原有逻辑)
- showInfo(msg) {
- wx.showToast({
- title: msg,
- icon: 'none',
- duration: 2000
- });
- },
-
-
- // 重新发送验证码
- onResendCode() {
- // 调用发送验证码接口
- this.showVerificationPopup();
- this.startCountdown(); // 重启倒计时
- wx.showToast({ title: '验证码已发送', icon: 'none' });
- // wx.request({
- // url: 'https://your-api.com/sendCode',
- // success: () => {
- // this.startCountdown(); // 重启倒计时
- // wx.showToast({ title: '验证码已发送', icon: 'none' });
- // }
- // });
- },
-
- // 验证码倒计时
- startCountdown() {
- let countdown = 60;
- this.setData({ canResend: false, countdown });
- const timer = setInterval(() => {
- countdown--;
- this.setData({ countdown });
- if (countdown <= 0) {
- clearInterval(timer);
- this.setData({ canResend: true, countdown: 60 });
- }
- }, 1000);
- },
- // 显示验证码弹窗(司机端无需验证码,直接执行操作)
- showVerificationPopup() {
- // 用户端正常显示验证码
- const data = { workorderId: this.data.optionsid };
-
- api.request(`/sysworkorder/createverify`, 'post', data, { isPublic: false })
- .then((data) => {
- if (data.code == 200) {
- wx.showToast({ title: data.msg || '验证码已发送', icon: 'none' });
- this.setData({
- showCodePopup: true,
- canResend: false
- });
- // 启动倒计时
- this.startCountdown();
- } else {
- this.showInfo(data.msg || '获取验证码失败');
- }
- })
- .catch((err) => {
- console.error('获取验证码失败:', err);
- this.showInfo('获取验证码失败');
- });
- },
-
- // 关闭弹窗
- onCodePopupClose() {
- this.setData({ showCodePopup: false });
- setTimeout(() => {
- const slideComponent = this.selectComponent("#mySlideConfirm");
- if (slideComponent) {
- slideComponent.reset();
- }
- }, 1000);
- },
-
- // 确认验证码(仅用户端有效)
- onCodeConfirm(e) {
- if (!this.data.isDriver) {
- console.log("确认验证码:", e.detail.code);
- this.setData({ showVerification: false });
- }
- },
-
- // 重新发送验证码(仅用户端有效)
- // onResendCode() {
- // if (!this.data.isDriver) {
- // console.log("重新发送验证码");
- // this.showVerificationPopup();
- // }
- // },
-
- // 验证码输入完成
- onCodeInputComplete(e) {
-
- console.log(e);
- const code = e.detail.value;
- console.log(code);
-
-
- const data = {
- carId: this.data.carId,
- verifyCode: code,
- workorderId: this.data.orderdata.workorderId
- };
-
- api.request(`/sysworkorder/submitworkorder`, 'post', data, { isPublic: false })
- .then((data) => {
- if (data.code == 200) {
- wx.showToast({ title: '验证码正确', icon: 'success' });
- this.setData({ showCodePopup: false });
- } else {
- const codePopup = this.selectComponent('.code-popup');
- codePopup.triggerErrorShake();
- wx.showToast({ title: res.data.msg || '验证码错误', icon: 'none' });
- }
- })
- .catch((err) => {
- console.error('验证请求失败:', err);
- this.showInfo('验证请求失败');
-
- setTimeout(() => {
- const slideComponent = this.selectComponent("#mySlideConfirm");
- if (slideComponent) {
- slideComponent.reset();
- }
- }, 5000);
- });
- },
- onrecognize(e){
- console.log(1111111);
- const that = this;
- // 检查设备是否支持生物认证--
- wx.checkIsSupportSoterAuthentication({
- success(res) {
- console.log(res.supportMode.includes('facial'));
- console.log(res.supportMode.includes('fingerPrint'));
- if (res.supportMode.includes('facial')) {
- // 支持人脸识别(FaceID)
- wx.startSoterAuthentication({
- requestAuthModes: ['facial'],
- challenge:e.currentTarget.dataset.type,
- authContent: '请进行人脸识别验证',
- success(res) {
- console.log('验证成功', res);
- that.onSlideSuccess()
- },
- fail(err) {
- setTimeout(() => {
- const slideComponent = that.selectComponent("#mySlideConfirm");
- if (slideComponent) {
- slideComponent.reset();
- }
- }, 5000);
- }
- });
- }
- if(res.supportMode.includes('fingerPrint')) {
- // 支持人脸识别(FaceID)
- wx.startSoterAuthentication({
- requestAuthModes: ['fingerPrint'],
- challenge:e.currentTarget.dataset.type,
- authContent: '请进行指纹识别验证',
- success(res) {
- console.log('验证成功', res);
- that.onSlideSuccess()
-
- },
- fail(err) {
- console.log(err);
- setTimeout(() => {
- const slideComponent = that.selectComponent("#mySlideConfirm");
- if (slideComponent) {
- slideComponent.reset();
- }
- }, 5000);
- }
- });
- }
- }
- });
- },
- onarrivalposition(){
- const data = {
- carId: this.data.orderdata.carId,
- verifyCode: '',
- workorderId: this.data.orderdata.workorderId
- };
- api.request(`/sysworkorder/submitworkorder`, 'post', data, { isPublic: false })
- .then((data) => {
- if (data.code == 200) {
- setTimeout(() => {
- const slideComponent = this.selectComponent("#mySlideConfirm");
- if (slideComponent) {
- slideComponent.reset();
- }
- }, 5000);
- app.stopDriverLocationUpload(this.data.optionsid);
-
- } else {
- this.showInfo(data.msg || '操作失败');
- }
- })
- .catch((err) => {
- console.error('操作请求失败:', err);
- this.showInfo('操作请求失败');
-
- setTimeout(() => {
- const slideComponent = this.selectComponent("#mySlideConfirm");
- if (slideComponent) {
- slideComponent.reset();
- }
- }, 5000);
- });
- },
-
- onSlideSuccess() {
- // console.log(e.currentTarget.dataset.type);
- // const type = e.currentTarget.dataset.type;
-
- const data = {
- carId: this.data.orderdata.carId,
- verifyCode: '',
- workorderId: this.data.orderdata.workorderId
- };
-
- api.request(`/sysworkorder/submitworkorder`, 'post', data, { isPublic: false })
- .then((data) => {
- if (data.code == 200) {
- // if (this.data.isDriver && type == 4) {
- // wx.stopLocationUpdateBackground({
- // success: (res) => {
- // console.log('后台定位已停止', res);
- // this.showInfo(this.data.isDriver ? '已停止定位追踪' : '已停止位置追踪');
- // },
- // fail: (err) => {
- // console.error('停止后台定位失败', err);
- // },
- // });
- // wx.offLocationChange();
- // }
- setTimeout(() => {
- const slideComponent = this.selectComponent("#mySlideConfirm");
- if (slideComponent) {
- slideComponent.reset();
- }
- }, 5000);
- } else {
- this.showInfo(data.msg || '操作失败');
- }
- })
- .catch((err) => {
- console.error('操作请求失败:', err);
- this.showInfo('操作请求失败');
-
- setTimeout(() => {
- const slideComponent = this.selectComponent("#mySlideConfirm");
- if (slideComponent) {
- slideComponent.reset();
- }
- }, 5000);
- });
- },
-
- ontelephone(e) {
- const phoneNumber = e.currentTarget.dataset.phone;
-
- if (!phoneNumber) {
- this.showInfo('电话号码无效');
- return;
- }
-
- wx.showModal({
- title: '确认拨打电话',
- content: `是否拨打${phoneNumber}?`,
- success: (res) => {
- if (res.confirm) {
- wx.makePhoneCall({
- phoneNumber: phoneNumber,
- fail: (err) => {
- console.error('拨打电话失败', err);
- this.showInfo('拨打电话失败');
- }
- });
- }
- }
- });
- },
-
- onmore() {
- this.setData({ moretype: !this.data.moretype });
- },
-
- oncostdetails() {
- this.setData({ costdetails: !this.data.costdetails });
- },
-
- // 拖动功能(司机端默认展开行程详情)
- handleTouchStart(e) {
- this.setData({ startY: e.changedTouches[0].clientY });
- },
-
- handleTouchMove(e) {
- const currentY = e.changedTouches[0].clientY;
- const deltaY = currentY - this.data.startY;
- const { min, max } = this.data.heightConfig;
-
- let newHeight = this.data.currentHeight - deltaY;
- newHeight = Math.max(min, Math.min(max, newHeight));
-
- let maskOpacity = this.data.maskOpacity;
- if (newHeight < max && newHeight > min) {
- maskOpacity = 0.3 + (newHeight - min) / (this.data.heightConfig.mid - min) * 0.2;
- } else {
- maskOpacity = 0;
- }
-
- this.setData({ currentHeight: newHeight, maskOpacity, startY: currentY });
- },
-
- handleTouchEnd() {
- const { currentHeight } = this.data;
- const { min, mid, max } = this.data.heightConfig;
-
- const distToMin = Math.abs(currentHeight - min);
- const distToMid = Math.abs(currentHeight - mid);
- const distToMax = Math.abs(currentHeight - max);
-
- let targetHeight, targetMode;
- if (distToMax <= 80) {
- targetHeight = max;
- targetMode = 'max';
- } else if (distToMin <= 50) {
- targetHeight = min;
- targetMode = 'min';
- } else if (distToMid <= 60) {
- targetHeight = mid;
- targetMode = 'mid';
- } else {
- const minDist = Math.min(distToMin, distToMid, distToMax);
- if (minDist == distToMin) {
- targetHeight = min;
- targetMode = 'min';
- } else if (minDist == distToMid) {
- targetHeight = mid;
- targetMode = 'mid';
- } else {
- targetHeight = max;
- targetMode = 'max';
- }
- }
-
- this.setData({
- currentHeight: targetHeight,
- cardHeight: targetMode,
- maskOpacity: targetMode == 'mid' ? 0.5 : 0
- });
- },
-
- closeCard() {
- this.setData({
- currentHeight: this.data.heightConfig.min,
- cardHeight: 'min',
- maskOpacity: 0
- });
- },
-
- closeFullscreen() {
- this.setData({
- currentHeight: this.data.heightConfig.min,
- cardHeight: 'min',
- maskOpacity: 0
- });
- },
-
- // 编辑工单
- editorder(){
- wx.navigateTo({
- url: `/package-order/pages/createorder/index?order=${this.data.optionsid}`,
- })
- },
- cancel(){
- let _this = this
- // 在页面的 js 文件中
- wx.showModal({
- title: '提示',
- content: '确定要取消工单吗?',
- success (res) {
- if (res.confirm) {
- console.log('用户点击了确定')
- // 在这里执行确认后的操作selectcarall selectcarall
- let data ={
- workorderId:_this.data.optionsid,
- workorderType:6
- }
- api.request(`/sysworkorder/updateworkorder`, 'post', data, { isPublic: false })
- .then((data) => {
- if (data.code == 200) {
- wx.switchTab({
- url: '/pages/tool/index',
- })
- }
- })
- .catch((err) => {
- this.showInfo('操作失败');
- });
- } else if (res.cancel) {
- this.showInfo('取消操作');
-
- }
- }
- })
- },
- /**
- * 复制目的地地址
- */
- copyDestination() {
- // 1. 获取目的地名称,做空值校验
- const poiName = this.data.orderdata?.poiName || '';
- if (!poiName.trim()) {
- wx.showToast({
- title: '暂无目的地地址可复制',
- icon: 'none',
- duration: 2000
- });
- return;
- }
-
- // 2. 调用微信API复制到剪贴板
- wx.setClipboardData({
- data: poiName, // 要复制的地址内容
- success: () => {
- // 复制成功提示
- wx.showToast({
- title: '地址已复制',
- icon: 'success',
- duration: 2000
- });
- },
- fail: (err) => {
- // 复制失败兜底提示
- console.error('复制地址失败', err);
- wx.showToast({
- title: '复制失败,请手动复制',
- icon: 'none',
- duration: 2000
- });
- }
- });
- },
- // 微信结算
- onpay(){
- this.setData({
- showpayment:true
- })
-
-
-
- },
- // 关闭结算弹窗
- onpaymentPopupClose() {
- this.setData({ showpayment: false });
- },
-
- // 接收结算弹窗输入完成的密码
- onpaymentInputComplete(e) {
- const paymentPwd = e.detail.value; // 获取弹窗输入的6位结算密码
- // 执行父组件的检验逻辑(替换为你的真实接口/校验)
- this.checkPaymentPwd(paymentPwd);
- },
-
- // 检验结算密码(父组件核心检验逻辑)
- checkPaymentPwd(pwd) {
- console.log(pwd);
- let password = {
- password:pwd
- }
- api.request(`/SysBalance/verifypassword`, 'post', password, { isPublic: false })
- .then((data) => {
- if (data.data) {
-
- }else{
- // 检验失败:触发弹窗晃动+清空
- const paymentPopup = this.selectComponent('.payment-popup');
- paymentPopup.triggerErrorShake(); // 调用弹窗的失败动效方法
- // 提示错误信息
- wx.showToast({ title:'' || '结算密码错误', icon: 'none' });
- return
-
- }
- })
- .catch((err) => {
- this.showInfo('操作失败');
- });
-
- let data ={
- workorderId:this.data.optionsid,
- price:this.data.orderdata.price
- }
- api.request(`/sysworkorder/updatesettlementtype`, 'post', data, { isPublic: false })
- .then((data) => {
- if (data.code == 200) {
- wx.showToast({ title: '结算密码正确', icon: 'success' });
- this.setData({ showpayment: false }); // 关闭弹窗
- this.getoneworkorderdetails();
- // wx.navigateTo({
- // url: `/package-user/pages/privacy/index?name=微信结算`,
- // })
-
-
- }
- })
- .catch((err) => {
- this.showInfo('操作失败');
- });
-
- },
-
-
- });
|