chuangte_bike_newxcx/pages/index/index.vue
2025-07-22 10:20:10 +08:00

3471 lines
94 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="">
<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;" @click="toggleIconAndCallout"
src="https://api.ccttiot.com/smartmeter/img/static/u6r5tQVe2VO6bvxTLeFT" mode=""></image>
<image style="width: 80rpx;height: 80rpx;" src="https://api.ccttiot.com/smartmeter/img/static/ug1ExhYsZmdWWjVvjjuk" @click="btnhuiz" mode=""></image>
<image style="width: 80rpx;height: 80rpx;" src="https://api.ccttiot.com/smartmeter/img/static/ucMoHgzqfBeC1lh2vo4Q" @click="btnbz" mode=""></image>
<image style="width: 80rpx;height: 80rpx;" src="https://api.ccttiot.com/smartmeter/img/static/uaxzNTZkmyPdh90eae7m" @click="btnkefu" mode=""></image>
</view>
<!-- 右侧图标 -->
<view class="rticon">
<image v-if="rtindex != 1" src="https://api.ccttiot.com/smartmeter/img/static/uRtmbcCSrLLZ7hkGFeg2"
@click="btntap(1)" mode=""></image>
<image v-if="rtindex == 1" src="https://api.ccttiot.com/smartmeter/img/static/u8zXd0xYhLKD0BvgZDVv"
@click="btntap(1)" mode=""></image>
<image v-if="rtindex != 2" src="https://api.ccttiot.com/smartmeter/img/static/uySqZZMETPWLmP26Qajc"
@click="btntap(2)" mode=""></image>
<image v-if="rtindex == 2" :src="iconobj.bikertpicgl"
@click="btntap(2)" mode=""></image>
<image v-if="rtindex != 3" src="https://api.ccttiot.com/smartmeter/img/static/unaFMV8lmyqWVyY2uOhR"
@click="btntap(3)" mode=""></image>
<image v-if="rtindex == 3" src="https://api.ccttiot.com/smartmeter/img/static/uEWVQFGBf10XJn8aTlaZ"
@click="btntap(3)" mode=""></image>
</view>
<!-- 点击地图门店弹窗 -->
<view class="shoptc" v-if="shoptcflag" @click="btnmendain">
<view class="top">
<view class="name">
云行租车(汇丰公寓)
</view>
<view class="zu">
1辆可租 <image src="https://api.ccttiot.com/smartmeter/img/static/uX3GfXzwzS4GY1J55raG" mode="">
</image>
</view>
</view>
<view class="juli">
<view class="mi">
727m
</view>
<view class="dizhi">
福建省宁德市霞浦县六一七路402号台铃...
</view>
</view>
<view class="cont">
<image src="https://api.ccttiot.com/smartmeter/img/static/uK5bAmrXLEHVxbH6FcFD" mode=""></image>
<view class="shuoming">
<view class="name">
全新车网红泡泡50KM...
</view>
<view class="price">
日租¥<text>108</text>
</view>
</view>
</view>
</view>
<!-- 车辆弹窗 -->
<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=""
@click="kefuflag = false"></image>
<view class="box">
<view class="" style="max-height: 170rpx;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">
<!-- 0800~2000 -->
温馨提示
</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" @click="btntz">
<view class="orderzt">
<view class="icon"></view>
</view>
<view class="cont_li">
<view class="left">
<view class="name">
{{orderobj.deviceVehicleNum == null ? '--' : orderobj.deviceVehicleNum}}
</view>
<view class="NO">
SN{{orderobj.deviceSn == null ? '--' : orderobj.deviceSn}}
</view>
<view class="km">
可继续行驶{{orderobj.deviceRemainEndurance == null ? '--' : orderobj.deviceRemainEndurance}}公里
</view>
<view class="speed">
<view class="speeds" :style="{ width: orderobj.deviceRemainingPower + '%' }"></view>
</view>
<view class="NO">
剩余电量{{orderobj.deviceRemainingPower == null ? '--' : orderobj.deviceRemainingPower}}%
</view>
</view>
<view class="right">
<image :src="iconobj.mapimg" mode="aspectFill"></image>
</view>
</view>
<view class="imgpic">
<image @click="btnxl" src="https://api.ccttiot.com/smartmeter/img/static/uFqlo25Wodl78q2c65rI" mode=""></image>
<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" @click.stop="btnqd">
{{orderobj.deviceLockStatus == 1 ? '临时锁车' : '开锁'}}
</view>
<view class="lssc" @click.stop="btnjsdd">
结束订单
</view>
</view>
</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 src="https://api.ccttiot.com/smartmeter/img/static/uKOCB6yMx4VMyBgblz3H" 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}}
</view>
<image class="ddc" src="https://api.ccttiot.com/smartmeter/img/static/uKOCB6yMx4VMyBgblz3H" mode=""></image>
</view>
<view class="mask" v-if="wenbentxtflag"></view>
<!-- 统一蓝牙连接失败 -->
<view class="tongyi" style="height: 700rpx;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="tops" style="padding: 0 30rpx;box-sizing: border-box;text-align: left;">
<view class="" style="font-weight: 600;font-size: 40rpx;text-align: center;">
<image style="width: 32rpx;height: 32rpx;margin-right: 14rpx;" src="https://api.ccttiot.com/smartmeter/img/static/uDfEXjApmdS6ByM88pv3" mode=""></image> 蓝牙连接失败
</view>
<view class="" style="margin: auto;margin-top: 10rpx;width: 460rpx;text-align: center;">
请检查手机或微信蓝牙授权是否打开
</view>
<view class="" @click="btnjc" style="color: #4C97E7;border-bottom: 1px solid #4C97E7;width: 230rpx;margin: auto;margin-top: 10rpx;padding-bottom: 4rpx;">
还是不行查看教程
</view>
</view>
<image class="ddc" style="margin-top: 20rpx;" 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>
<!-- <tab-bar :indexs='1'></tab-bar> -->
</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,
ljsbflag:false,
chongshinum:'',
}
},
onLoad() {
},
onShow() {
this.getorderdevice()
xBlufi.initXBlufi(1)
xBlufi.notifyStartDiscoverBle({
'isStart': true
})
xBlufi.listenDeviceMsgEvent(true, this.funListenDeviceMsgEvent)
uni.getLocation({
type: 'wgs84',
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.getkefu()
this.polyline = []
this.isFirstLoad = true // 重置首次加载标志
setTimeout(()=>{
this.toggleIconAndCallout()
},3000)
},
onUnload() {
this.clearTimer()
this.stopOrderDeviceTimer() // 停止订单设备定时器
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.isPageActive = false
this.closeWebSocket()
},
// 组件销毁时清除定时器
beforeDestroy() {
clearTimeout(this.uploadTimer)
this.stopOrderDeviceTimer() // 停止订单设备定时器
},
methods: {
// 点击查看教程
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
})
}
})
},
// 点击响铃
btnxl(){
if(this.jiance == true){
xBlufi.initXBlufi(1)
xBlufi.notifyStartDiscoverBle({
'isStart': true
})
xBlufi.listenDeviceMsgEvent(true, this.funListenDeviceMsgEvent)
}
this.wenbentxt = '车辆响铃中...'
this.wenbentxtflag = true
this.$u.put(`/app/device/iot/ring?id=${this.orderobj.deviceId}`).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
}
},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 => {})
}
}
}
findDevice()
} else {
this.wenbentxt = ''
this.wenbentxtflag = false
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
})
}
})
},
// 获取附近蓝牙设备列表
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(){
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
}
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) {
// this.iconflag = true
// if (e.type == 'end') {
// if (this.rtindex == 2) {
// this.jingweidu = e.detail.centerLocation.longitude + ',' + e.detail.centerLocation.latitude
// this.getAone()
// this.iconflag = false
// }
// }
},
debounceUpdate() {
if (this.updateTimer) {
clearTimeout(this.updateTimer)
}
this.updateTimer = setTimeout(() => {
this.getAone()
}, 300) // 延迟300ms执行更新
},
getNearbyMarkers(clickedLat, clickedLon) {
const nearbyMarkers = this.listData.filter(item => {
if (item.latitude && item.longitude) {
const distance = this.haversineDistance(
parseFloat(clickedLat),
parseFloat(clickedLon),
parseFloat(item.latitude),
parseFloat(item.longitude)
);
return distance <= 100
}
return false
});
// 更新 circles 数组来绘制淡灰色的圆形区域
this.circles = [{
latitude: clickedLat,
longitude: clickedLon,
color: '#fff', // 圆形边框颜色(淡灰色)
fillColor: '#00000010', // 圆形填充颜色(淡灰色)
radius: 100, // 圆的半径(单位:米)
strokeWidth: 1
}]
this.nearbyMarkers = nearbyMarkers
},
haversineDistance(lat1, lon1, lat2, lon2) {
const R = 6371e3 // Earth radius in meters
const toRad = angle => angle * Math.PI / 180
const dLat = toRad(lat2 - lat1)
const dLon = toRad(lon2 - lon1)
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2)
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
return R * c
},
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}`,
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: 40,
height: 60,
iconPath: item.type == 1 ?
'https://lxnapi.ccttiot.com/bike/img/static/up2xXqAgwCX5iER600k3' :
item.type == 2 ?
'https://lxnapi.ccttiot.com/bike/img/static/uDNY5Q4zOiZTCBTA2Jdq' :
'https://lxnapi.ccttiot.com/bike/img/static/u53BAQcFIX3vxsCzEZ7t',
callout: {
content: item.name,
color: '#ffffff',
fontSize: 14,
borderRadius: 10,
bgColor: item.type == 1 ? '#3A7EDB' : item.type == 2 ? '#FF473E' :
'#FFC107',
padding: 6,
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.$u.get("/app/order/mineProcessing").then((res) => {
if (res.code == 200) {
if(res.data){
if (this.orderAreaReturnVerify == true) {
if(this.orderobj.deviceOnlineStatus == 0){
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
})
}else{
that.ver_dataflag = 1
that.shibainum = 0
that.wenbentxt = ''
that.wenbentxtflag = false
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
that.ljsbflag = true
that.chongshinum = '还车'
}
}
}
findDevice()
}else{
uni.navigateTo({
url: '/page_user/hcshenhe?sn=' + this.orderobj.deviceSn + '&orderid=' + this.orderobj.orderId + '&orderAreaId=' + this.orderobj.orderAreaId + '&flag=' + false
})
}
} else {
uni.getLocation({
type: 'gcj02', // 国内地图更兼容
isHighAccuracy: true,
accuracy:'best',
success: (res) => {
console.log('精确坐标:', res)
this.lat = res.latitude
this.lon = res.longitude
this.getfeiyong()
},
fail: (err) => {
console.error('获取位置失败:', err)
this.lat = null
this.lon = null
this.getfeiyong() // 降级处理
}
});
}
}else{
uni.navigateTo({
url:'/page_user/yongche/orderxq?id=' + this.orderobj.orderId
})
}
}
})
},
// 点击还车判断是否需要另外缴费
getfeiyong() {
let data = {
orderId: this.orderobj.orderId,
lon: this.lonsc,
lat: this.latsc,
checkLocation:true
}
this.$u.post(`/app/order/calcFee`, data).then(res => {
if (res.code == 200) {
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 if(res.code == 30001){
uni.showToast({
title: '必须在停车点内还车',
icon: 'none',
duration: 5000
})
}else if(res.code == 30002){
uni.showToast({
title: '不允许在禁停区内还车',
icon: 'none',
duration: 5000
})
}else if(res.code == 30003){
uni.showToast({
title: '必须在运营区内还车',
icon: 'none',
duration: 5000
})
}else{
uni.showToast({
title: res.msg,
icon: 'none',
duration: 5000
})
}
})
},
// 点击缴纳罚金继续还车
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.lonsc,
lat: that.latsc,
requiredIot: true
}
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
}
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
}
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 = '还车'
}
},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 => {})
}
}
}
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() {
if(this.jiance == true){
xBlufi.initXBlufi(1)
xBlufi.notifyStartDiscoverBle({
'isStart': true
})
xBlufi.listenDeviceMsgEvent(true, this.funListenDeviceMsgEvent)
}
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
that.wenbentxt = '车辆连接中...'
that.wenbentxtflag = true
let query = {
orderId: that.orderobj.orderId,
lat: that.lslat,
lon: that.lslon,
requiredIot: true
}
let url = '/app/order/closeDevice?' + that.$tansParams(query)
that.$u.put(url).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
})
},1000)
} else if(res.code == 20001){
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 query = {
orderId: that.orderobj.orderId,
lat: that.lslat,
lon: that.lslon,
requiredIot: false
}
let url = '/app/order/closeDevice?' + that.$tansParams(query)
that.$u.put(url).then((res) =>{})
uni.navigateTo({
url: '/page_user/huanbike?sn=' + that.orderobj.deviceSn + '&orderid=' + that.orderobj.orderId + '&deviceid=' + that.deviceid + '&devicename=' + that.devicename
})
}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.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 query = {
orderId: that.orderobj.orderId,
lat: that.lslat,
lon: that.lslon,
requiredIot: false
}
let url = '/app/order/closeDevice?' + that.$tansParams(query)
that.$u.put(url).then((res) =>{})
uni.navigateTo({
url: '/page_user/huanbike?sn=' + that.orderobj.deviceSn + '&orderid=' + that.orderobj.orderId + '&deviceid=' + that.deviceid + '&devicename=' + that.devicename
})
}else{
that.ver_dataflag = 1
that.shibainum = 0
that.wenbentxt = ''
that.wenbentxtflag = false
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
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 => {})
}
}
}
findDevice()
}
} else {
that.wenbentxt = ''
that.wenbentxtflag = false
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
})
}
})
},
// 点击跳转到车辆
btntz() {
// uni.switchTab({
// url: '/pages/myorder/returned/index'
// })
},
// 点击跳转导航
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() {
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 query = {
orderId: that.orderobj.orderId,
lat: that.lslat,
lon: that.lslon,
requiredIot: true
}
let url = '/app/order/openDevice?' + that.$tansParams(query)
that.$u.put(url).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 query = {
orderId: that.orderobj.orderId,
lat: that.lslat,
lon: that.lslon,
requiredIot: false
}
let url = '/app/order/openDevice?' + that.$tansParams(query)
that.$u.put(url).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 => {})
}
}
}
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 query = {
orderId: that.orderobj.orderId,
lat: that.lslat,
lon: that.lslon,
requiredIot: true
}
let url = '/app/order/closeDevice?' + that.$tansParams(query)
that.$u.put(url).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 query = {
orderId: that.orderobj.orderId,
lat: that.lslat,
lon: that.lslon,
requiredIot: false
}
let url = '/app/order/closeDevice?' + that.$tansParams(query)
that.$u.put(url).then((res) =>{})
}else{
that.ver_dataflag = 1
that.shibainum = 0
that.wenbentxt = ''
that.wenbentxtflag = false
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
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 => {})
}
}
}
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.getMyLocation()
this.initWebSocket() //WebSocket接受数据
this.$u.get(`/app/area/detail?id=${this.orderAreaId}`).then((res) => {
if (res.code == 200) {
const polylines = this.convertBoundaryToPolyline(res.data.boundaryStr)
this.polyline.push(polylines)
this.getParking()
}
})
// 如果有数据,启动定时器每分钟执行一次
this.startOrderDeviceTimer()
} else {
uni.reLaunch({
url:'/pages/nearbystores/index'
})
this.orderAreaId = ''
this.orderflag = false
this.newMarkers = ''
console.log(this.covers)
// 如果没有数据,停止定时器
this.stopOrderDeviceTimer()
}
}
})
},
// 启动订单设备定时器
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
// 如果WebSocket连接断开重新连接
if (!this.socketTask || this.socketTask.readyState !== 1) {
this.initWebSocket()
}
} else {
// 如果没有数据,停止定时器
this.orderAreaId = ''
this.orderflag = false
this.newMarkers = ''
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.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() {
this.$u.put(`/app/device/iot/ring?id=${this.cheobj.id}&lat=${this.xllat}&lon=${this.xllng}`).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) {
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: this.iconPath,
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: 'wgs84',
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
}
}
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: 40,
height: 60,
iconPath: item.type == 1 ?
'https://lxnapi.ccttiot.com/bike/img/static/up2xXqAgwCX5iER600k3' :
item.type == 2 ?
'https://lxnapi.ccttiot.com/bike/img/static/uDNY5Q4zOiZTCBTA2Jdq' :
'https://lxnapi.ccttiot.com/bike/img/static/u53BAQcFIX3vxsCzEZ7t',
callout: {
content: item.name,
color: '#ffffff',
fontSize: 14,
borderRadius: 10,
bgColor: item.type == 1 ? '#3A7EDB' : item.type == 2 ? '#FF473E' :
'#FFC107',
padding: 6,
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 = []
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)
})
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 operationAreaPolylines = this.polyline.filter(p => p.isOperationArea)
// 合并所有边界数据
const allPolylines = [
...operationAreaPolylines,
...type1Polylines,
...type2Polylines,
...type3Polylines
]
// 缓存多边形数据
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) => {
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}`).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: this.getIconPath(),
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">
page {
background: #fff;
border-radius: 0rpx 0rpx 0rpx 0rpx;
}
.active {
image {
z-index: 99 !important;
}
.bike_item {
border: 1px solid #4297F3 !important;
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes rotate360 {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.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;
}
.tops{
margin-top: 30rpx;
image{
width: 50rpx;
height: 50rpx;
margin-right: 8rpx;
}
}
.ddc{
width: 610rpx;
height: 314rpx;
margin-top: 40rpx;
}
}
.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;
}
.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: 480rpx;
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: 0 30rpx;
padding-bottom: 30rpx;
box-sizing: border-box;
.orderzt {
display: flex;
justify-content: space-between;
width: 100%;
.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;
.jsdd{
width: 290rpx;
height: 88rpx;
background: rgba(76,151,231,0);
border-radius: 20rpx 20rpx 20rpx 20rpx;
border: 2rpx solid #4C97E7;
text-align: center;
line-height: 88rpx;
font-weight: 600;
font-size: 36rpx;
color: #4C97E7;
}
.lssc {
font-weight: 600;
font-size: 36rpx;
color: #FFFFFF;
width: 386rpx;
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;
}
.imgpic{
display: flex;
margin-top: 10rpx;
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;
.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;
}
}
.NO {
width: 100%;
font-weight: 400;
font-size: 24rpx;
color: #3D3D3D;
margin-top: 10rpx;
}
}
.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;
left: 28rpx;
top: 200rpx;
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>