<template> <view class="page"> <u-navbar title="订单详情" :border-bottom="false" :background="bgc" title-color='#000' title-size='36' height='45'></u-navbar> <map class="map" id="map" ref="map" :scale="zoomSize" :latitude="latitude" :longitude="longitude" :show-location='true' :markers="markers" :polygons="polygons" :polyline="polyline"> </map> <view class="park" @click="toggleIconAndCallout"> <image src="https://lxnapi.ccttiot.com/bike/img/static/uRiYQZQEb3l2LsltEsyW" mode=""></image> </view> <!-- <map class="map" id="map" ref="map" \> </map> --> <view class="bot_btn" v-if="false"> <view class="time"> 骑行时间30分钟9秒 </view> <view class="price"> 4.00<span>元</span> </view> <view class="toinfo"> 查看骑行费明细 > </view> <view class="btn"> 去支付 </view> </view> <view class="bot" v-if="loading"> <view class="card"> <view class="top"> <view class="topcont"> <view class="left"> {{orderInfo.totalFee}}<span style="font-size: 24rpx;">元</span> </view> <view class="right" @click="topage(2)" style="display: flex;flex-wrap: nowrap;align-items: center;"> 费用明细<view class="iconfont icon-xiangyou1" style="font-size: 24rpx;"></view> </view> </view> <view class="info"> <view class="type"> 电单车 </view> <view class="data" style="font-size: 26rpx;"> {{orderInfo.createTime}} </view> </view> <view class="topcont" style="margin-top: 32rpx;"> <view class="left" style="font-size:26rpx ;"> 订单时长 </view> <view class="right" style="font-size:26rpx ;"> {{computedList(orderInfo)}} </view> </view> <view class="topcont" style="margin-top: 14rpx;"> <view class="left" style="font-size:26rpx ;"> 骑行距离 </view> <view class="right" style="font-size:26rpx ;" v-if="orderInfo.distance"> <!-- {{orderInfo.distance}}公里 --> {{ (orderInfo.distance / 1000).toFixed(2) }} 公里 </view> <view class="right" style="font-size:26rpx ;" v-else> --公里 </view> </view> </view> <view class="bottom" @click="topage(1)"> <view class="text" style="display: flex;flex-wrap: nowrap;align-items: center;"> 故障上报 <view class="iconfont icon-xiangyou1" style="font-size: 26rpx;"></view> </view> </view> </view> <view class="paybtn" v-if="orderInfo.status==3&&orderInfo.paid==0" @click="topay1()"> 去支付 </view> <view class="kefus"> <view class="txt1"> 对订单有疑问? </view> <view class="btn1" @click="showkf=true"> 联系客服 </view> </view> </view> <u-mask :show="show" @click="show = false" :z-index='100' /> <u-mask :show="showkf" :z-index='100' /> <view class="kfbox" v-if="showkf"> <view class="tit"> 请选择您要联系的客服 </view> <view class="words"> 我们根据选择为您提供服务 </view> <!-- <view class="phone_box"> <view class="img"> <image src="https://lxnapi.ccttiot.com/bike/img/static/uwiRmed6Kz4OUJh00HBD" mode=""></image> </view> <view class="info"> <view class="name"> 官方客服 </view> <view class="phone"> 000-260-1559 </view> </view> </view> --> <view class="phone_box" v-if="areaInfo.serviceName1!=''&&areaInfo.serviceName1&&areaInfo.servicePhone1!=''&&areaInfo.servicePhone1" @click="callPhone(areaInfo.servicePhone1)"> <view class="img"> <image src="https://lxnapi.ccttiot.com/bike/img/static/unsZOLTPuYrpQKF8MpFt" mode=""></image> </view> <view class="info"> <view class="name"> {{areaInfo.serviceName1}} </view> <view class="phone"> {{areaInfo.servicePhone1}} </view> </view> </view> <view class="phone_box" v-if="areaInfo.serviceName2!=''&&areaInfo.serviceName2&&areaInfo.servicePhone2!=''&&areaInfo.servicePhone2" @click="callPhone(areaInfo.servicePhone2)"> <view class="img"> <image src="https://lxnapi.ccttiot.com/bike/img/static/unsZOLTPuYrpQKF8MpFt" mode=""></image> </view> <view class="info"> <view class="name"> {{areaInfo.serviceName2}} </view> <view class="phone"> {{areaInfo.servicePhone2}} </view> </view> </view> <view class="phone_box" v-if="areaInfo.serviceName3!=''&&areaInfo.serviceName3&&areaInfo.servicePhone3!=''&&areaInfo.servicePhone3" @click="callPhone(areaInfo.servicePhone3)"> <view class="img"> <image src="https://lxnapi.ccttiot.com/bike/img/static/unsZOLTPuYrpQKF8MpFt" mode=""></image> </view> <view class="info"> <view class="name"> {{areaInfo.serviceName3}} </view> <view class="phone"> {{areaInfo.servicePhone3}} </view> </view> </view> <image class="close" src="https://lxnapi.ccttiot.com/bike/img/static/ulwJylk0JSmOdmU3FnnG" mode="" @click="showkf=false"></image> </view> <!-- <image class="kefu" src="https://lxnapi.ccttiot.com/bike/img/static/u8osHvZfHL7u3lbveVXx" mode="" @click="showkf=true"></image> --> </view> </template> <script> export default { data() { return { bgc: { backgroundColor: "#F7FAFE", }, latitude: 0, longitude: 0, isMap: false, zoomSize: 18, markers: [], polyline: [{ points: [], width: 8, arrowLine: true, color: '#00AF99' // strokeWidth: 2, // strokeColor: '#00AF99', // fillColor: '#00AF99' }, ], polygons: [], cardId: '001区域', orderId: '', orderInfo: {}, loading: false, showIconAndCallout: false, ispaid: false, _mapContext: null, showkf: false, areaInfo: {}, } }, created() { this._mapContext = uni.createMapContext("map", this); //map为map组件id }, onLoad(e) { this.orderId = e.id this.getOrderDetail() }, components: { }, methods: { callPhone(phone){ this.isbackcar=false uni.makePhoneCall({ phoneNumber:phone }) setTimeout(()=>{ this.showkf=false },500) }, // 骑行结束支付 topay1() { if (this.ispaid == false) { this.ispaid = true let data = { userId: this.orderInfo.userId, sn: this.orderInfo.sn, orderNo: this.orderInfo.orderNo, // money: this.freeInfo.fee, mark: "订单支付", type: '1' } uni.showLoading({ }) console.log('点击了'); let that = this this.$u.post('/appVerify/pre/order', data).then((res) => { if (res.code === 200) { uni.hideLoading() // this.freList=res.rows uni.requestPayment({ provider: 'wxpay', timeStamp: res.data.timeStamp, nonceStr: res.data.nonceStr, package: res.data.packageVal, signType: res.data.signType, paySign: res.data.paySign, success(res) { that.ispaid = false // console.log('支付成功'); // // 支付成功逻辑 // clearInterval(that.timer) // that.orderinfo = {} // that.showdevice = false // that.deviceIndex = 0 that.getOrderDetail() }, fail(err) { that.ispaid = false // 支付失败逻辑 uni.showToast({ title: '支付失败', icon: 'none', duration: 2000 }); } }); } else { that.ispaid = false uni.showToast({ title: res.msg, icon: 'none', duration: 2000 }); } }) } }, topage(num) { if (num == 1) { uni.navigateTo({ url: '/page_user/gzsb?sn=' + this.orderInfo.sn }) } else if (num == 2) { uni.navigateTo({ url: '/page_user/ckmx?orderId=' + this.orderInfo.orderNo }) } }, computedList(item) { if (item.status == 0 || item.status == 2) { const createTime = new Date(item.createTime); const payTime = Date.now(); const timeDifference = Math.abs(createTime - payTime); const hours = Math.floor(timeDifference / (1000 * 60 * 60)); const minutes = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((timeDifference % (1000 * 60)) / 1000); let result = ''; if (hours > 0) { result += `${hours}小时`; } if (minutes > 0 || hours > 0) { // 显示分钟条件:有小时或者有分钟 result += `${minutes}分钟`; } // result += `${seconds}秒`; // 始终显示秒 return result; } else { const createTime = new Date(item.createTime); const payTime = new Date(item.returnTime); const timeDifference = Math.abs(createTime - payTime); const hours = Math.floor(timeDifference / (1000 * 60 * 60)); const minutes = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((timeDifference % (1000 * 60)) / 1000); let result = ''; if (hours > 0) { result += `${hours}小时`; } if (minutes > 0 || hours > 0) { // 显示分钟条件:有小时或者有分钟 result += `${minutes}分钟`; } // result += `${seconds}秒`; // 始终显示秒 return result; } }, convertBoundaryToPolyline(boundary) { if (!boundary) return null; const points = JSON.parse(boundary).map(coord => ({ latitude: coord[1], longitude: coord[0] })); const polyline = { points: points, fillColor: "#55888840", //填充颜色 strokeColor: "#22FF00", //描边颜色 strokeWidth: 2, //描边宽度 zIndex: 1, //层级 }; return polyline; }, convertBoundaryToPolyliness(boundary) { if (!boundary) return null; const points = JSON.parse(boundary).map(coord => ({ latitude: coord[1], longitude: coord[0] })); const polyline = { points: points, width: 8, arrowLine: true, color: '#00AF99' }; return polyline; }, convertBoundaryToPolylines(boundaries, num) { if (num == 1) { console.log('判断'); return boundaries.map(boundary => { if (!boundary) return null; let coords; try { coords = JSON.parse(boundary); } catch (error) { console.error("Error parsing boundary JSON:", error); return null; } if (!Array.isArray(coords)) { console.error("Parsed boundary is not an array:", coords); return null; } const points = coords.map(coord => ({ latitude: coord[1], longitude: coord[0] })); return { points: points, fillColor: "#3A7EDB40", //填充颜色 strokeColor: "#3A7EDB", //描边颜色 strokeWidth: 2, //描边宽度 zIndex: 1, //层级 }; }).filter(polyline => polyline !== null); // 过滤掉无效的折线数据 } else if (num == 2) { return boundaries.map(boundary => { if (!boundary) return null; let coords; try { coords = JSON.parse(boundary); } catch (error) { console.error("Error parsing boundary JSON:", error); return null; } if (!Array.isArray(coords)) { console.error("Parsed boundary is not an array:", coords); return null; } const points = coords.map(coord => ({ latitude: coord[1], longitude: coord[0] })); return { points: points, fillColor: "#FFF5D640", //填充颜色 strokeColor: "#FFC107", //描边颜色 strokeWidth: 2, //描边宽度 zIndex: 1, //层级 }; }).filter(polyline => polyline !== null); // 过滤掉无效的折线数据 } else if (num == 3) { return boundaries.map(boundary => { if (!boundary) return null; let coords; try { coords = JSON.parse(boundary); } catch (error) { console.error("Error parsing boundary JSON:", error); return null; } if (!Array.isArray(coords)) { console.error("Parsed boundary is not an array:", coords); return null; } const points = coords.map(coord => ({ latitude: coord[1], longitude: coord[0] })); return { points: points, fillColor: "#FFD1CF40", //填充颜色 strokeColor: "#FF473E", //描边颜色 strokeWidth: 2, //描边宽度 zIndex: 1, //层级 }; }).filter(polyline => polyline !== null); // 过滤掉无效的折线数据 } }, getParking() { // 发送请求获取数据 let data = { areaId: this.orderInfo.areaId } this.$u.get('/app/parking/list?', data).then((res) => { if (res.code === 200) { // 处理接口返回的数据 const type1Data = []; const type2Data = []; const type3Data = []; res.rows.forEach(row => { if (row.type == 1) { type1Data.push(row); } else if (row.type == 2) { type2Data.push(row); } else if (row.type == 3) { type3Data.push(row); } }); const validBoundaries = type1Data.map(row => row.boundaryStr).filter(boundary => typeof boundary === 'string' && boundary.trim() !== ''); const polylines = this.convertBoundaryToPolylines(validBoundaries, 1); const validBoundaries1 = type2Data.map(row => row.boundaryStr).filter(boundary => typeof boundary === 'string' && boundary.trim() !== ''); const polylines1 = this.convertBoundaryToPolylines(validBoundaries1, 2); const validBoundaries2 = type3Data.map(row => row.boundaryStr).filter(boundary => typeof boundary === 'string' && boundary.trim() !== ''); const polylines2 = this.convertBoundaryToPolylines(validBoundaries2, 3); // 将处理后的数据添加到 this.polyline 中 this.polygons = this.polygons.concat(polylines2); this.polygons = this.polygons.concat(polylines1); this.polygons = this.polygons.concat(polylines); // console.log(this.polyline); this.parkingList = res.rows } }).catch(error => { console.error("Error fetching parking data:", error); }); }, toggleIconAndCallout() { this.showIconAndCallout = !this.showIconAndCallout; if (this.showIconAndCallout) { const newMarkers = []; this.parkingList.forEach(item => { newMarkers.push({ id: parseFloat(item.parkingId), latitude: parseFloat(item.latitude), longitude: parseFloat(item.longitude), width: 20, height: 28.95, iconPath: item.type == 1 ? 'https://lxnapi.ccttiot.com/bike/img/static/up2xXqAgwCX5iER600k3' : item .type == 2 ? 'https://lxnapi.ccttiot.com/bike/img/static/u53BAQcFIX3vxsCzEZ7t' : ' https://lxnapi.ccttiot.com/bike/img/static/uDNY5Q4zOiZTCBTA2Jdq', callout: { content: item.parkingName, color: '#ffffff', fontSize: 14, borderRadius: 10, bgColor: item.type == 1 ? '#3A7EDB' : item.type == 2 ? '#FFC107' : '#FF473E', padding: 6, display: 'ALWAYS' }, isCalloutVisible: true // 添加标记 }); }); this.$set(this, 'markers', [...this.markers, ...newMarkers]); } else { // 过滤掉所有气泡显示的标记 this.$set(this, 'markers', this.markers.filter(marker => !marker.isCalloutVisible)); } }, getArea() { // this.$u.get("/app/area/" + this.orderInfo.areaId).then((res) => { this.$u.get("/app/area/" + this.orderInfo.areaId).then((res) => { if (res.code == 200) { this.areaInfo = res.data const polylines = this.convertBoundaryToPolyline(res.data.boundaryStr) // 更新折线数据 this.polygons.push(polylines) this.getParking() console.log(this.polygons, 'polylinespolylines'); } else { // uni.showToast({ // title: res.msg, // icon: 'none', // duration: 2000 // }); } }); // 发送请求获取数据 }, status() { if (this.orderInfo != '') { if (this.orderInfo.status == 0) { return '预约中' } else if (this.orderInfo.status == 1) { return '取消预约' } else if (this.orderInfo.status == 2) { return '开始骑行' } else if (this.orderInfo.status == 3) { return '骑行结束' } else if (this.orderInfo.status == 4) { return '订单完成' } } }, getOrderDetail() { uni.showLoading({}); this.$u.get('/appVerify/order/' + this.orderId).then((res) => { if (res.code === 200) { this.orderInfo = res.data; this.loading = true; this.getArea(); // if (res.data.tripRouteStr) { // let abb; // try { // abb = JSON.parse(res.data.tripRouteStr); // } catch (error) { // console.error("Error parsing tripRouteStr:", error); // return; // } // if (abb.length > 2) { // this.latitude = parseFloat(abb[0][1]); // this.longitude = parseFloat(abb[0][0]); // this.polyline[0].points = abb.map(coord => ({ // latitude: coord[1], // longitude: coord[0] // })); // this.markers.push({ // id: 0, // latitude: abb[0][1], // longitude: abb[0][0], // width: 25, // height: 38, // iconPath: 'https://lxnapi.ccttiot.com/bike/img/static/u06paUGiHLvL08Pw7BGr' // }, { // id: 1, // latitude: abb[abb.length - 1][1], // longitude: abb[abb.length - 1][0], // width: 25, // height: 38, // iconPath: 'https://lxnapi.ccttiot.com/bike/img/static/uwpAj9vYtPRmhtTOtflx' // }, { // id: 3, // latitude: abb[0][1], // longitude: abb[0][0], // width: 40, // height: 28, // iconPath: 'https://api.ccttiot.com/smartmeter/img/static/uF9qLejuAZErNTrRuHq7' // }); // // Start the track playback // this.translateMarkerFun(abb); // } else { // this.latitude = parseFloat(abb[0][1]); // this.longitude = parseFloat(abb[0][0]); // } // } this.getpolyline() uni.hideLoading(); } }).catch(error => { console.error("Error fetching area data:", error); }); }, getpolyline() { this.$u.post("/system/device/trajectoryByOrderNo?orderNo=" + this.orderId).then((res) => { if (res.code === 200) { this.polyline[0].points = JSON.parse(res.data).map(coord => ({ latitude: coord[1], longitude: coord[0] })); let abb; try { abb = JSON.parse(res.data); console.log(abb, 'abbbb'); } catch (error) { console.error("Error parsing tripRouteStr:", error); return; } if (abb.length > 2) { this.latitude = parseFloat(abb[0][1]); this.longitude = parseFloat(abb[0][0]); this.polyline[0].points = abb.map(coord => ({ latitude: coord[1], longitude: coord[0] })); this.markers.push({ id: 0, latitude: abb[0][1], longitude: abb[0][0], width: 25, height: 38, iconPath: 'https://lxnapi.ccttiot.com/bike/img/static/u06paUGiHLvL08Pw7BGr' }, { id: 1, latitude: abb[abb.length - 1][1], longitude: abb[abb.length - 1][0], width: 25, height: 38, iconPath: 'https://lxnapi.ccttiot.com/bike/img/static/uwpAj9vYtPRmhtTOtflx' }); } } }).catch(error => { console.error("Error fetching area data:", error); }); }, translateMarkerFun(path) { let abb = JSON.parse(this.orderInfo.tripRouteStr); // console.log(abb,'abb'); let formattedPath = path.map(coord => ({ latitude: parseFloat(coord[1]), longitude: parseFloat(coord[0]) })); // console.log(path,'path'); // let totalDistance = this.calculateTotalDistance(path); let baseSpeed = 300; // 设置一个基础速度,单位为距离每秒移动的像素数 // let duration = totalDistance > 0 ? totalDistance * baseSpeed : 60000; // 根据路径长度动态计算持续时间 let duration = abb.length * 300; // console.log(duration,'durationduration',totalDistance); this._mapContext.includePoints({ points: formattedPath, padding: [50, 50, 50, 50], }); this._mapContext.moveAlong({ markerId: 3, path: formattedPath, autoRotate: true, duration: duration, iconPath: 'https://api.ccttiot.com/smartmeter/img/static/uF9qLejuAZErNTrRuHq7', // 回放标记图片 }); this.$forceUpdate(); } } } </script> <style lang="scss"> page { background-color: #F7FAFE; } .page { width: 750rpx; .kefu { position: fixed; right: 30rpx; bottom: 500rpx; width: 82rpx; height: 82rpx; } .kfbox { padding: 48rpx 30rpx; position: fixed; left: 82rpx; top: 410rpx; width: 590rpx; // height: 282rpx; background: #FFFFFF; border-radius: 30rpx 30rpx 30rpx 30rpx; z-index: 110; display: flex; justify-content: center; flex-wrap: wrap; .close { position: relative; bottom: -124rpx; width: 60rpx; height: 60rpx; } .phone_box { margin-top: 32rpx; width: 528rpx; height: 144rpx; background: #FFFFFF; box-shadow: 0rpx 4rpx 22rpx 0rpx rgba(0, 0, 0, 0.1); border-radius: 20rpx 20rpx 20rpx 20rpx; display: flex; flex-wrap: nowrap; align-items: center; .img { width: 86rpx; height: 86rpx; image { width: 86rpx; height: 86rpx; } } .info { display: flex; flex-wrap: wrap; margin-left: 34rpx; .name { width: 100%; font-weight: 600; font-size: 32rpx; color: #3D3D3D; } .phone { width: 100%; font-weight: 400; font-size: 32rpx; color: #3D3D3D; } } } .tit { font-weight: 600; font-size: 40rpx; color: #3D3D3D; } .words { margin-bottom: 42rpx; margin-top: 16rpx; font-weight: 400; font-size: 28rpx; color: #3D3D3D; } } .map { width: 750rpx; height: 100vh; } .park { position: fixed; display: flex; align-items: center; justify-content: center; right: 30rpx; bottom: 650rpx; // background-color: #fff; border-radius: 50%; width: 82rpx; height: 82rpx; z-index: 10; .img { width: 82rpx; height: 82rpx; } } .bot { display: flex; flex-wrap: wrap; justify-content: center; padding: 26rpx 34rpx 48rpx 34rpx; position: fixed; bottom: 0; width: 750rpx; // height: 420rpx; background: #F7F7F7; border-radius: 30rpx; .kefus{ padding: 18rpx 38rpx; margin-top: 20rpx; width: 708rpx; background: #FFFFFF; border-radius: 24rpx 24rpx 24rpx 24rpx; .txt{ font-weight: 400; font-size: 32rpx; color: #3D3D3D; } .btn1{ margin-top: 26rpx; display: flex; align-items: center; justify-content: center; width: 626rpx; height: 88rpx; background: #64B6A7; border-radius: 14rpx 14rpx 14rpx 14rpx; font-weight: 500; font-size: 32rpx; color: #FFFFFF; } } .paybtn { display: flex; align-items: center; justify-content: center; margin-top: 30rpx; border-radius: 20rpx; width: 100%; height: 90rpx; background: #64B6A7; font-weight: 500; font-size: 40rpx; color: #FFFFFF; } .card { width: 708rpx; // height: 320rpx; background: #FFFFFF; border-radius: 32rpx 32rpx 32rpx 32rpx; .top { padding: 26rpx 38rpx; .topcont { display: flex; flex-wrap: nowrap; justify-content: center; justify-content: space-between; .left { font-weight: 500; font-size: 36rpx; color: #3D3D3D; } .right { font-weight: 400; font-size: 26rpx; color: #808080; } } .info { margin-top: 16rpx; display: flex; flex-wrap: nowrap; align-items: center; .type { display: flex; align-items: center; justify-content: center; width: 112rpx; height: 42rpx; background: linear-gradient(90deg, #64B6A7 0%, #64B6A7 50%, #5A9D93 100%); border-radius: 8rpx 8rpx 8rpx 8rpx; font-weight: 500; font-size: 24rpx; color: #FFFFFF; } .data { margin-left: 15rpx; font-weight: 400; font-size: 20rpx; color: #3D3D3D; } } } .bottom { // padding-top: 10rpx; display: flex; align-items: center; justify-content: center; border-top: 2rpx solid #EFEFEF; width: 100%; height: 80rpx; .text { font-weight: 400; font-size: 24rpx; color: #3D3D3D; } } } } .bot_btn { padding: 26rpx 34rpx 48rpx 34rpx; position: fixed; // display: flex; // flex-wrap: wrap; // justify-content: center; bottom: 0; width: 750rpx; height: 420rpx; background: #FFFFFF; box-shadow: 0rpx 10rpx 64rpx 0rpx rgba(0, 0, 0, 0.08); border-radius: 30rpx; .time { // height: 88rpx; width: 100%; text-align: center; padding-bottom: 24rpx; font-weight: 400; font-size: 28rpx; color: #3D3D3D; border-bottom: 2rpx solid #EFEFEF; } .price { margin-top: 22rpx; width: 100%; text-align: center; font-weight: 500; font-size: 72rpx; color: #3D3D3D; span { font-size: 28rpx; font-weight: 500; } } .toinfo { // margin-top: 12rpx; width: 100%; text-align: center; font-weight: 400; font-size: 24rpx; color: #3D3D3D; } .btn { margin-top: 34rpx; display: flex; align-items: center; justify-content: center; width: 680rpx; height: 90rpx; background: #4C97E7; border-radius: 54rpx 54rpx 54rpx 54rpx; font-weight: 500; font-size: 40rpx; color: #FFFFFF; } } } </style>