852 lines
20 KiB
Vue
Raw Normal View History

2025-04-28 15:37:57 +08:00
<template>
<map id="mapRef" ref="mapRef" style="width: 100%;height: 100vh;" show-location :longitude="location.longitude"
:latitude="location.latitude" :markers="markers" :scale="scale" :polygons="polygons" :polyline="polylines"
:circles="circles" @markertap="openBikeInfo" />
<div v-if="showTools" class="divMapTools" style="left: 10px;">
<div>
<image class="divImg" :src='imgPath+"static/userui/home/localtion.png"' @click="refresh" />
</div>
<div>
<image class="divImg" :src='imgPath+"static/userui/home/fault.png"' @click="reportFault" />
</div>
</div>
<div v-if="showTools" class="divMapTools" style="right: 10px;">
<div>
<image class="divImg" :src='imgPath+"static/userui/home/packing.png"' @click="applySite" />
</div>
<div>
<image class="divImg" :src='imgPath+"static/userui/home/mine.png"' @click="getMine" />
</div>
</div>
<div v-if="hasOrder" class="divMapOrder" @click="openOrderPay">
<div>
<image style="width: 15px;height: 15px;margin-left: 15px;margin-right: 10px;"
:src='imgPath+"static/userui/home/speaker.png"' />
<label>有骑行订单未支付请查看</label>
</div>
<div style="margin-right: 15px;">
<label>查看 <label>></label></label>
</div>
</div>
<div class="divMapBottom">
<div :class="(hasOrder?'divScanBtnDis ':'')+'divScanBtn'" @click="scanBike">
<uni-icons type="scan" color="white" :size="25"></uni-icons>
<label style="margin-left: 5px;">扫码用车</label>
</div>
</div>
<div v-if="showOrder" class="divOrder">
<div class="divOrderRow">
<div class="divOrderCell">
<image class="divOrderImg" :src='imgPath+"static/userui/home/money.png"' />
<label>费用</label>
<label>{{order.money}}</label>
</div>
<div class="divOrderCell2">
<label>{{order.bikecode}}</label>
</div>
</div>
<div class="divOrderRow" style="font-size: 12px;">
<div class="divOrderCell">
<image class="divOrderImg" :src='imgPath+"static/userui/home/timer.png"' />
<label>计时</label>
<label style="color: #61D246;">{{order.time}}</label>
</div>
2025-05-16 16:52:21 +08:00
<!-- <div class="divOrderCell2">
2025-04-28 15:37:57 +08:00
<image class="divOrderImg" :src='imgPath+"static/userui/home/bike.png"' />
<label>骑行</label>
<label style="color: #61D246;">{{order.mileage}}</label>
</div> -->
2025-04-28 15:37:57 +08:00
</div>
<div class="divOderBtn">
<image v-if="orderState==0" style="width: 120px;height: 40px;" :src='imgPath+"static/userui/home/lock.png"'
@click="lockRiding" />
<image v-if="orderState==1" style="width: 120px;height: 40px;" :src=' imgPath+"static/userui/home/run.png"'
@click="continueRiding" />
<image style="width: 160px;height: 40px;" :src='imgPath+"static/userui/home/endride.png"'
@click="endRiding" />
</div>
</div>
<div v-if="showMess!=1" class="divMess">
<uni-card>
<uni-list border>
<uni-list-item :thumb='imgPath+"static/userui/home/map1.png"' thumb-size="lg">
<template v-slot:body>
<div class="divMessTitle1">服务区域</div>
<div class="divMessTitle2">请在服务区域内骑行</div>
</template>
</uni-list-item>
<uni-list-item :thumb='imgPath+"static/userui/home/map2.png"' thumb-size="lg">
<template v-slot:body>
<div class="divMessTitle1">换车区域</div>
<div class="divMessTitle2">还车时确保车辆已经到达还车区域或者距你最近的停车网点</div>
</template>
</uni-list-item>
<uni-list-item :thumb='imgPath+"static/userui/home/map3.png"' thumb-size="lg">
<template v-slot:body>
<div class="divMessTitle1">停车网点</div>
<div class="divMessTitle2">还车至停车网点时长费最多可半价优惠</div>
</template>
</uni-list-item>
</uni-list>
<div class="divMessWorn">
<div class="divMessWornTitle">
·注意事项
</div>
<div class="divMessWornContent">禁止私自加锁或破坏车辆</div>
<div class="divMessWornContent">未满12岁禁止骑行</div>
<div class="divMessWornContent">如车辆故障及时通过app保修</div>
</div>
<div class="divMessBtn">
<label
style="color: #61D145;border: 1px solid #0000000f;padding: 5px 15px;border-radius: 5px;box-shadow: 2px 2px #0000000a;"
@click="clickMess">已知晓</label>
</div>
</uni-card>
</div>
<div v-if="showBikeInfo" style="position: absolute;z-index: 2000;bottom: 0;width: 100vw;">
2025-04-30 17:32:21 +08:00
<bike-info :bikedata="bikeData" @close="closeBikeInfo" />
2025-04-28 15:37:57 +08:00
</div>
<div v-if="showOrderPay" style="position: absolute;z-index: 2000;bottom: 0;width: 100vw;">
2025-05-09 16:36:41 +08:00
<bike-pay :orderId="orderData.orderId" />
2025-04-28 15:37:57 +08:00
</div>
</template>
<script setup>
import {
ref,
onMounted,
getCurrentInstance
} from 'vue';
import {
showModelMessage,
getUrlParams,
jkcBaseDecode
2025-04-28 15:37:57 +08:00
} from "@/utils/tools.js";
import {
callOrdereApi,
callOperateApi
} from "@/utils/api.js";
import {
findIndex
} from 'lodash';
import config from '@/utils/config';
import {
onShow,
onUnload,
onLoad
2025-04-28 15:37:57 +08:00
} from "@dcloudio/uni-app";
import * as map from "@/utils/usermap.js";
const imgPath = config.imgPath;
const location = ref({
longitude: "",
latitude: ""
});
const scale = ref(15);
const markers = ref([]);
const polygons = ref([]); //面
const polylines = ref([]); //线
const circles = ref([]); //圆
const pointStart = 100000000000;
const pointEnd = 100000000001;
2025-04-28 15:37:57 +08:00
let oMap = null;
const showTools = ref(true);
let oUser = null;
const showMess = ref(uni.getStorageSync("kbike-mess"));
const hasOrder = ref(false); //是否有订单
const showOrder = ref(false);
const order = ref({
2025-05-28 16:18:50 +08:00
bikecode: "",
money: "",
time: "",
mileage: ""
2025-04-28 15:37:57 +08:00
});
2025-04-28 15:37:57 +08:00
//订单信息
let orderData = {
bikeCode: null,
status: null,
createdAt: null,
orderId: null
};
let orderTimer = null;
const orderState = ref(0);
const showOrderPay = ref(false);
2025-04-28 15:37:57 +08:00
//车辆
let arrBikeData = [];
const showBikeInfo = ref(false);
const bikeData = ref({});
2025-05-29 18:06:51 +08:00
const onLoadData = ref({})
let ismount = false;
let arrSiteData = []
2025-04-28 15:37:57 +08:00
onLoad((query) => {
2025-05-30 13:53:37 +08:00
if (query.q) {
const q = decodeURIComponent(query.q) // 获取到二维码原始链接内容
const scancode_time = parseInt(query.scancode_time) // 获取用户扫码时间 UNIX 时间戳
const queryString = q.split('?')[1];
const params = queryString.split('&');
let p = {};
params.forEach(param => {
const [key, value] = param.split('=');
p[key] = value;
});
onLoadData.value = p;
} else if (query.number) {
onLoadData.value['number'] = query.number;
onLoadData.value['_tbScancodeApproach_'] = query._tbScancodeApproach_;
}
})
onMounted(() => {
const instance = getCurrentInstance();
oMap = uni.createMapContext("mapRef", {
this: instance.proxy
});
ismount = true;
getLoalcationData();
if (onLoadData.value) {
if (onLoadData.value['_tbScancodeApproach_'] == 'scan') {
if (!oUser) {
2025-05-30 13:53:37 +08:00
showModelMessage("登录后开始骑行", "登录提醒", true, "去登录").then(res => {
if (res.confirm) {
tologin()
}
})
2025-06-05 09:45:40 +08:00
}
checkRealName((res)=>{
if(!res) return;
getOrder((flag) => {
if (flag) {
map.addOrder(onLoadData.value["number"], false, (res) => {
if (res) {
getOrder();
}
})
}
});
},nLoadData.value["number"],onLoadData.value['_tbScancodeApproach_']);
/* else if (!oUser['realNameStatus']) {
2025-05-30 13:53:37 +08:00
showModelMessage("请进行实名认证后骑行", "实名认证", true, "去认证").then(res => {
if (res.confirm) {
uni.navigateTo({
url: "/pages/user/views/IdentityVerification?number=" + onLoadData
.value["number"] + "&_tbScancodeApproach_=" + onLoadData.value[
'_tbScancodeApproach_']
})
}
})
} else {
getOrder((flag) => {
if (flag) {
map.addOrder(onLoadData.value["number"], false, (res) => {
if (res) {
getOrder();
}
})
}
});
2025-06-05 09:45:40 +08:00
} */
}
}
})
2025-04-28 15:37:57 +08:00
//加载数据
function getLoalcationData() {
map.getLoalcation(res => {
2025-04-28 15:37:57 +08:00
const {
latitude,
longitude
} = res;
location.value = {
latitude,
longitude
};
2025-04-30 17:32:21 +08:00
oMap.moveToLocation({})
2025-04-28 15:37:57 +08:00
const params = {
latitude,
longitude,
2025-05-28 16:18:50 +08:00
radius: 1
2025-04-28 15:37:57 +08:00
};
callOrdereApi("userOrders/bikeList", params, "post").then(res => {
const {
code,
data,
message
} = res;
if (code != 200) {
showModelMessage(message);
return;
}
arrBikeData = data || [];
const arrData = markers.value || [];
arrBikeData.map((item, index) => {
2025-04-28 15:37:57 +08:00
const {
longitude,
latitude
} = item;
arrData.push(map.addMarker(index, longitude, latitude, "mapbike.png",
2025-04-30 17:32:21 +08:00
true));
2025-04-28 15:37:57 +08:00
})
markers.value = arrData;
});
getSiteList(longitude, latitude);
2025-04-28 15:37:57 +08:00
})
// uni.getLocation({
// type: 'gcj02',
// geocode: true,
// success(res) {
// location.value = {
// latitude,
// longitude
// };
2025-04-28 15:37:57 +08:00
// },
// fail(res) {
// }
// });
}
function clickMess() {
uni.setStorageSync("kbike-mess", 1);
showMess.value = 1;
}
//刷新
function refresh() {
getLoalcationData();
}
//故障上报
function reportFault() {
if (!oUser) {
tologin();
return;
2025-06-05 09:45:40 +08:00
}
checkRealName((res)=>{
if(!res) return;
uni.navigateTo({
url: "/pages/user/login/TroubleReportUser"
2025-05-30 13:53:37 +08:00
})
2025-04-28 15:37:57 +08:00
})
2025-06-05 09:45:40 +08:00
// else if (!oUser['realNameStatus']) {
// showModelMessage("请进行实名认证后骑行", "实名认证", true, "去认证").then(res => {
// if (res.confirm) {
// uni.navigateTo({
// url: "/pages/user/views/IdentityVerification"
// })
// }
// })
// }
// uni.navigateTo({
// url: "/pages/user/login/TroubleReportUser"
// })
2025-04-28 15:37:57 +08:00
}
//申请站点
function applySite() {
if (!oUser) {
tologin();
return;
2025-06-05 09:45:40 +08:00
}
checkRealName((res)=>{
if(!res) return;
uni.navigateTo({
url: "/pages/user/scan/applysite"
})
})
/* else if (!oUser['realNameStatus']) {
2025-05-30 13:53:37 +08:00
showModelMessage("请进行实名认证后骑行", "实名认证", true, "去认证").then(res => {
if (res.confirm) {
uni.navigateTo({
url: "/pages/user/views/IdentityVerification"
})
}
})
2025-04-28 15:37:57 +08:00
}
uni.navigateTo({
url: "/pages/user/scan/applysite"
2025-06-05 09:45:40 +08:00
}) */
2025-04-28 15:37:57 +08:00
}
//个人中心
function getMine() {
if (!oUser) {
tologin();
return;
2025-06-05 09:45:40 +08:00
}
checkRealName((res)=>{
if(!res) return;
uni.navigateTo({
url: "/pages/user/mine/MePage"
})
})
/* else if (!oUser['realNameStatus']) {
2025-05-30 13:53:37 +08:00
showModelMessage("请进行实名认证后骑行", "实名认证", true, "去认证").then(res => {
if (res.confirm) {
uni.navigateTo({
url: "/pages/user/views/IdentityVerification"
})
}
})
2025-04-28 15:37:57 +08:00
}
uni.navigateTo({
url: "/pages/user/mine/MePage"
2025-06-05 09:45:40 +08:00
}) */
2025-04-28 15:37:57 +08:00
}
//扫描
function scanBike() {
if (!oUser) {
tologin();
return;
2025-06-05 09:45:40 +08:00
}
checkRealName((res)=>{
if(!res) return;
const {
userId
} = oUser;
uni.navigateTo({
url: "/pages/user/scan/scancode?type=ride"
})
})
/* else if (!oUser['realNameStatus']) {
2025-05-30 13:53:37 +08:00
showModelMessage("请进行实名认证后骑行", "实名认证", true, "去认证").then(res => {
if (res.confirm) {
uni.navigateTo({
url: "/pages/user/views/IdentityVerification"
})
}
})
2025-04-28 15:37:57 +08:00
}
const {
userId
} = oUser;
uni.navigateTo({
url: "/pages/user/scan/scancode?type=ride"
2025-06-05 09:45:40 +08:00
}) */
2025-04-28 15:37:57 +08:00
}
//显示订单
function openOrderPay() {
showTools.value = false;
showOrderPay.value = true;
}
//获取订单
2025-05-30 13:53:37 +08:00
function getOrder(callBack) {
2025-04-28 15:37:57 +08:00
const {
userId
} = oUser;
callOrdereApi("userOrders/checkHistoryOrder", {
userId
}, "get").then(res => {
const {
code,
data,
message
} = res;
if (code != 200) {
showModelMessage(message);
2025-05-30 13:53:37 +08:00
if (callBack) callBack(true)
2025-04-28 15:37:57 +08:00
return;
}
if (!data) { //订单完成
completeRiding();
2025-05-30 13:53:37 +08:00
if (callBack) callBack(true)
2025-04-28 15:37:57 +08:00
return;
}
const {
bikeCode,
status,
createdAt,
orderId,
tempLock,
ridePoint,
returnPoint,
endTime
} = data;
//0-进行中 1-已取消 2-待支付 3-已支付 4-退款中 5-已退款
orderState.value = tempLock ? 1 : 0;
orderData = data;
if (status == 2) {
completeRiding();
hasOrder.value = true;
getTracking();
return;
} else if (status != 0) {
completeRiding();
return;
}
showOrder.value = true;
if (status == 0) {
// 获取订单信息
getOrderInfo(bikeCode);
order.value.bikecode = bikeCode;
// 设置 intervalId 变量来保存定时器 ID
const intervalId = setInterval(() => {
// 更新订单时间
order.value.time = timeDifference(createdAt);
if (!showOrder.value) { // 如果 showOrder 为 false停止轮询
clearInterval(intervalId); // 使用 intervalId 来停止轮询
}
2025-05-16 16:52:21 +08:00
}, 1000);
}
if (tempLock == 1) {
2025-04-28 15:37:57 +08:00
getTracking();
return;
}
2025-05-16 16:52:21 +08:00
2025-04-28 15:37:57 +08:00
getTracking();
// if (!orderTimer) {
// orderTimer = setInterval(getTracking, 100000);
// }
})
}
2025-05-30 13:53:37 +08:00
const getOrderInfo = (bikeCode) => {
const params = {
"userId": oUser.userId,
"bikeCode": bikeCode
}
2025-05-16 16:52:21 +08:00
callOrdereApi("userOrders/costCalculation", params).then(res => {
if (res.code == 200) {
order.value.money = res.data;
}
})
}
2025-04-28 15:37:57 +08:00
//轨迹
function getTracking() {
const {
bikeCode,
createdAt,
ridePoint,
returnPoint,
endTime
} = orderData;
let params = {
ebikeCode: bikeCode,
startTime: createdAt
}
if (endTime) params = {
...params,
endTime
}
callOperateApi("ebikeTracking/query", params, "post").then(res => {
const {
code,
data,
message
} = res;
if (code != 200) {
return;
}
const arrPoints = (!data || data.length == 0) ? [] : data.map(item => {
const {
lngGCJ02,
latGCJ02
} = item;
return {
longitude: lngGCJ02,
latitude: latGCJ02
}
});
2025-04-28 15:37:57 +08:00
const startPoint = ridePoint.split(",");
const lng = startPoint[0];
const lat = startPoint[1];
const start = {
longitude: lng,
latitude: lat
}
const arrMakers = markers.value || [];
arrPoints.splice(0, 0, start);
let indexStart = findIndex(arrMakers, {
pointStart
});
2025-04-28 15:37:57 +08:00
indexStart = indexStart == -1 ? arrMakers.length : indexStart;
arrMakers[indexStart] = map.addMarker(pointStart, lng, lat, "start.png");
if (data && data.length > 0) {
let {
lngGCJ02: endlng,
latGCJ02: endlat
} = data[data.length - 1];
arrMakers[indexStart + 1] = map.addMarker(pointEnd, endlng, endlat, "end.png");
}
markers.value = arrMakers;
if (arrPoints.length > 1) {
polylines.value = [map.addLine("#168DED", arrPoints)];
}
})
}
//完成骑行
function completeRiding() {
if (!orderTimer) return;
clearInterval(orderTimer);
orderTimer = null;
showOrder.value = false;
hasOrder.value = false;
orderState.value = 0;
}
function tologin() {
let url = '/pages/user/login/wx_login'
if (onLoadData.value) {
url += '?number=' + onLoadData.value['number'] + "&_tbScancodeApproach_=scan"
}
2025-04-28 15:37:57 +08:00
uni.navigateTo({
url: url
2025-04-28 15:37:57 +08:00
})
}
//临时锁车
function lockRiding() {
const {
userId
} = oUser;
const {
bikeCode
} = orderData;
const params = {
userId,
bikeCode
}
callOrdereApi("userOrders/tempLock", params, "post").then(res => {
const {
code,
message,
data
} = res;
showModelMessage(message)
if (code == 200) {
if (orderTimer) {
2025-04-28 15:37:57 +08:00
clearInterval(orderTimer);
orderTimer = null;
2025-04-28 15:37:57 +08:00
}
orderState.value = 1;
}
});
}
//结束用车
function endRiding() {
2025-05-07 16:02:37 +08:00
checkBikeEnding();
}
function checkBikeEnding(callback) {
2025-05-07 16:02:37 +08:00
const {
bikeCode
} = orderData;
const params = {
bikeCode
}
2025-05-07 16:02:37 +08:00
//运营区和停车区检查
const arrMethod = [callOrdereApi("userOrders/checkBikeInOperation", params, "get"), callOrdereApi(
"userOrders/checkBikeInParking", params, "get")]
Promise.all(arrMethod).then(([res1, res2]) => {
if (res1.code != 200) {
2025-05-07 16:02:37 +08:00
showModelMessage(res1.message);
return;
}
if (res2.code != 200) {
2025-05-07 16:02:37 +08:00
showModelMessage(res2.message);
return;
}
doneRide();
});
}
2025-05-07 16:02:37 +08:00
//完成骑行
function doneRide() {
2025-04-28 15:37:57 +08:00
const {
userId
} = oUser;
const {
bikeCode
} = orderData;
const params = {
userId,
bikeCode
}
callOrdereApi("userOrders/doneRide", params, "post").then(res => {
const {
code,
data,
message
} = res;
if (code != 200) {
showModelMessage(message);
return;
}
completeRiding();
openOrderPay();
})
}
//继续骑行 需要开锁
function continueRiding() {
const {
userId
} = oUser;
const {
bikeCode
} = orderData;
const params = {
userId,
bikeCode
}
callOrdereApi("userOrders/continueCycling", params, "post").then(res => {
const {
code,
message,
data
} = res;
showModelMessage(message)
if (code == 200) {
if (orderTimer) {
2025-04-28 15:37:57 +08:00
clearInterval(orderTimer);
orderTimer = null;
2025-04-28 15:37:57 +08:00
}
orderState.value = 0;
}
});
//getOrder();
}
//查看车辆信息
function openBikeInfo(e) {
if (!oUser) {
tologin();
return;
}
2025-04-30 17:32:21 +08:00
const {
markerId
} = e.detail;
if (markerId == pointEnd || markerId == pointStart) {
2025-04-30 17:32:21 +08:00
return;
}
bikeData.value = arrBikeData[markerId];
2025-04-28 15:37:57 +08:00
showBikeInfo.value = true;
showTools.value = false;
showOrderPay.value = false;
2025-04-28 15:37:57 +08:00
}
//关闭车辆信息
function closeBikeInfo() {
showBikeInfo.value = false;
showTools.value = true;
}
onShow(() => {
if (uni.getStorageSync("wechat_user")) {
oUser = JSON.parse(jkcBaseDecode(uni.getStorageSync("wechat_user")));
2025-05-22 11:28:43 +08:00
const {
userId
} = oUser;
if (userId) {
getOrder();
}
}
2025-06-05 09:45:40 +08:00
console.log("999999999999999999",ismount);
if (ismount) getLoalcationData();
2025-04-28 15:37:57 +08:00
});
onUnload(() => {})
function parseDate(createTime) {
2025-05-16 16:52:21 +08:00
// 将日期字符串转换为 iOS 支持的格式
createTime = createTime.replace(" ", "T"); // 将空格替换为 "T",使其符合 "yyyy-MM-ddTHH:mm:ss" 格式
return new Date(createTime); // 返回新的 Date 对象
}
2025-05-16 16:52:21 +08:00
function timeDifference(createTime) {
2025-05-16 16:52:21 +08:00
const currentTime = new Date();
const createDate = parseDate(createTime); // 使用转换后的日期字符串
const diffInSeconds = Math.floor((currentTime - createDate) / 1000);
2025-05-16 16:52:21 +08:00
if (diffInSeconds < 60) return `${diffInSeconds}`;
const diffInMinutes = Math.floor(diffInSeconds / 60);
if (diffInMinutes < 60) {
const remainingSeconds = diffInSeconds % 60;
return `${diffInMinutes}分钟 ${remainingSeconds}`;
}
const diffInHours = Math.floor(diffInMinutes / 60);
if (diffInHours < 24) {
const remainingMinutes = diffInMinutes % 60;
const remainingSeconds = diffInSeconds % 60;
return `${diffInHours}小时 ${remainingMinutes}分钟 ${remainingSeconds}`;
}
const diffInDays = Math.floor(diffInHours / 24);
return `${diffInDays}${diffInHours % 24}小时 ${diffInMinutes % 60}分钟 ${diffInSeconds % 60}`;
}
function getSiteList(lng, lat) {
const params = {
longitude: lng,
latitude: lat
2025-05-22 11:28:43 +08:00
}
callOrdereApi("userOrders/siteRegionList", params, "post").then(res => {
const {
code,
data,
message
} = res;
const arrData = [];
if (code == 200 && data && data.length > 0) {
data.map(item => {
const {
shapeType,
points
} = item;
if (shapeType == "2") {
arrData.push(map.addPolygon("#578FD4", "#c0daf54d", points));
2025-05-22 11:28:43 +08:00
}
});
polygons.value = arrData;
} else {
console.log("userOrders/siteRegionList", res);
2025-05-22 11:28:43 +08:00
}
})
}
2025-06-05 09:45:40 +08:00
function checkRealName(callBack,number,_tbScancodeApproach_){
if (!oUser['realNameStatus']) {
showModelMessage("请先完成实名认证,再继续。", "实名认证", true, "去认证").then(res => {
if (res.confirm) {
let url="/pages/user/views/IdentityVerification";
if(number){
url=`${url}?number=${number}&_tbScancodeApproach_=${_tbScancodeApproach_}`;
}
uni.navigateTo({url});
callBack(false);
return;
}
callBack(false);
})
return;
}
callBack(true);
}
2025-04-28 15:37:57 +08:00
</script>
<style scoped>
@import url("home.css");
</style>