chuangte_bike_newxcx/pages/index/index.vue
2026-01-15 14:40:00 +08:00

4644 lines
130 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page">
<u-navbar title=" " :border-bottom="false" back-icon-color="000" :background="bgc" title-color='#000'
title-size='36' height='44' id="navbar" :custom-back="btnfh">
</u-navbar>
<view class="gonggao" @click="btntopgg" v-if="ordernum > 1">
<image style="position: absolute;left: 20rpx;width: 20rpx;height: 34rpx;" src="https://api.ccttiot.com/smartmeter/img/static/uezO7WsDc6GIeLfAkAWb" mode=""></image>
<view class="container">
<view class="scroll-text">
<view class="scroll-item">
查看更多<text style="color: #4297F3;">骑行订单</text>,查看详情后可 <text style="color: #4297F3;">点击切换</text>
</view>
</view>
</view>
<u-icon name="arrow-right" color="#4297F3" style="position: absolute;right: 10rpx;" size="32"></u-icon>
</view>
<!-- 地图 -->
<view class="">
<image class="picimg" v-if="iconflag"
src="https://api.ccttiot.com/smartmeter/img/static/uU4DEpKYqBND0oXDiqod" mode=""></image>
</view>
<map class='map' id="map" :latitude="latitude" :longitude="longitude" :markers="covers"
@markertap="handleMarkerClick" @regionchange="regionchange" :circles="circles" :polygons="polyline"
:show-location="true">
</map>
<view class="lticon">
<image style="width: 80rpx;height: 80rpx;"
src="https://api.ccttiot.com/smartmeter/img/static/ucMoHgzqfBeC1lh2vo4Q" @click="btnbz" mode=""></image>
</view>
<image style="width: 80rpx;height: 80rpx;position: fixed;right: 22rpx;bottom: 840rpx;"
@click="toggleIconAndCallout" src="https://api.ccttiot.com/smartmeter/img/static/u6r5tQVe2VO6bvxTLeFT"
mode=""></image>
<image style="width: 80rpx;height: 80rpx;position: fixed;right: 22rpx;bottom: 740rpx;"
src="https://api.ccttiot.com/smartmeter/img/static/ug1ExhYsZmdWWjVvjjuk" @click="btnhuiz" mode=""></image>
<!-- 车辆弹窗 -->
<view class="biketc" v-if="taocanflag">
<view class="topfor">
<view class="biketop">
<image src="https://api.ccttiot.com/smartmeter/img/static/u6u6mWzrgiVCHICU1IWg" mode=""></image>
<view class="bianh">
<view class="">
车牌号:{{cheobj.vehicleNum == null ? '--' : cheobj.vehicleNum}}
</view>
<view class="bh" style="color: #808080;">
车辆编号:{{cheobj.sn == null ? '--' : cheobj.sn}}
</view>
</view>
<view class="bikebeep" @click="btnxlxc">
响铃寻车
</view>
</view>
<view class="bikesy">
<view class="bikelt">
<view class="bikets">
剩余骑行
</view>
<view class="bikegongli">
<image src="https://api.ccttiot.com/smartmeter/img/static/uLybsyJqWL4siF7mXkXh" mode="">
</image> {{cheobj.remainEndurance == null ? '--' : cheobj.remainEndurance}}公里
</view>
</view>
<view class="bikert">
<view class="bikets">
剩余电量
</view>
<view class="bikegongli">
<image v-if="cheobj.remainingPower >= 0 && cheobj.remainingPower < 20 "
src="https://api.ccttiot.com/smartmeter/img/static/u8M9KmIfHXpmeifTwCzj" mode="">
</image>
<image v-if="cheobj.remainingPower >= 20 && cheobj.remainingPower < 50 "
src="https://api.ccttiot.com/smartmeter/img/static/u2gp2pE9kPGwaJ4MKUxE" mode="">
</image>
<image v-if="cheobj.remainingPower >= 50 && cheobj.remainingPower < 80 "
src="https://api.ccttiot.com/smartmeter/img/static/umm5Ruc5vhNSjeacslwX" mode="">
</image>
<image v-if="cheobj.remainingPower >= 80 && cheobj.remainingPower <= 100 "
src="https://api.ccttiot.com/smartmeter/img/static/uo75cOfYZiQoxZQAI3FH" mode="">
</image>
{{cheobj.remainingPower == null ? '--' : cheobj.remainingPower}}%
</view>
</view>
</view>
<view class="bikeyc" @click="btncheyc">
×
</view>
</view>
<view class="anniuks" @click="btndetaxq">
<text>解锁骑行</text>
</view>
</view>
<view class="clmask" v-if="taocanflag"></view>
<!-- 平台客服弹窗 -->
<view class="kefutc" v-if="kefuflag">
<image src="https://api.ccttiot.com/smartmeter/img/static/umtjJg2CJLiOS6hfAEzo" mode="aspectFill"
@click="kefuflag = false"></image>
<view class="box" >
<view class="" style="max-height: 268rpx;overflow: scroll;">
<view class="top" v-for="(item,index) in kefulist" :key="index">
<view class="dianhua">
{{item.name == null ? '--' : item.name}}{{item.contact == null ? '--' : item.contact}}
</view>
<view class="boda" @click.stop="btnptkf(item.contact)">
<u-icon name="phone-fill" color="#4297F3" size="28"></u-icon>
<text>拨打</text>
</view>
</view>
</view>
<view class="bot">
<!-- <view class="wz">
在线客服
</view>
<view class="wz">
温馨提示
</view> -->
<view class="wzs">
客服电话高峰期可能遇忙请耐心等待
</view>
</view>
</view>
</view>
<view class="mask" style="z-index: 98;background-color: rgba(0, 0, 0, .6);" v-if="kefuflag"></view>
<!-- 有订单弹窗 -->
<view class="conts_box" v-if="orderflag">
<view class="orderzt">
<view class="" style="display: flex;align-items: center;">
<image src="https://api.ccttiot.com/smartmeter/img/static/uc5JSRyb7S6TUCbOiWb3"
v-if="huiyuanlist.length > 0" class="qixing" mode="" @click="btnhuiyuan"></image>
<view class="NO">
<image v-if="orderobj.deviceRemainingPower >= 0 && orderobj.deviceRemainingPower < 20 "
src="https://api.ccttiot.com/smartmeter/img/static/uPEOcK5sThcn6u2CtbGG" mode=""></image>
<image v-if="orderobj.deviceRemainingPower >= 20 && orderobj.deviceRemainingPower < 50 "
src="https://api.ccttiot.com/smartmeter/img/static/ukirjWKpLd9l0HXc1RA5" mode=""></image>
<image v-if="orderobj.deviceRemainingPower >= 50 && orderobj.deviceRemainingPower < 80 "
src="https://api.ccttiot.com/smartmeter/img/static/uI9cNuw1Qxl3hS1cKB9V" mode=""></image>
<image v-if="orderobj.deviceRemainingPower >= 80 && orderobj.deviceRemainingPower <= 100 "
src="https://api.ccttiot.com/smartmeter/img/static/ulCbP0LzpIp38u6P2fLF" mode=""></image>
<text v-if="orderobj.deviceRemainingPower >= 80 && orderobj.deviceRemainingPower <= 100 "
style="color: #16BC32;">{{orderobj.deviceRemainingPower == null ? '--' : orderobj.deviceRemainingPower}}%</text>
<text v-if="orderobj.deviceRemainingPower >= 50 && orderobj.deviceRemainingPower < 80 "
style="color: #16BC32;">{{orderobj.deviceRemainingPower == null ? '--' : orderobj.deviceRemainingPower}}%</text>
<text v-if="orderobj.deviceRemainingPower >= 20 && orderobj.deviceRemainingPower < 50"
style="color: #e87f25;">{{orderobj.deviceRemainingPower == null ? '--' : orderobj.deviceRemainingPower}}%</text>
<text v-if="orderobj.deviceRemainingPower >= 0 && orderobj.deviceRemainingPower < 20 "
style="color: #e81e1e;">{{orderobj.deviceRemainingPower == null ? '--' : orderobj.deviceRemainingPower}}%</text>
</view>
<view class="" style="margin-left: 20rpx;font-weight: 600;font-size: 28rpx;color: #3D3D3D;">
可骑行约{{orderobj.deviceRemainEndurance == null ? '--' : orderobj.deviceRemainEndurance}}km
</view>
</view>
<view class="" style="font-size: 28rpx;color: #4297F3;display: flex;align-items: center;"
@click="btnkefu">
<image style="width: 40rpx;height: 40rpx;margin-right: 10rpx;"
src="https://api.ccttiot.com/smartmeter/img/static/utZyZyusfqjD0TO0iOgZ" mode=""></image> 联系客服
</view>
</view>
<view class="cont_li">
<view class="one">
<view class="oneone">
{{orderobj.rideFee == null ? '0.00' : orderobj.rideFee}} <text>元</text>
</view>
<view class="twotwo" style="display: flex;align-items: center;">
骑行费用
</view>
</view>
<view class="one">
<view class="oneone">
{{ rideDurationText }}
</view>
<view class="twotwo">
骑行时长
</view>
</view>
<view class="one">
<view class="oneone">
{{orderobj.orderDistance == null ? '0.0' : (orderobj.orderDistance / 1000).toFixed(1)}}
<text>km</text>
</view>
<view class="twotwo">
骑行距离
</view>
</view>
</view>
<view class="imgpic">
<!-- <image @click="btnguzhang" class="gzimg" src="https://api.ccttiot.com/smartmeter/img/static/uNuvhrYF4COxUixSCg1q" mode=""></image>
<image @click="btnghbike" class="hcimg" src="https://api.ccttiot.com/smartmeter/img/static/uX8eCy3tMz4hMZc6A35P" mode=""></image>
<image v-if="orderobj.deviceModelEnableSeat == true" @click="btnkzds" src="https://api.ccttiot.com/smartmeter/img/static/u5yuBRYiIeychUXprgzI" mode=""></image> -->
</view>
<view class="botbtn">
<view class="suocheanniu">
<view class="jsdd" style="width: 290rpx;" @click.stop="btnqd">
{{orderobj.deviceLockStatus == 1 ? '临时锁车' : '开锁'}}
</view>
<view class="lssc" style="width: 380rpx;" @click.stop="btnjsdd">
我要还车
</view>
</view>
</view>
<view class="suocheanniu" style="margin-top: 40rpx;padding: 0 80rpx;">
<image src="https://api.ccttiot.com/smartmeter/img/static/u2N3Owincw5NIqOKmRDQ" @click="btnxl" mode="">
</image>
<image src="https://api.ccttiot.com/smartmeter/img/static/uNqmroyWtaYIW9yLn8lw" @click="btnxunche"
mode=""></image>
<image v-if="enableChange" src="https://api.ccttiot.com/smartmeter/img/static/ubg3Go1JkwJmzHxUqBdT" @click="btnghbike"
mode=""></image>
<image v-if="orderobj.deviceModelEnableSeat == true"
src="https://api.ccttiot.com/smartmeter/img/static/uqAFkcZMSlfUl7b7mY7m" @click="btnkzds" mode="">
</image> <!-- 坐垫锁 -->
<image src="https://api.ccttiot.com/smartmeter/img/static/u5GXMpFXAfVPtX3Vauco" @click="btnguzhang"
mode=""></image> <!-- 故障 -->
</view>
<view class=""
style="color: #7C7C7C;font-size: 24rpx;margin-top: 30rpx;width: 100%;text-align: center;display: flex;justify-content: center;padding: 0 50rpx;">
<view class="">
车牌:{{orderobj.deviceVehicleNum == null ? '--' : orderobj.deviceVehicleNum}} <text
style="margin-left: 40rpx;">SN{{orderobj.deviceSn == null ? '--' : orderobj.deviceSn}}</text>
</view>
</view>
</view>
<view class="daohang" v-if="daohangflag">
<view class="name">
{{chexq.name == null ? '--' : chexq.name}}
<text v-if="chexq.type == 1">停车区</text>
<text v-if="chexq.type == 2">禁停区</text>
<text v-if="chexq.type == 3">禁行区</text>
<text v-if="chexq.type == 4">景区</text>
</view>
<view class="shuom">
{{chexq.remark == null ? '暂无说明' : chexq.remark}}
</view>
<image :src="chexq.picture" mode="aspectFill"></image>
<view class="anniu" @click="btndh">
导航前往
</view>
<view class="cha" @click="daohangflag = false">
×
</view>
</view>
<!-- 扫码用车未在停车点内还车弹窗 -->
<view class="tingchetc" v-if="fjflag">
<view class="topname">
<image src="https://api.ccttiot.com/smartmeter/img/static/uDfEXjApmdS6ByM88pv3" mode=""></image>
{{fajinobj.manageFee > 0 ? '不在运营区' : fajinobj.dispatchFee > 0 ? '不在停车点' : ''}}
</view>
<view class="shuom">
需额外支付<text>{{fajinobj.manageFee > 0 ? fajinobj.manageFee : fajinobj.dispatchFee > 0 ? fajinobj.dispatchFee : ''}}元</text><text
@click="btntcd" v-if="fajinobj.dispatchFee > 0">查看最近停车点</text> <text
v-if="fajinobj.manageFee > 0">请规范还车</text>
</view>
<image v-if="fajinobj.manageFee > 0"
src="https://api.ccttiot.com/smartmeter/img/static/u1JsP3mFqiYgfxrlfvA3" class="tcimg"
mode="aspectFill"></image>
<image v-if="fajinobj.dispatchFee > 0"
src="https://api.ccttiot.com/smartmeter/img/static/uVZ6KuaUpYHJgOeSpbv4" class="tcimg"
mode="aspectFill"></image>
<view class="btnan">
<view class="fj" @click="btnfajin">
缴纳罚金还车
</view>
<view class="qx" @click="btnjjqx">
继续骑行
</view>
</view>
</view>
<view class="mask" style="z-index: 10;" v-if="fjflag"></view>
<!-- 统一动画 -->
<view class="tongyi" v-if="wenbentxtflag">
<view class="top">
<image src="https://api.ccttiot.com/smartmeter/img/static/uft9oJbJIjOd6whGG3cM" mode=""></image>
{{wenbentxt}} <text class="percentage-text"
@click="restartPercentageAnimation">{{Math.floor(percentage)}}%</text>
</view>
<view class="" style="width: 100%;text-align: center;margin-top: 20rpx;font-size: 26rpx;color: #3D3D3D;">
{{caozuotext}}
</view>
<image class="ddc" v-if="caozuotext == '骑行前请检查车轿刹车是否灵敏,安全骑行'"
src="https://api.ccttiot.com/%E5%88%B9%E8%BD%A6-1756546350335.gif" mode=""></image>
<image class="ddc" v-else src="https://api.ccttiot.com/smartmeter/img/static/uKOCB6yMx4VMyBgblz3H" mode="">
</image>
</view>
<view class="mask" v-if="wenbentxtflag"></view>
<!-- 统一蓝牙连接失败 -->
<view class="tongyi" style="height: 1100rpx;padding: 0 20rpx;box-sizing: border-box;" v-if="ljsbflag">
<view class="" style="font-size: 60rpx;font-weight: 600;position: absolute;top: 0;right: 20rpx;"
@click="ljsbflag = false">
×
</view>
<view class="bluetooth-error-container">
<view class="error-header">
<image class="error-icon"
src="https://api.ccttiot.com/smartmeter/img/static/uDfEXjApmdS6ByM88pv3" mode=""></image>
<text class="error-title">蓝牙连接失败</text>
</view>
<view class="error-steps">
<view class="step-item">
<view class="step-number">1</view>
<text class="step-text">请检查手机蓝牙是否打开</text>
</view>
<view class="step-item">
<view class="step-number">2</view>
<text class="step-text">小程序蓝牙权限是否授权</text>
</view>
<view class="step-item">
<view class="step-number">3</view>
<text class="step-text">如有不解请点击查看教程</text>
</view>
</view>
<view class="tutorial-link" @click="btnjc">
<text class="tutorial-text">查看教程</text>
<view class="tutorial-arrow">→</view>
</view>
</view>
<image style="margin-top: 0;" class="ddc" v-if="caozuotext == '骑行前请检查车轿刹车是否灵敏,安全骑行'"
src="https://api.ccttiot.com/%E5%88%B9%E8%BD%A6-1756546350335.gif" mode=""></image>
<image style="margin-top: 0;" class="ddc" v-else src="https://api.ccttiot.com/smartmeter/img/static/uKOCB6yMx4VMyBgblz3H" mode=""></image>
<view class="anniu">
<view class="lx" @click="btnkefu">
联系客服
</view>
<view class="zx" @click="btnchongshi">
点击重试
</view>
</view>
</view>
<view class="mask" v-if="ljsbflag"></view>
</view>
</template>
<script>
var xBlufi = require("@/components/blufi/xBlufi.js")
export default {
data() {
return {
iconobj: this.$store.state.iconobj,
bgc: {
backgroundColor: "",
},
latitude: '',
longitude: '',
lat: '',
lng: '',
latsc: '',
lngsc: '',
rtindex: 2,
covers: [],
shoptcflag: false,
iconPath: '',
tcindex: 0,
taocanflag: false,
kefuflag: false,
iconflag: false,
cheobj: {},
jingweidu: '',
taocaolist: [],
polyline: [],
kefulist: [],
orderAreaId: '',
areaId: '',
orderobj: {},
orderAreaReturnVerify: '',
fajinobj: {},
fjflag: false,
showIconAndCallout: false,
orderflag: false,
hei: {
height: '64vh'
},
sockedata: {},
socketTask: null,
messages: [],
reconnectAttempts: 0,
maxReconnectAttempts: 5,
reconnectInterval: 3000,
isPageActive: true,
deviceMac: '',
newMarkers: '',
count: 0,
timer: null,
user: {},
xllat: '',
xllng: '',
circles: [],
nearbyMarkers: [],
listData: [],
yyid: '',
cachedPolyline: [], // 缓存多边形数据
cachedParkingData: {}, // 缓存停车区域数据
isFirstLoad: true, // 是否是首次加载
parkingList: [],
shibainum: 0,
jiance: false,
ver_dataflag: 1,
mac: '',
deviceid: '',
devicename: '',
name: '',
devicesarr: [],
findDeviceTimer: null,
uploadTimer: null, // 定时器ID
lastUploadTime: 0, // 上次上传时间戳
isUploading: false, // 上传状态锁
isRefreshing: false,
bluetoothData: {},
lslat: '',
lslon: '',
orderDeviceTimer: null, // 订单设备定时器
wenbentxt: '',
wenbentxtflag: false,
percentage: 0, // 百分比数值
percentageTimer: null, // 百分比动画定时器
ljsbflag: false,
chongshinum: '',
jieshuflag: true,
rideDurationText: '00:00',
rideTimer: null,
huiyuanlist: [],
daohangflag: false,
distance: 0,
chexq: {},
caozuotext: '',
enableChange:false,
scdevlist:[],
ordernum:0,
bltRemark:''
}
},
onLoad(e) {
console.log(e);
},
onShow() {
uni.openBluetoothAdapter({
success: function (res) {
this.bltRemark = '蓝牙权限均已打开'
},
fail: function (err) {
console.error('蓝牙适配器初始化失败', err)
// 蓝牙未打开或初始化失败
if(err.errMsg == 'openBluetoothAdapter:fail auth deny'){
this.bltRemark = '微信蓝牙权限没有授权'
}else if(err.errMsg == 'openBluetoothAdapter:fail open fail'){
this.bltRemark = '手机蓝牙没有打开'
}else if(err.errMsg == 'openBluetoothAdapter:fail:not available'){
this.bltRemark = '手机蓝牙是否打开'
}
console.log(this.bltRemark);
}
})
this.getnum()
this.getorderdevice()
xBlufi.initXBlufi(1)
xBlufi.notifyStartDiscoverBle({
'isStart': true
})
xBlufi.listenDeviceMsgEvent(true, this.funListenDeviceMsgEvent)
uni.getLocation({
type: 'gcj02',
success: (res) => {
this.xllat = res.latitude
this.xllng = res.longitude
},
fail: (err) => {
console.error('获取位置失败:', err)
}
})
this.getAone()
this.covers = []
this.sockedata = ''
setTimeout(() => {
this.setMapScale()
}, 500)
this.polyline = []
this.isFirstLoad = true // 重置首次加载标志
setTimeout(() => {
this.toggleIconAndCallout()
}, 3000)
},
onUnload() {
this.clearTimer()
this.stopOrderDeviceTimer() // 停止订单设备定时器
this.stopRideTimer()
this.stopPercentageAnimation() // 停止百分比动画
this.isPageActive = false
this.closeWebSocket()
if (this.findDeviceTimer) {
clearTimeout(this.findDeviceTimer)
this.findDeviceTimer = null
}
},
onHide() {
if (this.findDeviceTimer) {
clearTimeout(this.findDeviceTimer)
this.findDeviceTimer = null
}
this.clearTimer()
this.stopOrderDeviceTimer() // 停止订单设备定时器
this.stopRideTimer()
this.stopPercentageAnimation() // 停止百分比动画
// 页面隐藏时关闭连接
this.isPageActive = false
this.closeWebSocket()
},
// 组件销毁时清除定时器
beforeDestroy() {
clearTimeout(this.uploadTimer)
this.stopOrderDeviceTimer() // 停止订单设备定时器
this.stopPercentageAnimation() // 停止百分比动画
},
watch: {
wenbentxtflag(newVal) {
if (newVal) {
// 当wenbentxtflag变为true时启动百分比动画
setTimeout(() => {
this.startPercentageAnimation()
}, 500)
} else {
// 当wenbentxtflag变为false时停止百分比动画
this.stopPercentageAnimation()
this.percentage = 0
}
}
},
methods: {
// 查询订单数量
getnum(){
this.$u.get(`/app/orderDevice/mineUsingCount`).then(res => {
if (res.code == 200) {
this.ordernum = res.data
}
})
},
// 点击跳转进行中订单列表页
btntopgg(){
uni.navigateTo({
url:'/page_shanghu/yunwei/xzshebei'
})
},
// 启动百分比动画
startPercentageAnimation() {
this.percentage = 0
this.percentageTimer = setInterval(() => {
if (this.percentage < 98) {
// 使用缓动函数,让动画更自然
const remaining = 98 - this.percentage
const increment = Math.max(1, remaining * 0.1) // 越接近98%增长越慢最小增长1
this.percentage += increment
if (this.percentage > 98) {
this.percentage = 98
}
} else {
clearInterval(this.percentageTimer)
this.percentageTimer = null
}
}, 80) // 每80ms更新一次让动画更流畅
},
// 停止百分比动画
stopPercentageAnimation() {
if (this.percentageTimer) {
clearInterval(this.percentageTimer)
this.percentageTimer = null
}
},
// 重新开始百分比动画
restartPercentageAnimation() {
this.stopPercentageAnimation()
setTimeout(() => {
this.startPercentageAnimation()
}, 100)
},
// 规划路线
handleMarkerClick(e) {
console.log(e);
this.getcha(e.markerId)
this.daohangflag = true
},
// 查询运营区信息
getcha(id) {
this.$u.get(`/app/areaSub/detail?id=${id}`).then(res => {
if (res.code == 200) {
this.chexq = res.data
}
})
},
// 点击跳转导航
btndh() {
uni.openLocation({
latitude: this.chexq.latitude, //纬度-目的地/坐标点
longitude: this.chexq.longitude, //经度-目的地/坐标点
name: this.chexq.name, //地点名称
address: this.chexq.name //详细地点名称
})
},
// 计算骑行时长显示(按时和分,不到一分钟显示一分钟)
computeRideDurationText() {
if (!this.orderobj || !this.orderobj.orderStartTime) {
this.rideDurationText = '00:00'
return
}
let startMs = null
const os = this.orderobj.orderStartTime
if (typeof os === 'number') {
startMs = os
} else if (typeof os === 'string') {
const parsed = Date.parse(os.replace(/-/g, '/'))
startMs = isNaN(parsed) ? null : parsed
} else if (os instanceof Date) {
startMs = os.getTime()
}
if (!startMs) {
this.rideDurationText = '00:00'
return
}
const now = Date.now()
let diffMs = Math.max(0, now - startMs)
let totalMinutes = Math.floor(diffMs / 60000)
if (totalMinutes < 1) totalMinutes = 1
const hours = Math.floor(totalMinutes / 60)
const minutes = totalMinutes % 60
const hh = hours.toString().padStart(2, '0')
const mm = minutes.toString().padStart(2, '0')
this.rideDurationText = `${hh}:${mm}`
},
// 启动骑行时长定时器
startRideTimer() {
this.stopRideTimer()
this.computeRideDurationText()
this.rideTimer = setInterval(() => {
this.computeRideDurationText()
}, 1000)
},
// 停止骑行时长定时器
stopRideTimer() {
if (this.rideTimer) {
clearInterval(this.rideTimer)
this.rideTimer = null
}
},
// 点击查看蓝牙连接教程
btnjc() {
uni.navigateTo({
url: '/page_user/yongche/index?type=2'
})
},
// 点击进行操作重试
btnchongshi() {
this.ljsbflag = false
if (this.chongshinum == '解锁' || this.chongshinum == '锁车') {
this.btnqd()
} else if (this.chongshinum == '还车') {
this.btnjsdd()
} else if (this.chongshinum == '换车') {
this.btnghbike()
} else if (this.chongshinum == '响铃') {
this.btnxl()
}
},
// 点击请求客服列表进行咨询
btnkefu() {
this.$u.get(`/app/customerService/list?pageNum=1&pageSize=999&areaId=${this.orderobj.orderAreaId}`).then(
res => {
if (res.code == 200) {
if (res.rows.length > 0) {
this.kefulist = res.rows
this.kefuflag = true
} else {
uni.showToast({
title: '当前运营区暂无客服',
icon: 'none',
duration: 2000
})
}
} else {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
})
}
})
},
// 点击跳转导航寻车
btnxunche() {
this.$u.get(`/app/device/detailByOrderId?orderId=${this.orderobj.orderId}&supportLocation=true`).then((
res) => {
if (res.code == 200) {
uni.openLocation({
latitude: res.data.latitude, //纬度-目的地/坐标点
longitude: res.data.longitude, //经度-目的地/坐标点
// name: res.data.deviceVehicleNum, //地点名称
})
} else {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
})
}
})
},
// 点击车辆响铃
btnxl() {
this.scdevlist = this.devicesarr.map(item => {
const name = item.name || ''
return name.slice(-12)
})
if (this.jiance == true) {
xBlufi.initXBlufi(1)
xBlufi.notifyStartDiscoverBle({
'isStart': true
})
xBlufi.listenDeviceMsgEvent(true, this.funListenDeviceMsgEvent)
}
this.wenbentxt = '车辆响铃中...'
this.wenbentxtflag = true
uni.getLocation({
type: 'gcj02',
success: (res) => {
console.log(res);
this.xllat = res.latitude
this.xllng = res.longitude
},
fail: (err) => {
console.error('获取位置失败:', err)
}
})
let data = {
id:this.orderobj.deviceId,
lat:this.xllat,
lon:this.xllng,
macList:this.scdevlist
}
this.$u.put(`/app/device/iot/ring`,data).then((res) => {
if (res.code == 200) {
this.wenbentxt = ''
this.wenbentxtflag = false
uni.showToast({
title: '操作成功',
icon: 'success',
duration: 2000
})
} else if (res.code == 20001) {
this.wenbentxt = '蓝牙响铃中...'
let that = this
const findDevice = () => {
that.ver_dataflag = 2
const matchedDevice = that.devicesarr.find(device => {
return device.name.slice(-12) == that.mac.slice(-12)
})
if (matchedDevice) {
xBlufi.notifyStartDiscoverBle({
'isStart': false
})
xBlufi.notifyConnectBle({
isStart: true,
deviceId: matchedDevice.deviceId,
name: matchedDevice.name
})
that.deviceid = matchedDevice.deviceId
that.devicename = matchedDevice.name
setTimeout(() => {
if (that.ver_dataflag == 3) {
that.wenbentxt = ''
that.wenbentxtflag = false
xBlufi.notifySendCustomData({
customData: "11play1@"
})
} else {
that.chongshinum = '响铃'
that.ver_dataflag = 1
that.shibainum = 0
that.wenbentxt = ''
that.wenbentxtflag = false
that.ljsbflag = true
uni.openBluetoothAdapter({
success: function (res) {
},
fail: function (err) {
console.error('蓝牙适配器初始化失败', err)
// 蓝牙未打开或初始化失败
if(err.errMsg == 'openBluetoothAdapter:fail auth deny'){
uni.showToast({
title: '请检查微信蓝牙权限是否授权',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail open fail'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail:not available'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}
}
})
}
}, 4000)
} else {
if (that.shibainum < 3) {
that.shibainum++
that.findDeviceTimer = setTimeout(findDevice.bind(that),1000) // 使用 bind 保持 this 上下文
} else {
that.chongshinum = '响铃'
that.ver_dataflag = 1
that.shibainum = 0
that.wenbentxt = ''
that.wenbentxtflag = false
that.ljsbflag = true
let lanya = ''
if (that.jiance == true) {
lanya = '蓝牙未开启'
} else {
lanya = '蓝牙已开启'
}
let data = {
mac: that.mac,
orderId: that.orderobj.orderId,
reason: '用户蓝牙响铃失败' + lanya,
command: '11play1@',
lat: that.lat,
lon: that.lon,
result: '失败'
}
that.$u.post(`/app/commandLog/bluetooth`, data).then(res => {})
uni.openBluetoothAdapter({
success: function (res) {
},
fail: function (err) {
console.error('蓝牙适配器初始化失败', err)
// 蓝牙未打开或初始化失败
if(err.errMsg == 'openBluetoothAdapter:fail auth deny'){
uni.showToast({
title: '请检查微信蓝牙权限是否授权',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail open fail'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail:not available'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}
}
})
}
}
}
findDevice()
} else {
this.wenbentxt = ''
this.wenbentxtflag = false
uni.showToast({
title: res.msg,
icon: 'none',
duration: 3000
})
}
})
},
// 获取附近蓝牙设备列表
funListenDeviceMsgEvent: function(options) {
switch (options.type) {
case xBlufi.XBLUFI_TYPE.TYPE_STATUS_CONNECTED: //监听蓝牙是否断开
if (!options.result) {
this.ver_dataflag = 1
console.log(this.ver_dataflag, '断开断开');
clearTimeout(this.uploadTimer) //清除每十秒传一次的定时
this.jiance = true
}
break;
case xBlufi.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS: //获取附近蓝牙设备列表
if (options.result) {
this.devicesarr = options.data
}
break;
case xBlufi.XBLUFI_TYPE.TYPE_CONNECTED: //连接回调是否连接上蓝牙
console.log("连接回调:" + JSON.stringify(options))
if (options.result == true) {
setTimeout(() => {
this.ver_dataflag = 3
}, 2000)
xBlufi.notifyInitBleEsp32({
deviceId: this.deviceid
})
this.deviceid = options.data.deviceId
this.name = this.name
} else {
this.ver_dataflag = 1
}
break;
case xBlufi.XBLUFI_TYPE.TYPE_RECIEVE_CUSTON_DATA: //接收蓝牙传输数据
console.log("1收到设备发来的自定义数据结果", options.data)
this.getlysj(options.data)
break;
case xBlufi.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS_START: //判断蓝牙是否初始化成功兼是否开启蓝牙
if (!options.result) {
console.log('蓝牙未开启')
this.jiance = true
return
}
break;
}
},
// 解析接收的蓝牙数据
getlysj(data) {
if (!data) return;
// 1. 更健壮的数据解析
const dataStr = data.toString();
// console.log('原始数据:', dataStr);
const dataObj = {};
// 判断数据格式:检查是否包含@或,分隔符
let separator = ',';
if (dataStr.includes('@')) {
separator = '@';
}
dataStr.split(separator).forEach(part => {
if (!part) return; // 忽略空字符串
let key, value;
// 如果使用@分隔符,数据格式为 key-value 对,例如: status0@csq0@bat125@...
if (separator === '@') {
// 使用正则表达式分离键(字母)和值(数字)
const match = part.match(/^([a-zA-Z]+)(.*)$/);
if (!match) return;
key = match[1];
value = match[2];
} else {
// 如果使用,分隔符,数据格式为 key:value 对,例如: status:0,csq:0,bat:125,...
const [keyPart, valuePart] = part.split(':').map(item => item.trim());
if (!keyPart || valuePart === undefined) return;
key = keyPart;
value = valuePart;
}
if (key && value !== undefined) {
switch (key) {
case 'status':
dataObj.status = value;
break;
case 'bat':
dataObj.bat = parseFloat(value);
break;
case 'csq':
dataObj.csq = parseInt(value, 10);
break;
case 'lat':
dataObj.lat = parseFloat(value);
break;
case 'lon':
dataObj.lon = parseFloat(value);
break;
case 'q':
dataObj.q = parseInt(value, 10);
break;
case 's':
dataObj.s = parseInt(value, 10);
break;
}
}
})
// 2. 获取定位
uni.getLocation({
type: 'gcj02',
isHighAccuracy: true,
success: (res) => {
this.submitData({
...dataObj,
lon: res.longitude,
lat: res.latitude
})
},
fail: () => {
this.submitData({
...dataObj,
lon: dataObj.lon || 0,
lat: dataObj.lat || 0
})
}
})
},
// 3. 单独封装数据提交
submitData(data) {
const payload = {
mac: this.mac,
sys: {
bat: data.bat !== undefined && data.bat !== null ? Number(data.bat) : 0,
csq: data.csq !== undefined && data.csq !== null ? Number(data.csq) : 0,
s: data.s !== undefined && data.s !== null ? Number(data.s) : null,
q: data.q !== undefined && data.q !== null ? Number(data.q) : null,
status: String(data.status || '0'),
lon: data.lon !== undefined && data.lon !== null ? Number(data.lon) : 0,
lat: data.lat !== undefined && data.lat !== null ? Number(data.lat) : 0
}
}
this.bluetoothData = payload
this.throttledUpload()
},
// 节流上传控制
throttledUpload() {
const now = Date.now()
const throttleInterval = 10000 // 10秒
clearTimeout(this.uploadTimer)
// 如果距离上次上传超过10秒且没有正在上传的请求
if (now - this.lastUploadTime >= throttleInterval && !this.isUploading) {
this.doUpload()
} else {
const remainingTime = throttleInterval - (now - this.lastUploadTime)
this.uploadTimer = setTimeout(() => {
this.doUpload()
}, remainingTime)
}
},
// 实际执行上传
doUpload() {
if (!this.bluetoothData || this.isUploading) return
this.isUploading = true
this.lastUploadTime = Date.now()
this.$u.put(`/app/device/iot/bltUpload`, this.bluetoothData).then(res => {
if (res.code == 200) {
console.log('上传蓝牙数据成功', this.bluetoothData, new Date().toLocaleTimeString())
} else {
console.log('上传蓝牙数据失败', res.msg)
}
}).catch(err => {
console.error('上传异常:', err)
}).finally(() => {
this.isUploading = false
})
},
// 开坐垫锁
btnkzds(){
this.scdevlist = this.devicesarr.map(item => {
const name = item.name || ''
return name.slice(-12)
})
let that = this
uni.openBluetoothAdapter({
success: function (res) {
that.bltRemark = '蓝牙权限均已打开'
that.btnkzs()
},
fail: function (err) {
console.error('蓝牙适配器初始化失败', err)
// 蓝牙未打开或初始化失败
if(err.errMsg == 'openBluetoothAdapter:fail auth deny'){
that.bltRemark = '微信蓝牙权限没有授权'
that.btnkzs()
}else if(err.errMsg == 'openBluetoothAdapter:fail open fail'){
that.bltRemark = '手机蓝牙没有打开'
that.btnkzs()
}else if(err.errMsg == 'openBluetoothAdapter:fail:not available'){
that.bltRemark = '手机蓝牙是否打开'
that.btnkzs()
}else{
that.bltRemark = `其他错误 + ${err.errMsg}`
that.btnkzs()
}
}
})
},
btnkzs() {
uni.getLocation({
type: 'gcj02', // 国内地图更兼容
isHighAccuracy: true,
accuracy: 'best',
success: (res) => {
// console.log('精确坐标:', res)
this.lslat = res.latitude
this.lslon = res.longitude
},
fail: (err) => {
console.error('获取位置失败:', err)
this.lslat = null
this.lslat = null
}
})
let that = this
uni.showModal({
title: '提示',
content: '您是否要开启坐垫锁?',
showCancel: true,
success: function(res) {
if (res.confirm) {
uni.showLoading({
title: '加载中...',
mask: true
})
let data = {
orderId: that.orderobj.orderId,
lon: that.lslon,
lat: that.lslat,
requiredIot: true,
bltRemark:that.bltRemark
}
that.$u.put("/app/order/seat", data).then((res) => {
if (res.code == 200) {
uni.showToast({
title: '打开成功',
icon: 'success',
duration: 2000
})
} else if (res.code == 20001) {
uni.hideLoading()
if (that.ver_dataflag != 3) {
uni.showLoading({
title: '坐垫锁开启中...',
mask: true
})
this.ver_dataflag = 2
const matchedDevice = this.devicesarr.find(device => {
return device.name.slice(-12) == this.mac.slice(-12)
})
if (matchedDevice) {
xBlufi.notifyStartDiscoverBle({
'isStart': false
})
xBlufi.notifyConnectBle({
isStart: true,
deviceId: matchedDevice.deviceId,
name: matchedDevice.name
})
this.deviceid = matchedDevice.deviceId
this.devicename = matchedDevice.name
setTimeout(() => {
uni.hideLoading()
xBlufi.notifySendCustomData({
customData: "11hpen@"
})
}, 4000)
} else {
if (this.shibainum < 3) {
this.shibainum++
this.findDeviceTimer = setTimeout(this.findDevice.bind(this), 1000) // 使用 bind 保持 this 上下文
} else {
this.ver_dataflag = 1
this.shibainum = 0
uni.showModal({
title: '提示',
content: '开启坐垫锁失败,请重试',
showCancel: false,
success: function(res) {
if (res.confirm) {
} else if (res.cancel) {
}
}
})
}
}
}
} else {
uni.hideLoading()
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
})
}
})
}
}
})
},
// 点击自定义返回页面
btnfh() {
uni.reLaunch({
url: '/pages/nearbystores/index?qbtype=1'
})
},
// 拖动查询中心点的数据
regionchange(e) {},
// 解析判断赋值车辆状态
status(item) {
if (item.status == 0) {
return '仓库中'
} else if (item.status == 1) {
return '待租'
} else if (item.status == 2) {
return '预约中'
} else if (item.status == 3) {
return '骑行中'
} else if (item.status == 4) {
return '临时锁车中'
} else if (item.status == 6) {
return '调度中'
} else if (item.status == 7) {
return '未绑定'
} else if (item.status == 8) {
return '禁用中'
}
},
// startTimer() {
// this.timer = setInterval(() => {
// this.count++ //每次加一
// // 这里替换为你的实际逻辑
// this.setMapScale()
// }, 5000)
// },
// 清除定时器
clearTimer() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
console.log("定时器已清除")
}
},
// 点击继续骑行
btnjjqx() {
this.orderflag = true
this.fjflag = false
},
//WebSocket 自动重连实现
initWebSocket() {
if (!this.isPageActive || !this.deviceMac) return
let token = uni.getStorageSync('token')
// 关闭已有连接
if (this.socketTask) {
this.socketTask.close()
this.socketTask = null
}
// 创建新连接
this.socketTask = uni.connectSocket({
url: `wss://ele.ccttiot.com/prod-api/ws/device?token=${token}&mac=${this.deviceMac}`,
// url: `wss://ysd.chuantewulian.cn/prod-api/ws/device?token=${token}&mac=${this.deviceMac}`,
success: () => {
console.log('WebSocket连接建立中...')
},
fail: (err) => {
console.error('WebSocket连接失败:', err)
this.scheduleReconnect()
}
});
// 监听连接打开
this.socketTask.onOpen(() => {
console.log('WebSocket连接已打开')
this.reconnectAttempts = 0; // 重置重连计数器
// 发送订阅消息(如果需要)
this.socketTask.send({
data: JSON.stringify({
action: 'subscribe'
}),
success: () => console.log('订阅消息发送成功'),
fail: (err) => console.error('订阅消息发送失败:', err)
})
})
// 监听消息接收
this.socketTask.onMessage((res) => {
console.log('收到实时消息:', res.data)
this.messages.push(res.data) // 存储消息
try {
const data = JSON.parse(res.data)
console.log('解析后的JSON数据:', data)
// 这里可以处理具体的业务逻辑
this.sockedata = data
this.covers = []
const newMarkers = []
this.parkingList.forEach(item => {
newMarkers.push({
id: parseFloat(item.id),
latitude: parseFloat(item.latitude),
longitude: parseFloat(item.longitude),
width: 18,
height: 26,
iconPath: item.type == 1 ? 'https://lxnapi.ccttiot.com/bike/img/static/up2xXqAgwCX5iER600k3' : item.type == 2 ? 'https://lxnapi.ccttiot.com/bike/img/static/uDNY5Q4zOiZTCBTA2Jdq' : item.type == 3 ? 'https://lxnapi.ccttiot.com/bike/img/static/u53BAQcFIX3vxsCzEZ7t' : 'https://api.ccttiot.com/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20250829161752_210_17-1756455764351.png',
callout: {
content: item.name,
color: '#ffffff',
fontSize: 12,
borderRadius: 8,
bgColor: item.type == 1 ? '#3A7EDB' : item.type == 2 ?'#FF473E' : item.type == 3 ? '#FFC107' : '#3bbd55',
padding: 4,
display: 'ALWAYS'
},
isCalloutVisible: true // 添加标记
})
})
this.newMarkers = newMarkers
this.$set(this, 'covers', [...this.covers, ...newMarkers])
if (this.sockedata.latitude) {
this.covers.push({
latitude: this.sockedata.latitude,
longitude: this.sockedata.longitude,
width: 8,
height: 8,
iconPath: 'https://api.ccttiot.com/smartmeter/img/static/uow9Zq3edTUYCVHI9H60',
})
}
this.covers.push({
latitude: data.latitude,
longitude: data.longitude,
width: 8,
height: 8,
iconPath: 'https://api.ccttiot.com/smartmeter/img/static/uow9Zq3edTUYCVHI9H60',
})
} catch (e) {
console.log('原始消息内容:', res.data)
}
});
// 监听错误
this.socketTask.onError((err) => {
console.error('WebSocket错误:', err)
this.scheduleReconnect()
});
// 监听连接关闭
this.socketTask.onClose((res) => {
console.log('WebSocket连接已关闭', res)
if (this.isPageActive) {
this.scheduleReconnect()
}
})
},
// 关闭WebSocket连接
closeWebSocket() {
if (this.socketTask) {
this.socketTask.close({
success: () => {
console.log('WebSocket已主动关闭')
this.socketTask = null
},
fail: (err) => {
console.error('WebSocket关闭失败:', err)
this.socketTask = null
}
})
}
},
// 安排重连
scheduleReconnect() {
if (!this.isPageActive || this.reconnectAttempts >= this.maxReconnectAttempts) {
console.log('已达到最大重连次数或页面已关闭,停止重连')
return
}
this.reconnectAttempts++;
console.log(`尝试第 ${this.reconnectAttempts} 次重连,等待 ${this.reconnectInterval/1000} 秒...`)
setTimeout(() => {
this.initWebSocket()
}, this.reconnectInterval)
// 指数退避策略,增加重连间隔
this.reconnectInterval = Math.min(this.reconnectInterval * 2, 30000) // 最大不超过30秒
},
// 点击结束订单
btnjsdd(){
this.scdevlist = this.devicesarr.map(item => {
const name = item.name || ''
return name.slice(-12)
})
let that = this
uni.openBluetoothAdapter({
success: function (res) {
that.bltRemark = '蓝牙权限均已打开'
that.btnjsds()
},
fail: function (err) {
console.error('蓝牙适配器初始化失败', err)
// 蓝牙未打开或初始化失败
if(err.errMsg == 'openBluetoothAdapter:fail auth deny'){
that.bltRemark = '微信蓝牙权限没有授权'
that.btnjsds()
}else if(err.errMsg == 'openBluetoothAdapter:fail open fail'){
that.bltRemark = '手机蓝牙没有打开'
that.btnjsds()
}else if(err.errMsg == 'openBluetoothAdapter:fail:not available'){
that.bltRemark = '手机蓝牙是否打开'
that.btnjsds()
}else{
that.bltRemark = `其他错误 + ${err.errMsg}`
that.btnjsds()
}
}
})
},
btnjsds() {
if (this.jiance == true) {
xBlufi.initXBlufi(1)
xBlufi.notifyStartDiscoverBle({
'isStart': true
})
xBlufi.listenDeviceMsgEvent(true, this.funListenDeviceMsgEvent)
}
this.caozuotext = '还车前请将车辆停放于运营区和停车区内'
if (this.jieshuflag == true) {
this.jieshuflag = false
this.$u.get("/app/order/mineProcessing").then((res) => {
if (res.code == 200) {
if (res.data) {
if (this.orderAreaReturnVerify == true) {
if (this.orderobj.deviceOnlineStatus == 0) {
this.jieshuflag = true
this.wenbentxtflag = true
this.wenbentxt = '蓝牙连接中...'
let that = this
const findDevice = () => {
that.ver_dataflag = 2
const matchedDevice = that.devicesarr.find(device => {
return device.name.slice(-12) == that.mac.slice(-12)
})
if (matchedDevice) {
xBlufi.notifyStartDiscoverBle({
'isStart': false
})
xBlufi.notifyConnectBle({
isStart: true,
deviceId: matchedDevice.deviceId,
name: matchedDevice.name
})
that.deviceid = matchedDevice.deviceId
that.devicename = matchedDevice.name
setTimeout(() => {
if (that.ver_dataflag == 3) {
that.wenbentxt = ''
that.wenbentxtflag = false
let flag = false
uni.navigateTo({
url: '/page_user/hcshenhe?sn=' +that.orderobj.deviceSn +'&orderid=' + that.orderobj.orderId + '&orderAreaId=' +that.orderobj.orderAreaId +'&flag=' + flag + '&mac=' + that.mac + '&macList=' + that.scdevlist
})
} else {
that.ver_dataflag = 1
that.shibainum = 0
that.wenbentxt = ''
that.wenbentxtflag = false
that.ljsbflag = true
that.chongshinum = '还车'
uni.openBluetoothAdapter({
success: function (res) {
},
fail: function (err) {
console.error('蓝牙适配器初始化失败', err)
// 蓝牙未打开或初始化失败
if(err.errMsg == 'openBluetoothAdapter:fail auth deny'){
uni.showToast({
title: '请检查微信蓝牙权限是否授权',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail open fail'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail:not available'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}
}
})
}
}, 4000)
} else {
if (that.shibainum < 3) {
that.shibainum++
that.findDeviceTimer = setTimeout(findDevice.bind(that),1000) // 使用 bind 保持 this 上下文
} else {
that.ver_dataflag = 1
that.shibainum = 0
that.wenbentxt = ''
that.wenbentxtflag = false
that.ljsbflag = true
that.chongshinum = '还车'
uni.openBluetoothAdapter({
success: function (res) {
},
fail: function (err) {
console.error('蓝牙适配器初始化失败', err)
// 蓝牙未打开或初始化失败
if(err.errMsg == 'openBluetoothAdapter:fail auth deny'){
uni.showToast({
title: '请检查微信蓝牙权限是否授权',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail open fail'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail:not available'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}
}
})
}
}
}
findDevice()
} else {
this.jieshuflag = true
uni.navigateTo({
url: '/page_user/hcshenhe?sn=' + this.orderobj.deviceSn +'&orderid=' + this.orderobj.orderId + '&orderAreaId=' +this.orderobj.orderAreaId + '&flag=' + true + '&macList=' + this.scdevlist
})
}
} else {
this.wenbentxt = '车辆还车中...'
this.wenbentxtflag = true
console.log(this.devicesarr, '附近设备');
let that = this
const findDevice = () => {
that.ver_dataflag = 2
const matchedDevice = that.devicesarr.find(device => {
return device.name.slice(-12) == that.mac.slice(-12)
})
if (matchedDevice) {
console.log('在旁边');
that.wenbentxt = ''
that.wenbentxtflag = false
uni.getLocation({
type: 'gcj02', // 国内地图更兼容
isHighAccuracy: true,
accuracy: 'best',
success: (res) => {
console.log('精确坐标:', res)
that.lat = res.latitude
that.lon = res.longitude
that.lngsc = res.longitude
that.latsc = res.latitude
that.getfeiyong()
},
fail: (err) => {
console.error('获取位置失败:', err)
that.lat = null
that.lon = null
that.lngsc = null
that.latsc = null
that.getfeiyong() // 降级处理
}
})
} else {
if (that.shibainum < 3) {
that.shibainum++
that.findDeviceTimer = setTimeout(findDevice.bind(that),
1000) // 使用 bind 保持 this 上下文
} else {
console.log('不在旁边2');
uni.getLocation({
type: 'gcj02', // 国内地图更兼容
isHighAccuracy: true,
accuracy: 'best',
success: (res) => {
console.log('精确坐标:', res)
that.lat = res.latitude
that.lon = res.longitude
that.lngsc = res.longitude
that.latsc = res.latitude
that.ver_dataflag = 1
that.shibainum = 0
that.wenbentxt = ''
that.wenbentxtflag = false
that.chongshinum = '还车'
that.getfeiyong()
},
fail: (err) => {
console.error('获取位置失败:', err)
that.lat = null
that.lon = null
that.lngsc = null
that.latsc = null
that.ver_dataflag = 1
that.shibainum = 0
that.wenbentxt = ''
that.wenbentxtflag = false
that.chongshinum = '还车'
that.getfeiyong()
}
})
}
}
}
findDevice()
}
} else {
this.jieshuflag = true
uni.navigateTo({
url: '/page_user/yongche/orderxq?id=' + this.orderobj.orderId
})
}
} else {
this.jieshuflag = true
uni.showToast({
title: res.msg,
icon: 'none',
duration: 5000
})
}
})
}
},
// 点击还车判断是否需要另外缴费
// getfeiyong(){
// this.scdevlist = this.devicesarr.map(item => {
// const name = item.name || ''
// return name.slice(-12)
// })
// let that = this
// uni.openBluetoothAdapter({
// success: function (res) {
// that.bltRemark = '蓝牙权限均已打开'
// that.getfeiyons()
// },
// fail: function (err) {
// console.error('蓝牙适配器初始化失败', err)
// // 蓝牙未打开或初始化失败
// if(err.errMsg == 'openBluetoothAdapter:fail auth deny'){
// that.bltRemark = '微信蓝牙权限没有授权'
// that.getfeiyons()
// }else if(err.errMsg == 'openBluetoothAdapter:fail open fail'){
// that.bltRemark = '手机蓝牙没有打开'
// that.getfeiyons()
// }else if(err.errMsg == 'openBluetoothAdapter:fail:not available'){
// that.bltRemark = '手机蓝牙是否打开'
// that.getfeiyons()
// }else{
// that.bltRemark = `其他错误 + ${err.errMsg}`
// that.getfeiyons()
// }
// }
// })
// },
getfeiyong() {
let data = {
orderId: this.orderobj.orderId,
lon: this.lngsc,
lat: this.latsc,
checkLocation: true,
macList:this.scdevlist,
bltRemark:this.bltRemark
}
this.$u.post(`/app/order/calcFee`, data).then(res => {
if (res.code == 200) {
this.jieshuflag = true
this.fajinobj = res.data
if (res.data.manageFee > 0 || res.data.dispatchFee > 0) {
this.wenbentxt = ''
this.wenbentxtflag = false
this.fjflag = true
this.orderflag = false
} else {
this.gethuan()
}
} else {
setTimeout(() => {
this.jieshuflag = true
}, 3000)
uni.showModal({
title: '提示',
content: res.msg,
showCancel: false,
confirmText: '知道了'
})
}
})
},
// 点击缴纳罚金继续还车
btnfajin() {
this.gethuan()
},
// 还车统一调用
gethuan() {
let that = this
uni.showModal({
title: '提示',
content: '您确定要还车吗?',
showCancel: true,
success: function(res) {
if (res.confirm) {
that.fjflag = false
that.wenbentxt = '车辆还车中...'
that.wenbentxtflag = true
let data = {
orderId: that.orderobj.orderId,
picture: that.imgs,
lon: that.lngsc,
lat: that.latsc,
requiredIot: true,
macList:that.scdevlist,
bltRemark:that.bltRemark
}
that.$u.put(`/app/order/end`, data).then(res => {
if (res.code == 200) {
that.cheflag = true
that.fjflag = false
that.wenbentxt = ''
that.wenbentxtflag = false
uni.showToast({
title: '还车成功',
icon: 'success',
duration: 2000
})
setTimeout(() => {
uni.navigateTo({
url: '/page_user/yongche/orderxq?id=' +that.orderobj.orderId
})
}, 1000)
} else if (res.code == 20001) {
if (that.ver_dataflag == 3) {
that.wenbentxt = '蓝牙还车中...'
xBlufi.notifySendCustomData({
customData: "11llosesub300@"
})
setTimeout(() => {
xBlufi.notifySendCustomData({
customData: "11reboot@"
})
}, 2000)
that.fjflag = false
let data = {
orderId: that.orderobj.orderId,
picture: that.imgs,
lon: that.lon,
lat: that.lat,
requiredIot: false,
macList:that.scdevlist,
bltRemark:that.bltRemark
}
that.$u.put(`/app/order/end`, data).then(res => {
if (res.code == 200) {
setTimeout(() => {
that.wenbentxt = ''
that.wenbentxtflag = false
setTimeout(() => {
uni.navigateTo({
url: '/page_user/yongche/orderxq?id=' +that.orderobj.orderId
})
}, 1000)
}, 2000)
} else if (res.msg == null) {
that.wenbentxt = ''
that.wenbentxtflag = false
uni.showToast({
title: '未知错误',
icon: 'none',
duration: 2000
})
} else {
that.wenbentxt = ''
that.wenbentxtflag = false
uni.showModal({
title: '提示',
content: res.msg,
showCancel: false,
success: function(res) {
if (res.confirm) {
} else if (res.cancel) {
}
}
})
}
})
} else {
that.wenbentxt = '蓝牙还车中...'
const findDevice = () => {
that.ver_dataflag = 2
const matchedDevice = that.devicesarr.find(device => {
return device.name.slice(-12) == that.mac.slice(-12)
})
if (matchedDevice) {
xBlufi.notifyStartDiscoverBle({
'isStart': false
})
xBlufi.notifyConnectBle({
isStart: true,
deviceId: matchedDevice.deviceId,
name: matchedDevice.name
})
that.deviceid = matchedDevice.deviceId
that.devicename = matchedDevice.name
setTimeout(() => {
if (that.ver_dataflag == 3) {
that.fjflag = false
let data = {
orderId: that.orderobj.orderId,
picture: that.imgs,
lon: that.lon,
lat: that.lat,
requiredIot: false,
macList:that.scdevlist,
bltRemark:that.bltRemark
}
that.$u.put(`/app/order/end`, data).then(res => {
if (res.code == 200) {
xBlufi.notifySendCustomData({
customData: "11close@"
})
setTimeout(() => {
xBlufi.notifySendCustomData({
customData: "11reboot@"
})
that.wenbentxt =''
that.wenbentxtflag =false
setTimeout(() => {
uni.navigateTo({
url: '/page_user/yongche/orderxq?id=' +that.orderobj.orderId
})
},1000)
}, 2000)
} else if (res.msg == null) {
that.wenbentxt = ''
that.wenbentxtflag =false
that.orderflag =true
uni.showToast({
title: '未知错误',
icon: 'none',
duration: 2000
})
} else {
that.wenbentxt = ''
that.wenbentxtflag =false
that.orderflag =true
uni.showModal({
title: '提示',
content: res.msg,
showCancel: false,
success: function(res) {
if (res.confirm) {
} else if (res.cancel) {
}
}
})
}
})
} else {
that.ver_dataflag = 1
that.shibainum = 0
that.wenbentxt = ''
that.wenbentxtflag = false
that.orderflag = true
that.ljsbflag = true
that.chongshinum = '还车'
uni.openBluetoothAdapter({
success: function (res) {
},
fail: function (err) {
console.error('蓝牙适配器初始化失败', err)
// 蓝牙未打开或初始化失败
if(err.errMsg == 'openBluetoothAdapter:fail auth deny'){
uni.showToast({
title: '请检查微信蓝牙权限是否授权',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail open fail'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail:not available'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}
}
})
}
}, 4000)
} else {
if (that.shibainum < 3) {
that.shibainum++
that.findDeviceTimer = setTimeout(findDevice.bind(that), 1000) // 使用 bind 保持 this 上下文
} else {
that.ver_dataflag = 1
that.shibainum = 0
that.wenbentxt = ''
that.wenbentxtflag = false
that.orderflag = true
that.ljsbflag = true
that.chongshinum = '还车'
let lanya = ''
if (that.jiance == true) {
lanya = '蓝牙未开启'
} else {
lanya = '蓝牙已开启'
}
let data = {
mac: that.mac,
orderId: that.orderobj.orderId,
reason: '用户蓝牙还车失败' + lanya,
command: '11close@',
lat: that.lat,
lon: that.lon,
result: '失败'
}
that.$u.post(`/app/commandLog/bluetooth`, data).then(res => {})
uni.openBluetoothAdapter({
success: function (res) {
},
fail: function (err) {
console.error('蓝牙适配器初始化失败', err)
// 蓝牙未打开或初始化失败
if(err.errMsg == 'openBluetoothAdapter:fail auth deny'){
uni.showToast({
title: '请检查微信蓝牙权限是否授权',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail open fail'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail:not available'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}
}
})
}
}
}
findDevice()
}
} else if (res.msg == null) {
that.wenbentxt = ''
that.wenbentxtflag = false
that.orderflag = true
uni.showToast({
title: '未知错误',
icon: 'none',
duration: 2000
})
} else {
that.wenbentxt = ''
that.wenbentxtflag = false
that.orderflag = true
uni.showModal({
title: '提示',
content: res.msg,
showCancel: false,
success: function(res) {
if (res.confirm) {
} else if (res.cancel) {
}
}
})
}
})
} else if (res.cancel) {
that.wenbentxtflag = false
that.wenbentxt = ''
}
}
})
},
// 点击跳转到最近停车点
btntcd() {
uni.navigateTo({
url: '/pages/myorder/returned/tingche?areaId=' + this.orderobj.orderAreaId
})
},
// 点击故障上报
btnguzhang() {
uni.navigateTo({
url: '/page_user/guzhang/index?sn=' + this.orderobj.deviceSn
})
},
// 点击去进行换车
btnghbike(){
this.scdevlist = this.devicesarr.map(item => {
const name = item.name || ''
return name.slice(-12)
})
let that = this
uni.openBluetoothAdapter({
success: function (res) {
that.bltRemark = '蓝牙权限均已打开'
that.btnghbiks()
},
fail: function (err) {
console.error('蓝牙适配器初始化失败', err)
// 蓝牙未打开或初始化失败
if(err.errMsg == 'openBluetoothAdapter:fail auth deny'){
that.bltRemark = '微信蓝牙权限没有授权'
that.btnghbiks()
}else if(err.errMsg == 'openBluetoothAdapter:fail open fail'){
that.bltRemark = '手机蓝牙没有打开'
that.btnghbiks()
}else if(err.errMsg == 'openBluetoothAdapter:fail:not available'){
that.bltRemark = '手机蓝牙是否打开'
that.btnghbiks()
}else{
that.bltRemark = `其他错误 + ${err.errMsg}`
that.btnghbiks()
}
}
})
},
btnghbiks() {
this.caozuotext = '换车前请将车辆停放于运营区和停车区内'
if (this.jiance == true) {
xBlufi.initXBlufi(1)
xBlufi.notifyStartDiscoverBle({
'isStart': true
})
xBlufi.listenDeviceMsgEvent(true, this.funListenDeviceMsgEvent)
}
const findDevice = () => {
this.ver_dataflag = 2
const matchedDevice = this.devicesarr.find(device => {
return device.name.slice(-12) == this.mac.slice(-12)
})
if (matchedDevice) {
xBlufi.notifyStartDiscoverBle({
'isStart': false
})
uni.getLocation({
type: 'gcj02', // 国内地图更兼容
isHighAccuracy: true,
accuracy: 'best',
success: (res) => {
console.log('精确坐标:', res)
this.lslat = res.latitude
this.lslon = res.longitude
},
fail: (err) => {
console.error('获取位置失败:', err)
this.lslat = null
this.lslon = null
}
})
} else {
if (this.shibainum < 3) {
this.shibainum++
this.findDeviceTimer = setTimeout(findDevice.bind(this), 1000) // 使用 bind 保持 this 上下文
} else {
this.lslat = null
this.lslon = null
}
}
}
findDevice()
let that = this
that.wenbentxt = '车辆锁车中...'
that.wenbentxtflag = true
let data = {
orderId: that.orderobj.orderId,
lat: that.lslat,
lon: that.lslon,
requiredIot: true,
macList:that.scdevlist,
bltRemark:that.bltRemark
}
that.$u.put(`/app/order/closeDevice`,data).then((res) => {
if (res.code == 200) {
that.wenbentxt = ''
that.wenbentxtflag = false
uni.showToast({
title: '锁车成功',
icon: 'success',
duration: 2000
})
that.orderobj.deviceLockStatus = 0
setTimeout(() => {
uni.navigateTo({
url: '/page_user/huanbike?sn=' + that.orderobj.deviceSn +'&orderid=' + that.orderobj.orderId + '&deviceid=' + that.deviceid + '&devicename=' + that.devicename + '&macList=' + this.scdevlist
})
}, 1000)
} else if (res.code == 20001) {
if (that.ver_dataflag == 3) {
uni.getLocation({
type: 'gcj02', // 国内地图更兼容
isHighAccuracy: true,
accuracy: 'best',
success: (res) => {
console.log('精确坐标:', res)
that.lslat = res.latitude
that.lslon = res.longitude
},
fail: (err) => {
console.error('获取位置失败:', err)
that.lslat = null
that.lslon = null
}
})
that.orderobj.deviceLockStatus = 0
xBlufi.notifySendCustomData({
customData: "11llosesub300@",
})
setTimeout(() => {
that.wenbentxt = ''
that.wenbentxtflag = false
}, 2000)
let lanya = ''
if (that.jiance == true) {
lanya = '蓝牙未开启'
} else {
lanya = '蓝牙已开启'
}
let data = {
mac: that.mac,
reason: '临时锁车' + lanya,
command: '11llosesub300@',
longitude: that.lslon,
latitude: that.lslat,
result: '失败'
}
that.$u.post(`/app/commandLog/bluetooth`, data).then(res => {
console.log(res, '蓝牙')
})
let datas = {
orderId: that.orderobj.orderId,
lat: that.lslat,
lon: that.lslon,
requiredIot: true,
macList:that.scdevlist,
bltRemark:that.bltRemark
}
that.$u.put(`/app/order/closeDevice`,datas).then((res) => {})
uni.navigateTo({
url: '/page_user/huanbike?sn=' + that.orderobj.deviceSn + '&orderid=' +that.orderobj.orderId + '&deviceid=' + that.deviceid + '&devicename=' +that.devicename + '&macList=' + that.scdevlist
})
} else {
that.wenbentxt = '车辆锁车中...'
const findDevice = () => {
that.ver_dataflag = 2
const matchedDevice = that.devicesarr.find(device => {
return device.name.slice(-12) == that.mac.slice(-12)
})
if (matchedDevice) {
xBlufi.notifyStartDiscoverBle({
'isStart': false
})
xBlufi.notifyConnectBle({
isStart: true,
deviceId: matchedDevice.deviceId,
name: matchedDevice.name
})
that.deviceid = matchedDevice.deviceId
that.devicename = matchedDevice.name
setTimeout(() => {
if (that.ver_dataflag == 3) {
uni.getLocation({
type: 'gcj02', // 国内地图更兼容
isHighAccuracy: true,
accuracy: 'best',
success: (res) => {
console.log('精确坐标:', res)
that.lslat = res.latitude
that.lslon = res.longitude
},
fail: (err) => {
console.error('获取位置失败:', err)
that.lslat = null
that.lslon = null
}
})
that.orderobj.deviceLockStatus = 0
xBlufi.notifySendCustomData({
customData: "11llosesub300@",
})
setTimeout(() => {
xBlufi.notifySendCustomData({
customData: "11reboot@"
})
that.wenbentxt = ''
that.wenbentxtflag = false
}, 2000)
let lanya = ''
if (that.jiance == true) {
lanya = '蓝牙未开启'
} else {
lanya = '蓝牙已开启'
}
let data = {
mac: that.mac,
reason: '临时锁车' + lanya,
command: '11llosesub300@',
longitude: that.lslon,
latitude: that.lslat,
result: '成功'
}
that.$u.post(`/app/commandLog/bluetooth`, data).then(res => {
console.log(res, '蓝牙')
})
let datas = {
orderId: that.orderobj.orderId,
lat: that.lslat,
lon: that.lslon,
requiredIot: true,
macList:that.scdevlist,
bltRemark:that.bltRemark
}
that.$u.put(`/app/order/closeDevice`,datas).then((res) => {})
uni.navigateTo({
url: '/page_user/huanbike?sn=' + that.orderobj.deviceSn + '&orderid=' + that.orderobj.orderId + '&deviceid=' + that.deviceid +'&devicename=' + that.devicename + '&macList=' + this.scdevlist
})
} else {
that.ver_dataflag = 1
that.shibainum = 0
that.wenbentxt = ''
that.wenbentxtflag = false
that.ljsbflag = true
that.chongshinum = '换车'
uni.openBluetoothAdapter({
success: function (res) {
},
fail: function (err) {
console.error('蓝牙适配器初始化失败', err)
// 蓝牙未打开或初始化失败
if(err.errMsg == 'openBluetoothAdapter:fail auth deny'){
uni.showToast({
title: '请检查微信蓝牙权限是否授权',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail open fail'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail:not available'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}
}
})
}
}, 4000)
} else {
if (that.shibainum < 3) {
that.shibainum++
that.findDeviceTimer = setTimeout(findDevice.bind(that),1000) // 使用 bind 保持 this 上下文
} else {
uni.getLocation({
type: 'gcj02', // 国内地图更兼容
isHighAccuracy: true,
accuracy: 'best',
success: (res) => {
console.log('精确坐标:', res)
that.lslat = res.latitude
that.lslon = res.longitude
},
fail: (err) => {
console.error('获取位置失败:', err)
that.lslat = null
that.lslon = null
}
})
that.ver_dataflag = 1
that.shibainum = 0
that.wenbentxt = ''
that.wenbentxtflag = false
that.ljsbflag = true
that.chongshinum = '换车'
let lanya = ''
if (that.jiance == true) {
lanya = '蓝牙未开启'
} else {
lanya = '蓝牙已开启'
}
let data = {
mac: that.mac,
orderId: that.orderobj.orderId,
reason: '用户蓝牙临时锁车失败' + lanya,
command: '11llosesub300@',
lat: that.lslat,
lon: that.lslon,
result: '失败'
}
that.$u.post(`/app/commandLog/bluetooth`, data).then(res => {})
uni.openBluetoothAdapter({
success: function (res) {
},
fail: function (err) {
console.error('蓝牙适配器初始化失败', err)
// 蓝牙未打开或初始化失败
if(err.errMsg == 'openBluetoothAdapter:fail auth deny'){
uni.showToast({
title: '请检查微信蓝牙权限是否授权',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail open fail'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail:not available'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}
}
})
}
}
}
findDevice()
}
} else {
that.wenbentxt = ''
that.wenbentxtflag = false
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
})
}
})
},
// 点击跳转导航
danghang() {
if (this.orderobj.deviceLatitude && this.orderobj.deviceLongitude) {
uni.openLocation({
latitude: this.orderobj.deviceLatitude, //纬度-目的地/坐标点
longitude: this.orderobj.deviceLongitude, //经度-目的地/坐标点
name: '', //地点名称
address: '' //详细地点名称
})
} else {
uni.showToast({
title: '车辆暂无法导航',
icon: 'none',
duration: 2000
})
}
},
// 点击启动and关闭
btnqd(){
this.scdevlist = this.devicesarr.map(item => {
const name = item.name || ''
return name.slice(-12)
})
let that = this
uni.openBluetoothAdapter({
success: function (res) {
that.bltRemark = '蓝牙权限均已打开'
that.btnqs()
},
fail: function (err) {
console.error('蓝牙适配器初始化失败', err)
// 蓝牙未打开或初始化失败
if(err.errMsg == 'openBluetoothAdapter:fail auth deny'){
that.bltRemark = '微信蓝牙权限没有授权'
that.btnqs()
}else if(err.errMsg == 'openBluetoothAdapter:fail open fail'){
that.bltRemark = '手机蓝牙没有打开'
that.btnqs()
}else if(err.errMsg == 'openBluetoothAdapter:fail:not available'){
that.bltRemark = '手机蓝牙是否打开'
that.btnqs()
}else{
that.bltRemark = `其他错误 + ${err.errMsg}`
that.btnqs()
}
}
})
},
btnqs() {
this.caozuotext = '骑行前请检查车轿刹车是否灵敏,安全骑行'
if (this.jiance == true) {
xBlufi.initXBlufi(1)
xBlufi.notifyStartDiscoverBle({
'isStart': true
})
xBlufi.listenDeviceMsgEvent(true, this.funListenDeviceMsgEvent)
}
this.$u.get("/app/orderDevice/mineUsing").then((res) => {
if (res.code == 200) {
if (res.data) {
if (res.data.deviceStatus == 9) {
uni.showModal({
title: '提示',
content: '超出运营区车辆已被强制锁车,请返回运营区或联系客服',
showCancel: false,
success: function(res) {
if (res.confirm) {
}
}
})
} else {
if (res.data.deviceLockStatus == 0) {
uni.getLocation({ //获取手机定位
type: 'gcj02', // 国内地图更兼容
isHighAccuracy: true,
accuracy: 'best',
success: (res) => {
console.log('精确坐标:', res)
this.lslat = res.latitude
this.lslon = res.longitude
},
fail: (err) => {
console.error('获取位置失败:', err)
this.lslat = null
this.lslon = null
}
})
let that = this
uni.showModal({
title: '提示',
content: '您是否要解锁车辆?',
showCancel: true,
success: function(res) {
if (res.confirm) {
that.wenbentxt = '车辆解锁中...'
that.wenbentxtflag = true
let dataks = {
orderId: that.orderobj.orderId,
lat: that.lslat,
lon: that.lslon,
requiredIot: true,
bltRemark:that.bltRemark
}
that.$u.put('/app/order/openDevice',dataks).then((res) => {
if (res.code == 200) {
that.wenbentxt = ''
that.wenbentxtflag = false
uni.showToast({
title: '解锁成功',
icon: 'success',
duration: 2000
})
that.orderobj.deviceLockStatus = 1
} else if (res.code == 20001) {
that.wenbentxt = '蓝牙解锁中...'
const findDevice = () => {
that.ver_dataflag = 2
const matchedDevice = that.devicesarr.find(device => {
return device.name.slice(-12) ==that.mac.slice(-12)
})
if (matchedDevice) {
xBlufi.notifyStartDiscoverBle({
'isStart': false
})
xBlufi.notifyConnectBle({
isStart: true,
deviceId: matchedDevice.deviceId,
name: matchedDevice.name
})
that.deviceid =matchedDevice.deviceId
that.devicename =matchedDevice.name
setTimeout(() => {
if (that.ver_dataflag ==3) {
xBlufi.notifySendCustomData({
customData: "11opensub5@"
})
that.wenbentxt =''
that.wenbentxtflag =false
that.orderobj.deviceLockStatus =1
let datakss = {
orderId: that.orderobj.orderId,
lat: that.lslat,
lon: that.lslon,
requiredIot: false,
bltRemark:that.bltRemark
}
that.$u.put('/app/order/openDevice',datakss).then((res) => {})
} else {
that.ver_dataflag =1
that.shibainum =0
that.wenbentxt =''
that.wenbentxtflag =false
uni.hideLoading()
that.ljsbflag =true
that.chongshinum ='解锁'
}
}, 4000)
} else {
if (that.shibainum < 3) {
that.shibainum++
that.findDeviceTimer = setTimeout(findDevice.bind(that),1000) // 使用 bind 保持 this 上下文
} else {
that.ver_dataflag = 1
that.shibainum = 0
that.wenbentxt = ''
that.wenbentxtflag =false
uni.hideLoading()
that.ljsbflag = true
that.chongshinum = '解锁'
let lanya = ''
if (that.jiance ==true) {
lanya = '蓝牙未开启'
} else {
lanya = '蓝牙已开启'
}
let data = {
mac: that.mac,
orderId: that.orderobj.orderId,
reason: '用户蓝牙解锁失败' +lanya,
command: '11opensub5@',
lat: that.lslat,
lon: that.lslon,
result: '失败',
}
that.$u.post(`/app/commandLog/bluetooth`,data).then(res => {})
uni.openBluetoothAdapter({
success: function (res) {
},
fail: function (err) {
console.error('蓝牙适配器初始化失败', err)
// 蓝牙未打开或初始化失败
if(err.errMsg == 'openBluetoothAdapter:fail auth deny'){
uni.showToast({
title: '请检查微信蓝牙权限是否授权',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail open fail'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail:not available'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}
}
})
}
}
}
findDevice()
} else {
uni.hideLoading()
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
})
}
})
}
}
})
} else if (res.data.deviceLockStatus == 1) {
uni.getLocation({
type: 'gcj02', // 国内地图更兼容
isHighAccuracy: true,
accuracy: 'best',
success: (res) => {
console.log('精确坐标:', res)
this.lslat = res.latitude
this.lslon = res.longitude
},
fail: (err) => {
console.error('获取位置失败:', err)
this.lslat = null
this.lslon = null
}
})
let that = this
uni.showModal({
title: '提示',
content: '您是否要临时锁车?',
showCancel: true,
success: function(res) {
if (res.confirm) {
that.wenbentxt = '车辆临时锁车中...'
that.wenbentxtflag = true
let data = {
orderId: that.orderobj.orderId,
lat: that.lslat,
lon: that.lslon,
requiredIot: true,
macList:that.scdevlist,
bltRemark:that.bltRemark
}
that.$u.put(`/app/order/closeDevice`,data).then((res) => {
if (res.code == 200) {
that.wenbentxt = ''
that.wenbentxtflag = false
uni.showToast({
title: '临时锁车成功',
icon: 'success',
duration: 2000
})
that.orderobj.deviceLockStatus = 0
} else if (res.code == 20001) {
that.wenbentxt = '蓝牙临时锁车中...'
const findDevice = () => {
that.ver_dataflag = 2
const matchedDevice = that.devicesarr.find(device => {
return device.name.slice(-12) ==that.mac.slice(-12)
})
if (matchedDevice) {
xBlufi.notifyStartDiscoverBle({
'isStart': false
})
xBlufi.notifyConnectBle({
isStart: true,
deviceId: matchedDevice.deviceId,
name: matchedDevice.name
})
that.deviceid =matchedDevice.deviceId
that.devicename =matchedDevice.name
setTimeout(() => {
if (that.ver_dataflag ==3) {
that.orderobj.deviceLockStatus =0
xBlufi.notifySendCustomData({
customData: "11llosesub300@",
})
setTimeout(() => {
xBlufi.notifySendCustomData({
customData: "11reboot@"
})
that.wenbentxt =''
that.wenbentxtflag =false
},2000)
let lanya =''
if (that.jiance ==true) {
lanya ='蓝牙未开启'
} else {
lanya ='蓝牙已开启'
}
let data = {
mac: that.mac,
reason: '临时锁车' +lanya,
command: '11llosesub300@',
longitude: that.lslon,
latitude: that.lslat,
result: '失败'
}
that.$u.post(`/app/commandLog/bluetooth`,data).then(res =>{console.log(res,'蓝牙')})
let datas = {
orderId: that.orderobj.orderId,
lat: that.lslat,
lon: that.lslon,
requiredIot: false,
macList:that.scdevlist,
bltRemark:that.bltRemark
}
that.$u.put(`/app/order/closeDevice`,datas).then((res) => {})
} else {
that.ver_dataflag = 1
that.shibainum = 0
that.wenbentxt = ''
that.wenbentxtflag = false
that.ljsbflag = true
that.chongshinum = '锁车'
uni.openBluetoothAdapter({
success: function (res) {
},
fail: function (err) {
console.error('蓝牙适配器初始化失败', err)
// 蓝牙未打开或初始化失败
if(err.errMsg == 'openBluetoothAdapter:fail auth deny'){
uni.showToast({
title: '请检查微信蓝牙权限是否授权',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail open fail'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail:not available'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}
}
})
}
}, 4000)
} else {
if (that.shibainum < 3) {
that.shibainum++
that.findDeviceTimer = setTimeout(findDevice.bind(that),1000) // 使用 bind 保持 this 上下文
} else {
that.ver_dataflag = 1
that.shibainum = 0
that.wenbentxt = ''
that.wenbentxtflag = false
that.ljsbflag = true
that.chongshinum = '锁车'
let lanya = ''
if (that.jiance == true) {
lanya = '蓝牙未开启'
} else {
lanya = '蓝牙已开启'
}
let data = {
mac: that.mac,
orderId: that.orderobj.orderId,
reason: '用户蓝牙临时锁车失败' +lanya,
command: '11llosesub300@',
lat: that.lslat,
lon: that.lslon,
result: '失败'
}
that.$u.post(`/app/commandLog/bluetooth`,data).then(res => {})
uni.openBluetoothAdapter({
success: function (res) {
},
fail: function (err) {
console.error('蓝牙适配器初始化失败', err)
// 蓝牙未打开或初始化失败
if(err.errMsg == 'openBluetoothAdapter:fail auth deny'){
uni.showToast({
title: '请检查微信蓝牙权限是否授权',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail open fail'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}else if(err.errMsg == 'openBluetoothAdapter:fail:not available'){
uni.showToast({
title: '请检查手机蓝牙是否打开',
icon: 'none',
duration:5000
})
}
}
})
}
}
}
findDevice()
} else {
that.wenbentxt = ''
that.wenbentxtflag = false
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
})
}
})
} else if (res.cancel) {
console.log('取消') // 用户点击取消
}
}
})
}
}
} else {
uni.navigateTo({
url: '/page_user/yongche/orderxq?id=' + this.orderobj.orderId
})
}
} else if (res.code == 40001) {
uni.navigateTo({
url: '/page_user/yongche/orderxq?id=' + this.orderobj.orderId
})
}
})
},
// 获取本人正在使用的订单设备
getorderdevice() {
this.$u.get("/app/orderDevice/mineUsing").then((res) => {
if (res.code == 200) {
if (res.data) {
this.orderobj = res.data
this.orderAreaReturnVerify = res.data.orderAreaReturnVerify
this.orderAreaId = res.data.orderAreaId
this.areaId = res.data.orderAreaId
this.deviceMac = res.data.deviceMac
this.mac = res.data.deviceMac
this.orderflag = true
this.isPageActive = true
this.gethuiyuan()
this.getMyLocation()
this.initWebSocket() //WebSocket接受数据
this.$u.get(`/app/area/detail?id=${this.orderAreaId}`).then((res) => {
if (res.code == 200) {
this.enableChange = res.data.enableChange
const polylines = this.convertBoundaryToPolyline(res.data.boundaryStr)
this.polyline.push(polylines)
this.getParking()
}
})
this.startRideTimer()
// 如果有数据,启动定时器每分钟执行一次
this.startOrderDeviceTimer()
} else {
uni.reLaunch({
url: '/pages/nearbystores/index'
})
this.orderAreaId = ''
this.orderflag = false
this.newMarkers = ''
console.log(this.covers)
this.stopRideTimer()
this.rideDurationText = '00:00'
// 如果没有数据,停止定时器
this.stopOrderDeviceTimer()
}
}
})
},
// 请求会员卡列表
gethuiyuan() {
this.$u.get(`/app/vip/listByArea?areaId=${this.areaId}`).then(res => {
if (res.code == 200) {
this.huiyuanlist = res.data
}
})
},
// 点击跳转到购买会员列表
btnhuiyuan() {
uni.navigateTo({
url: '/page_fenbao/huiyuan/index?areaId=' + this.areaId
})
},
// 启动订单设备定时器
startOrderDeviceTimer() {
// 先清除可能存在的定时器
this.stopOrderDeviceTimer()
// 创建新的定时器,每分钟执行一次
this.orderDeviceTimer = setInterval(() => {
// 检查页面是否活跃
if (!this.isPageActive) {
this.stopOrderDeviceTimer()
return
}
// 执行获取订单设备的请求
this.$u.get("/app/orderDevice/mineUsing").then((res) => {
if (res.code == 200) {
if (res.data) {
// 更新订单数据
this.orderobj = res.data
this.orderAreaReturnVerify = res.data.orderAreaReturnVerify
this.orderAreaId = res.data.orderAreaId
this.areaId = res.data.orderAreaId
this.deviceMac = res.data.deviceMac
this.mac = res.data.deviceMac
this.orderflag = true
this.isPageActive = true
this.computeRideDurationText()
if (!this.rideTimer) this.startRideTimer()
// 如果WebSocket连接断开重新连接
if (!this.socketTask || this.socketTask.readyState !== 1) {
this.initWebSocket()
}
} else {
// 如果没有数据,停止定时器
this.orderAreaId = ''
this.orderflag = false
this.newMarkers = ''
this.stopRideTimer()
this.rideDurationText = '00:00'
this.stopOrderDeviceTimer()
}
}
}).catch(err => {
console.error('定时获取订单设备失败:', err)
// 发生错误时也停止定时器
this.stopOrderDeviceTimer()
})
}, 60000) // 60000毫秒 = 1分钟
},
// 停止订单设备定时器
stopOrderDeviceTimer() {
if (this.orderDeviceTimer) {
clearInterval(this.orderDeviceTimer)
this.orderDeviceTimer = null
console.log('订单设备定时器已停止')
}
},
// // 请求客服
// getkefu() {
// this.$u.get(`/app/customerService/list?pageNum=1&pageSize=999`).then(res => {
// if (res.code == 200) {
// this.kefulist = res.rows
// }
// })
// },
// 点击去下单
btndetaxq() {
this.$u.get(`/getInfo`).then(res => {
if (res.code == 200) {
this.taocanflag = false
uni.setStorageSync('user', res.user)
uni.navigateTo({
url: '/page_fenbao/storedlist/trueorder?modelId=' + this.cheobj.modelId + '&sn=' + this.cheobj.sn
})
} else if (res.code == 401) {
uni.showModal({
title: '提示',
content: '您当前未登录,是否前去登录?',
showCancel: true,
success: function(res) {
if (res.confirm) {
uni.reLaunch({
url: '/pages/login/login'
})
} else if (res.cancel) {
}
}
})
}
})
},
// 点击响铃寻车
btnxlxc() {
let data = {
id:this.orderobj.deviceId,
lat:this.xllat,
lon:this.xllng,
macList:this.scdevlist
}
this.$u.put(`/app/device/iot/ring`,data).then((res) => {
if (res.code == 200) {
uni.showToast({
title: '操作成功',
icon: 'success',
duration: 2000
})
} else if (res.code == 401) {
uni.showModal({
title: '提示',
content: '您当前未登录,是否前去登录?',
showCancel: true,
success: function(res) {
if (res.confirm) {
uni.reLaunch({
url: '/pages/login/login'
})
} else if (res.cancel) {
}
}
})
} else {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
})
}
})
},
// 点击隐藏车辆弹窗
btncheyc() {
this.taocanflag = false
this.newMarkers = ''
},
// 点击选择骑行套餐
btntcxz(index) {
this.tcindex = index
},
// 点击跳转到帮助中心
btnbz() {
uni.navigateTo({
url: '/page_user/bangzhu'
})
},
// 点击拨打平台客服电话
btnptkf(tel) {
uni.makePhoneCall({
phoneNumber: tel,
success: function(res) {
console.log('拨打电话成功', res)
},
fail: function(err) {
console.error('拨打电话失败', err)
}
})
},
// 点击跳转到租车门店
btnmendain() {
uni.navigateTo({
url: '/page_fenbao/storedlist/index'
})
},
// 点击右侧图标
btntap(num) {
if (num == 3) {
uni.showToast({
title: '导览暂未开放',
icon: 'none',
duration: 2000
})
} else {
this.covers = []
this.rtindex = num
this.shoptcflag = false
this.getqingqiu()
}
},
// 点击调用回到地图中心点
btnhuiz() {
this.setMapScale()
},
// 回到地图中心点
async setMapScale(e, val) {
console.log(e,val);
let mapContext = uni.createMapContext('map', this);
let setScale = () => {
return new Promise((resolve, reject) => {
mapContext.getScale({
success: r => {
resolve()
}
})
})
};
await setScale()
mapContext.moveToLocation({
success: (res) => {
const timer = setTimeout(() => {
clearTimeout(timer)
}, 500)
}
})
},
// 请求附近车辆and门店
getqingqiu() {
if (this.rtindex == 1) {
this.iconPath = 'https://api.ccttiot.com/smartmeter/img/static/upX2lLilhrRi4tttdHlo'
} else if (this.rtindex == 2) {
this.iconPath = this.iconobj.mappic
this.$u.get(`/app/device/listNearBy?radius=10000&center=${this.jingweidu}&areaId=${this.orderobj.orderAreaId == undefined ? null : this.orderobj.orderAreaId}`).then((res) => {
if (res.code == 200) {
this.covers = []
this.listData = []
this.$set(this, 'covers', [...this.covers, ...this.newMarkers])
if (this.sockedata.latitude) {
this.covers.push({
latitude: this.sockedata.latitude,
longitude: this.sockedata.longitude,
width: 8,
height: 8,
iconPath: 'https://api.ccttiot.com/smartmeter/img/static/uow9Zq3edTUYCVHI9H60',
})
}
this.listData = res.data
res.data.forEach(item => {
const shopCover = {
// 门店后面拼接1车辆拼接23是导览
id: this.rtindex == 1 ? parseInt(item.id + "1") : this.rtindex == 2 ? parseInt(item.id + "2") : parseInt(item.id + "3"),
latitude: item.latitude,
longitude: item.longitude,
width: 35,
height: 40,
iconPath: item.modelIcon == null ? this.iconPath : item.modelIcon,
callout: {
content: item.vehicleNum == null ? item.sn : '' + item.vehicleNum, // 修改为你想要显示的文字内容
color: '#0D75E5', // 修改为文字颜色
fontSize: 10, // 修改为文字大小
borderRadius: 10, // 修改为气泡圆角大小
bgColor: '#fff', // 修改为气泡背景颜色
padding: 3, // 修改为气泡内边距
display: 'ALWAYS', // 修改为气泡的显示策略
}
}
this.covers.push(shopCover)
})
}
})
} else if (this.rtindex == 3) {
this.iconPath = 'https://api.ccttiot.com/smartmeter/img/static/un7ecyEN8vsJhlEnXfD4'
} else {
this.iconPath = null
}
},
// 获取自身位置
getMyLocation() {
uni.getLocation({
type: 'gcj02',
success: (res) => {
this.latitude = Number(res.latitude) - 0.005
this.longitude = Number(res.longitude) + 0.005
this.jingweidu = this.longitude + ',' + this.latitude
this.getqingqiu()
},
fail: (err) => {
console.error('获取位置失败:', err)
}
})
},
convertBoundaryToPolyline(boundary) {
if (!boundary) return null
const points = JSON.parse(boundary).map(coord => ({
latitude: coord[1],
longitude: coord[0]
}))
const polyline = {
points: points,
fillColor: "#55888820",
strokeColor: "#22FF00",
strokeWidth: 1,
zIndex: 1,
isOperationArea: true
}
return polyline
},
convertBoundaryToPolylines(boundaries, num) {
if (!Array.isArray(boundaries)) {
console.error('边界数据不是数组:', boundaries)
return []
}
const polylines = boundaries.map(boundary => {
if (!boundary) {
console.warn('边界数据为空')
return null
}
let coords
try {
coords = JSON.parse(boundary)
} catch (error) {
console.error('解析边界JSON失败:', error)
return null
}
if (!Array.isArray(coords)) {
console.error('解析后的边界数据不是数组:', coords)
return null
}
const points = coords.map(coord => {
if (!Array.isArray(coord) || coord.length < 2) {
console.warn('坐标数据格式错误:', coord)
return null
}
return {
latitude: parseFloat(coord[1]),
longitude: parseFloat(coord[0])
}
}).filter(point => point !== null)
if (points.length < 3) {
console.warn('有效坐标点不足3个无法构成多边形')
return null
}
// 根据类型设置不同的样式
let style = {}
if (num == 1) { // 停车区
style = {
fillColor: "#88888850",
strokeColor: "#88888850",
strokeWidth: 1,
zIndex: 1,
isOperationArea: false
}
} else if (num == 2) { // 禁停区
style = {
fillColor: "#FFF5D640",
strokeColor: "#FF473E",
strokeWidth: 2,
zIndex: 1,
isOperationArea: false
}
} else if (num == 3) { // 禁行区
style = {
fillColor: "#FFD1CF40",
strokeColor: "#FFC107",
strokeWidth: 2,
zIndex: 1,
isOperationArea: false
}
} else if (num == 4) { // 景区
style = {
fillColor: "#4abd2040",
strokeColor: "#4abd20",
strokeWidth: 2,
zIndex: 1,
isOperationArea: false
}
}
return {
points: points,
...style
}
}).filter(polyline => polyline !== null)
return polylines
},
toggleIconAndCallout() {
if (this.cheobj == '') {
uni.showToast({
title: '请选选择车辆',
icon: 'none',
duration: 2000
})
} else {
this.showIconAndCallout = !this.showIconAndCallout
if (this.showIconAndCallout) {
const newMarkers = []
this.parkingList.forEach(item => {
newMarkers.push({
id: parseFloat(item.id),
latitude: parseFloat(item.latitude),
longitude: parseFloat(item.longitude),
width: 18,
height: 26,
iconPath: item.type == 1 ?
'https://lxnapi.ccttiot.com/bike/img/static/up2xXqAgwCX5iER600k3' :
item.type == 2 ?
'https://lxnapi.ccttiot.com/bike/img/static/uDNY5Q4zOiZTCBTA2Jdq' :
item.type == 3 ?
'https://lxnapi.ccttiot.com/bike/img/static/u53BAQcFIX3vxsCzEZ7t' :
'https://api.ccttiot.com/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20250829161752_210_17-1756455764351.png',
callout: {
content: item.name,
color: '#ffffff',
fontSize: 12,
borderRadius: 8,
bgColor: item.type == 1 ? '#3A7EDB' : item.type == 2 ? '#FF473E' : item
.type == 3 ? '#FFC107' : '#3bbd55',
padding: 4,
display: 'ALWAYS'
},
isCalloutVisible: true // 添加标记
})
})
this.newMarkers = newMarkers
this.$set(this, 'covers', [...this.covers, ...newMarkers])
} else {
// 过滤掉所有气泡显示的标记
this.$set(this, 'covers', this.covers.filter(marker => !marker.isCalloutVisible))
}
}
},
getParking() {
this.$u.get(`/app/areaSub/listByArea?areaId=${this.areaId}`).then((res) => {
if (res.code === 200 && Array.isArray(res.data)) {
// 缓存数据
const filteredData = res.data.filter(item => item.status != 1);
this.cachedParkingData[this.areaId] = filteredData
const type1Data = []
const type2Data = []
const type3Data = []
const type4Data = []
filteredData.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)
else if (row.type == 4) type4Data.push(row)
})
const processBoundaries = (data, type) => {
const validBoundaries = data.map(row => row.boundaryStr).filter(boundary => boundary && typeof boundary === 'string' && boundary.trim() !== '')
if (validBoundaries.length > 0) {
const polylines = this.convertBoundaryToPolylines(validBoundaries, type)
if (polylines && polylines.length > 0) {
return polylines
}
}
return []
}
// 先处理所有边界数据
const type1Polylines = processBoundaries(type1Data, 1)
const type2Polylines = processBoundaries(type2Data, 2)
const type3Polylines = processBoundaries(type3Data, 3)
const type4Polylines = processBoundaries(type4Data, 4)
// 保留现有的运营区边界
const operationAreaPolylines = this.polyline.filter(p => p.isOperationArea)
// 合并所有边界数据
const allPolylines = [
...operationAreaPolylines,
...type1Polylines,
...type2Polylines,
...type3Polylines,
...type4Polylines
]
// 缓存多边形数据
this.cachedPolyline = allPolylines
// 更新显示
this.polyline = allPolylines
this.parkingList = filteredData
this.isFirstLoad = false
}
})
},
updatePolylineFromCache() {
// 保留现有的运营区边界
const operationAreaPolylines = this.polyline.filter(p => p.isOperationArea)
// 从缓存中获取其他边界数据
const otherPolylines = this.cachedPolyline.filter(p => !p.isOperationArea)
// 合并数据
const allPolylines = [...operationAreaPolylines, ...otherPolylines]
// 更新显示
this.polyline = allPolylines
},
// 请求运营区停车点,禁行区,
getArea() {
this.polyline = []
this.$u.get(`/app/area/detail?id=${this.areaId}`).then((res) => {
this.enableChange = res.data.enableChange
if (res.code == 200) {
const polylines = this.convertBoundaryToPolyline(res.data.boundaryStr)
this.polyline.push(polylines)
this.getParking()
}
})
},
// 第一次请求运营区停车点,禁行区,
getAone() {
this.$u.get(`/getInfo`).then(res => {
if (res.code == 200) {
this.user = res.user
this.$u.get(`/app/area/nearby?id=${res.user.areaId == null ? '' : res.user.areaId}&radius=1000&center=${this.jingweidu}&appId=${this.$store.state.appid}`).then((resp) => {
if (resp.code == 200) {
if (resp.data) {
this.yyid = resp.data.id
}
if (resp.data && resp.data.boundaryStr) {
const polylines = this.convertBoundaryToPolyline(resp.data.boundaryStr)
if (polylines) {
this.polyline = [polylines]
this.getParking()
if (resp.data && resp.data.id) {
this.loadNearbyDevices(resp.data.id)
}
}
}
}
})
}
})
},
loadNearbyDevices(areaId) {
if (this.rtindex == 2) {
this.$u.get(`/app/device/listNearBy?radius=10000&center=${this.jingweidu}&areaId=${areaId}`).then((res) => {
if (res.code == 200) {
this.listData = res.data
this.updateMarkers()
}
})
}
},
updateMarkers() {
const newMarkers = []
this.listData.forEach(item => {
if (item.latitude && item.longitude) {
const marker = {
id: this.rtindex == 1 ? parseInt(item.id + "1") : this.rtindex == 2 ? parseInt(item.id + "2") : parseInt(item.id + "3"),
latitude: parseFloat(item.latitude),
longitude: parseFloat(item.longitude),
width: 35,
height: 40,
iconPath: item.modelIcon == null ? this.getIconPath() : item.modelIcon,
callout: {
content: item.vehicleNum || item.sn || '',
color: '#0D75E5',
fontSize: 10,
borderRadius: 10,
bgColor: '#fff',
padding: 3,
display: 'ALWAYS'
}
}
newMarkers.push(marker)
}
})
this.tempCovers = newMarkers
this.covers = this.tempCovers
},
getIconPath() {
if (this.rtindex == 1) {
return 'https://api.ccttiot.com/smartmeter/img/static/upX2lLilhrRi4tttdHlo'
} else if (this.rtindex == 2) {
return this.iconobj.mappic
} else if (this.rtindex == 3) {
return 'https://api.ccttiot.com/smartmeter/img/static/un7ecyEN8vsJhlEnXfD4'
}
return null
},
updatePolyline(newPolylines) {
// 使用Vue的响应式更新
this.tempPolyline = [...newPolylines]
this.polyline = this.tempPolyline
},
updateCovers(newCovers) {
// 使用Vue的响应式更新
this.tempCovers = [...newCovers]
this.covers = this.tempCovers
},
}
}
</script>
<style lang="scss">
.gonggao{
width: 682rpx;
height: 72rpx;
overflow: hidden;
background: #FFFFFF;
box-shadow: 0rpx 4rpx 10rpx 0rpx rgba(0,0,0,0.3);
border-radius: 53rpx 53rpx 53rpx 53rpx;
position: fixed;
left: 50%;
transform: translateX(-50%);
z-index: 99;
display: flex;
align-items: center;
margin-bottom: 10rpx;
margin: auto;
padding-left: 70rpx;
.container{
width: 560rpx;
overflow: hidden;
height: 72rpx;
line-height: 72rpx;
}
}
page {
background: #fff;
border-radius: 0rpx 0rpx 0rpx 0rpx;
}
@keyframes gifLoop {
0% {
opacity: 1;
}
100% {
opacity: 1;
}
}
.active {
image {
z-index: 99 !important;
}
.bike_item {
border: 1px solid #4297F3 !important;
}
}
.daohang {
width: 750rpx;
height: 652rpx;
background: #FFFFFF;
box-shadow: 0rpx 10rpx 64rpx 0rpx rgba(0, 0, 0, 0.08);
position: fixed;
left: 0;
bottom: 0;
border-radius: 30rpx 30rpx 0 0;
padding: 44rpx 38rpx;
box-sizing: border-box;
.cha {
font-size: 60rpx;
font-weight: 600;
position: absolute;
top: 30rpx;
right: 34rpx;
}
.name {
font-weight: 600;
font-size: 44rpx;
color: #3D3D3D;
display: flex;
align-items: center;
text {
padding: 6rpx 10rpx;
background-color: #0D75E5;
color: #fff;
margin-left: 10rpx;
border-radius: 6rpx;
font-size: 26rpx;
}
}
.shuom {
font-weight: 600;
font-size: 32rpx;
color: #808080;
margin-top: 22rpx;
}
image {
width: 680rpx;
height: 234rpx;
margin-top: 30rpx;
}
.anniu {
width: 682rpx;
height: 90rpx;
background: #4C97E7;
border-radius: 54rpx 54rpx 54rpx 54rpx;
font-weight: 600;
font-size: 40rpx;
color: #FFFFFF;
text-align: center;
line-height: 90rpx;
margin-top: 62rpx;
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes rotate360 {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes pulse {
0%,
100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.1);
opacity: 0.8;
}
}
.tongyi {
width: 100%;
height: 580rpx;
background: #FFFFFF;
border-radius: 3rpx 3rpx 0rpx 0rpx;
position: fixed;
bottom: 0;
left: 50%;
transform: translateX(-50%);
z-index: 97;
border-radius: 30rpx 30rpx 0 0;
text-align: center;
.anniu {
width: 100%;
display: flex;
justify-content: space-between;
margin-top: 30rpx;
.lx {
width: 338rpx;
height: 90rpx;
border-radius: 10rpx;
border: 2rpx solid #808080;
text-align: center;
line-height: 90rpx;
font-size: 40rpx;
color: #808080;
}
.zx {
width: 338rpx;
height: 90rpx;
background: #4C97E7;
border-radius: 10rpx;
text-align: center;
line-height: 90rpx;
font-size: 40rpx;
color: #FFFFFF;
}
}
.top {
display: flex;
justify-content: center;
align-items: center;
margin-top: 30rpx;
image {
width: 50rpx;
height: 50rpx;
margin-right: 8rpx;
animation: rotate360 1.2s linear infinite;
}
font-weight: 600;
font-size: 32rpx;
color: #3D3D3D;
.percentage-text {
margin-left: 10rpx;
font-size: 36rpx; // 增大字体与前方文字保持一致
color: #3D3D3D; // 使用与前方文字相同的颜色
font-weight: 600; // 与前方文字保持一致的字体粗细
animation: pulse 1.5s ease-in-out infinite;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
color: #000; // 悬停时变为黑色
transform: scale(1.05);
}
}
}
.tops {
margin-top: 30rpx;
image {
width: 50rpx;
height: 50rpx;
margin-right: 8rpx;
}
}
// 蓝牙连接失败样式
.bluetooth-error-container {
padding: 40rpx 30rpx;
text-align: left;
.error-header {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 40rpx;
.error-icon {
width: 40rpx;
height: 40rpx;
margin-right: 16rpx;
}
.error-title {
font-weight: 600;
font-size: 36rpx;
color: #333;
}
}
.error-steps {
margin-bottom: 40rpx;
.step-item {
display: flex;
align-items: center;
margin-bottom: 24rpx;
padding: 20rpx;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-radius: 16rpx;
border-left: 6rpx solid #4C97E7;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
&:hover {
transform: translateX(8rpx);
box-shadow: 0 8rpx 20rpx rgba(76, 151, 231, 0.15);
}
.step-number {
width: 48rpx;
height: 48rpx;
background: linear-gradient(135deg, #4C97E7 0%, #6BB6FF 100%);
color: #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 28rpx;
margin-right: 20rpx;
box-shadow: 0 4rpx 12rpx rgba(76, 151, 231, 0.3);
}
.step-text {
flex: 1;
font-size: 30rpx;
color: #333;
line-height: 1.5;
font-weight: 500;
}
}
}
.tutorial-link {
display: flex;
align-items: center;
justify-content: center;
padding: 24rpx 32rpx;
background: linear-gradient(135deg, #4C97E7 0%, #6BB6FF 100%);
border-radius: 50rpx;
box-shadow: 0 8rpx 24rpx rgba(76, 151, 231, 0.3);
transition: all 0.3s ease;
cursor: pointer;
&:hover {
transform: translateY(-4rpx);
box-shadow: 0 12rpx 32rpx rgba(76, 151, 231, 0.4);
}
&:active {
transform: translateY(-2rpx);
}
.tutorial-text {
color: #fff;
font-size: 32rpx;
font-weight: 600;
margin-right: 12rpx;
}
.tutorial-arrow {
color: #fff;
font-size: 32rpx;
font-weight: 600;
transition: transform 0.3s ease;
}
&:hover .tutorial-arrow {
transform: translateX(8rpx);
}
}
}
.ddc {
width: 610rpx;
height: 314rpx;
margin-top: 40rpx;
animation: gifLoop 1s infinite;
}
}
.fixdivce {
padding: 12rpx 22rpx 12rpx 22rpx;
position: fixed;
left: 0;
top: 34vh;
width: 280rpx;
height: 40vh;
background: #FFFFFF10;
border-radius: 0 40rpx 40rpx 0;
box-shadow: 0rpx 4rpx 10rpx 0rpx rgba(0, 0, 0, 0.3);
.scrollable-content::-webkit-scrollbar {
display: none;
}
.scrollable-content {
height: 100%;
overflow-y: auto;
.divce_li:last-child {
border-bottom: 1rpx solid #fff;
}
.divce_li {
padding: 10rpx 0;
display: flex;
flex-wrap: nowrap;
align-items: center;
border-bottom: 1rpx solid #D8D8D8;
.left_img {
image {
width: 44rpx;
height: 70rpx;
}
}
.right_cont {
margin-left: 20rpx;
display: flex;
flex-wrap: wrap;
font-weight: 400;
font-size: 24rpx;
color: #3D3D3D;
.right_top {
width: 100%;
display: flex;
flex-wrap: nowrap;
align-items: center;
.right_top_left {
margin-left: auto;
display: flex;
flex-wrap: nowrap;
align-items: center;
image {
margin-right: 6rpx;
width: 12rpx;
height: 26rpx;
}
}
.right_top_right {}
}
.right_bot {
width: 100%;
display: flex;
flex-wrap: nowrap;
justify-content: space-between;
margin-top: 8rpx;
}
}
}
}
}
.mask {
width: 100%;
height: 100vh;
position: fixed;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, .3);
z-index: 9;
}
.tingchetc {
width: 100%;
height: 700rpx;
background: #FFFFFF;
border-radius: 20rpx 20rpx 20rpx 20rpx;
position: fixed;
left: 50%;
transform: translateX(-50%);
bottom: 0;
z-index: 99;
padding: 28rpx 36rpx;
box-sizing: border-box;
.btnan {
display: flex;
justify-content: space-between;
margin-top: 40rpx;
.fj {
width: 320rpx;
height: 90rpx;
border-radius: 10rpx;
border: 2rpx solid #808080;
font-weight: 600;
font-size: 32rpx;
color: #808080;
text-align: center;
line-height: 90rpx;
}
.qx {
width: 330rpx;
height: 90rpx;
background: #4C97E7;
border-radius: 10rpx;
text-align: center;
line-height: 90rpx;
box-sizing: border-box;
font-weight: 600;
font-size: 32rpx;
color: #FFFFFF;
}
}
.tcimg {
width: 668rpx;
height: 360rpx;
margin-top: 28rpx;
animation: gifLoop 1s infinite;
}
.shuom {
font-size: 26rpx;
color: #3D3D3D;
margin-top: 18rpx;
text {
color: #4C97E7;
}
}
.topname {
font-weight: 600;
font-size: 36rpx;
color: #3D3D3D;
display: flex;
align-items: center;
image {
width: 48rpx;
height: 48rpx;
margin-right: 14rpx;
}
}
}
.conts_box {
width: 100%;
height: 600rpx;
margin: 0 auto;
margin-top: 38rpx;
background: #FFFFFF;
box-shadow: 0rpx 10rpx 64rpx 0rpx rgba(0, 0, 0, 0.08);
border-radius: 30rpx 30rpx 20rpx 20rpx;
padding-bottom: 20rpx;
position: fixed;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
bottom: 0;
padding-bottom: 30rpx;
box-sizing: border-box;
.orderzt {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
border-bottom: 1px solid #F4F4F4;
padding: 0 54rpx;
position: relative;
background-color: #fff;
.qixing {
width: 100%;
height: 130rpx;
position: absolute;
top: -80rpx;
left: 0;
z-index: -1;
}
.NO {
font-weight: 600;
font-size: 32rpx;
color: #3D3D3D;
display: flex;
align-items: center;
image {
width: 58rpx;
height: 70rpx;
margin-right: 8rpx;
}
}
.huanche {
width: 150rpx;
height: 60rpx;
background-color: #0D75E5;
color: #fff;
text-align: center;
line-height: 60rpx;
font-size: 32rpx;
border-radius: 30rpx;
}
.icon {
display: flex;
align-items: center;
image {
width: 30rpx;
height: 36rpx;
}
}
}
.txtss {
margin-top: 18rpx;
padding-left: 20rpx;
width: 100%;
font-weight: 500;
font-size: 28rpx;
color: #808080;
}
.dh {
width: 160rpx;
height: 60rpx;
border-radius: 30rpx;
text-align: center;
border: 1px solid #333;
font-size: 28rpx;
padding-top: 10rpx;
box-sizing: border-box;
}
.suocheanniu {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
image {
width: 90rpx;
height: 88rpx;
}
.jsdd {
width: 190rpx;
height: 88rpx;
background: rgba(76, 151, 231, 0);
border-radius: 20rpx 20rpx 20rpx 20rpx;
border: 2rpx solid #A8A8A8;
text-align: center;
line-height: 88rpx;
font-weight: 600;
font-size: 36rpx;
color: #3D3D3D;
}
.lssc {
font-weight: 600;
font-size: 36rpx;
color: #FFFFFF;
width: 240rpx;
height: 88rpx;
text-align: center;
line-height: 88rpx;
background: #4C97E7;
border-radius: 20rpx 20rpx 20rpx 20rpx;
}
}
.botbtn {
display: flex;
width: 100%;
justify-content: space-between;
margin-top: 30rpx;
padding: 0 30rpx;
}
.imgpic {
display: flex;
margin-top: 10rpx;
padding: 0 54rpx;
image {
width: 152rpx;
height: 38rpx;
margin-right: 16rpx;
}
.gzimg {
width: 152rpx;
height: 38rpx;
margin-right: 16rpx;
}
.hcimg {
width: 162rpx;
height: 38rpx;
}
}
.cont_li {
width: 100%;
display: flex;
flex-wrap: nowrap;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
padding: 0 54rpx;
background-color: #fff;
.one {
text-align: center;
.oneone {
font-weight: 600;
font-size: 52rpx;
color: #3D3D3D;
margin-top: 30rpx;
text {
font-size: 24rpx;
}
}
.twotwo {
font-weight: 600;
font-size: 24rpx;
color: #3D3D3D;
margin-top: 10rpx;
image {
width: 32rpx;
height: 32rpx;
margin-left: 10rpx;
}
}
}
.left {
font-weight: 600;
font-size: 36rpx;
color: #3D3D3D;
width: 70%;
.guzhang {
width: 240rpx;
text-align: center;
color: #fff !important;
padding: 8rpx 10rpx;
box-sizing: border-box;
border-radius: 50rpx;
background-color: #4C97E7;
font-weight: 400;
font-size: 28rpx;
margin-top: 10rpx;
}
.km {
font-weight: 400;
font-size: 28rpx;
color: #3D3D3D;
margin-top: 10rpx;
}
.speed {
margin-top: 10rpx;
width: 226rpx;
height: 22rpx;
background: #ccc;
border-radius: 16rpx 16rpx 16rpx 16rpx;
.speeds {
height: 100%;
background: #4297F3;
border-radius: 16rpx 16rpx 16rpx 16rpx;
}
}
}
.right {
padding-right: 20rpx;
font-size: 24rpx;
color: #333;
image {
width: 280rpx;
height: 224rpx;
}
}
}
}
.picimg {
width: 46rpx;
height: 76rpx;
position: fixed;
left: 50%;
transform: translateX(-50%);
top: 30%;
z-index: 99;
}
.kefutc {
animation: fadeIn 0.5s ease-in-out forwards;
position: fixed;
top: 660rpx;
left: 50%;
transform: translateX(-50%);
z-index: 99;
.bot {
margin-top: 30rpx;
.wz {
margin-top: 10rpx;
font-weight: 600;
font-size: 28rpx;
color: #3D3D3D;
}
.wzs {
margin-top: 10rpx;
font-size: 24rpx;
color: #7C7C7C;
}
}
.top {
width: 538rpx;
height: 122rpx;
background: #FFFFFF;
box-shadow: 0rpx 0rpx 10rpx 0rpx rgba(0, 0, 0, 0.1);
border-radius: 14rpx 14rpx 14rpx 14rpx;
display: flex;
justify-content: space-between;
align-items: center;
padding-right: 14rpx;
box-sizing: border-box;
margin-top: 20rpx;
.dianhua {
font-weight: 600;
font-size: 28rpx;
color: #3D3D3D;
padding-left: 26rpx;
box-sizing: border-box;
}
.boda {
width: 94rpx;
height: 94rpx;
background: #DCEDFF;
border-radius: 8rpx 8rpx 8rpx 8rpx;
text-align: center;
padding-top: 8rpx;
box-sizing: border-box;
text {
display: block;
}
}
}
image {
position: absolute;
top: -280rpx;
z-index: -1;
left: 50%;
transform: translateX(-50%);
width: 614rpx;
height: 748rpx;
}
}
.mask {
width: 100%;
height: 100vh;
position: fixed;
z-index: 96;
background-color: rgba(0, 0, 0, 0.08);
top: 0;
left: 0;
}
.clmask {
width: 100%;
height: 100vh;
position: fixed;
z-index: 98;
background-color: rgba(0, 0, 0, 0.08);
top: 0;
left: 0;
}
.biketc {
position: fixed;
left: 50%;
transform: translateX(-50%);
bottom: 50rpx;
z-index: 99;
background-color: #fff;
border-radius: 30rpx;
width: 700rpx;
margin: auto;
padding-bottom: 30rpx;
box-sizing: border-box;
.topfor {
width: 100%;
margin: auto;
max-height: 664rpx;
background: #fff;
border-radius: 30rpx 30rpx 0 0;
padding: 44rpx 34rpx;
box-sizing: border-box;
position: relative;
.bikeyc {
position: absolute;
top: 20rpx;
right: 32rpx;
font-size: 70rpx;
font-weight: 600;
}
.biketaocan {
display: flex;
overflow: scroll;
.bikelist {
margin-right: 22rpx;
.bike_item {
border: 1px solid #fff;
margin-top: 36rpx;
padding-top: 16rpx;
padding-left: 24rpx;
padding-right: 24rpx;
box-sizing: border-box;
width: 368rpx;
height: 280rpx;
background: #FFFFFF;
box-shadow: 0rpx 10rpx 64rpx 0rpx rgba(0, 0, 0, 0.08);
border-radius: 26rpx 26rpx 26rpx 26rpx;
position: relative;
overflow: hidden;
image {
width: 82rpx;
height: 50rpx;
position: absolute;
top: 0;
right: 0;
z-index: -1;
}
.name {
font-weight: 600;
font-size: 32rpx;
color: #3D3D3D;
}
.qibu {
display: flex;
justify-content: space-between;
font-size: 24rpx;
color: #3D3D3D;
margin-top: 16rpx;
}
.ckxq {
width: 368rpx;
height: 58rpx;
background: #4297F3;
font-weight: 600;
font-size: 28rpx;
color: #FFFFFF;
position: absolute;
left: 0;
bottom: 0;
text-align: center;
line-height: 58rpx;
}
}
}
}
.bikesy {
width: 100%;
border-top: 1rpx solid #D8D8D8;
margin-top: 30rpx;
padding-top: 36rpx;
box-sizing: border-box;
display: flex;
.bikelt {
width: 50%;
text-align: center;
.bikegongli {
font-weight: 600;
font-size: 48rpx;
color: #3D3D3D;
}
.bikets {
font-size: 28rpx;
color: #808080;
margin-bottom: 28rpx;
}
image {
width: 48rpx;
height: 36rpx;
margin-right: 18rpx;
}
}
.bikert {
width: 50%;
text-align: center;
.bikegongli {
font-weight: 600;
font-size: 48rpx;
color: #3D3D3D;
}
.bikets {
font-size: 28rpx;
color: #808080;
margin-bottom: 28rpx;
}
image {
width: 22rpx;
height: 48rpx;
margin-right: 18rpx;
}
}
}
.biketop {
display: flex;
align-items: center;
.bikebeep {
width: 160rpx;
height: 60rpx;
border-radius: 10rpx 10rpx 10rpx 10rpx;
border: 2rpx solid #4C97E7;
font-weight: 600;
font-size: 28rpx;
color: #4C97E7;
text-align: center;
line-height: 60rpx;
margin-left: 80rpx;
}
.bianh {
view {
font-weight: 600;
font-size: 28rpx;
color: #3D3D3D;
}
}
image {
width: 56rpx;
height: 56rpx;
margin-right: 24rpx;
}
}
}
.anniuks {
width: 100%;
// height: 184rpx;
// background: #FFFFFF;
text-align: center;
// line-height: 184rpx;
text {
display: inline-block;
width: 680rpx;
height: 90rpx;
background: #4C97E7;
border-radius: 54rpx 54rpx 54rpx 54rpx;
font-weight: 600;
font-size: 40rpx;
color: #FFFFFF;
text-align: center;
line-height: 90rpx;
}
}
}
.shoptc {
position: fixed;
width: 696rpx;
max-height: 312rpx;
background: #FFFFFF;
border-radius: 20rpx 20rpx 20rpx 20rpx;
bottom: 200rpx;
left: 50%;
transform: translateX(-50%);
padding: 28rpx 34rpx;
box-sizing: border-box;
.cont {
margin-top: 40rpx;
display: flex;
.shuoming {
.name {
font-size: 28rpx;
color: #3D3D3D;
}
.price {
font-size: 24rpx;
color: #FF1C1C;
margin-top: 20rpx;
text {
font-size: 44rpx;
}
}
}
image {
width: 166rpx;
height: 128rpx;
margin-right: 26rpx;
}
}
.juli {
display: flex;
align-items: center;
margin-top: 12rpx;
.mi {
padding: 0 10rpx;
box-sizing: border-box;
height: 38rpx;
line-height: 38rpx;
background: #DCEDFF;
border-radius: 4rpx 4rpx 4rpx 4rpx;
font-size: 24rpx;
color: #0D75E5;
margin-right: 20rpx;
}
.dizhi {
font-size: 28rpx;
color: #808080;
}
}
.top {
display: flex;
justify-content: space-between;
.name {
font-size: 32rpx;
color: #3D3D3D;
font-weight: 600;
}
.zu {
font-size: 24rpx;
color: #3D3D3D;
display: flex;
align-items: center;
image {
width: 22rpx;
height: 22rpx;
}
}
}
}
.rticon {
position: fixed;
right: 28rpx;
top: 200rpx;
image {
width: 78rpx;
height: 96rpx;
display: block;
margin-top: 32rpx;
}
}
.lticon {
position: fixed;
right: 20rpx;
bottom: 940rpx;
image {
width: 88rpx;
height: 88rpx;
display: block;
margin-top: 32rpx;
}
}
.map {
width: 100%;
height: 130vh;
position: absolute;
top: -30vh;
.center-marker {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -80%);
/* 定位在中心点上方 */
pointer-events: none;
/* 使其不可点击 */
}
}
</style>