885 lines
21 KiB
Vue
Raw Normal View History

2025-04-28 15:37:57 +08:00
<template>
2025-07-10 10:13:42 +08:00
<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>
<!-- <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-07-10 10:13:42 +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"
>
<bike-info :bikedata="bikeData" @close="closeBikeInfo" />
</div>
<div
v-if="showOrderPay"
style="position: absolute; z-index: 2000; bottom: 0; width: 100vw"
>
<bike-pay :orderId="orderData.orderId" />
</div>
2025-04-28 15:37:57 +08:00
</template>
<script setup>
2025-07-10 10:13:42 +08:00
import { ref, onMounted, getCurrentInstance } from "vue";
import {
showModelMessage,
getUrlParams,
jkcBaseDecode,
} from "@/utils/tools.js";
import { callOrdereApi, callOperateApi } from "@/utils/api.js";
import { findIndex } from "lodash";
import config from "@/utils/config";
import { onShow, onUnload, onLoad } 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;
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({
bikecode: "",
money: "",
time: "",
mileage: "",
});
//订单信息
let orderData = {
bikeCode: null,
status: null,
createdAt: null,
orderId: null,
};
let orderTimer = null;
const orderState = ref(0);
const showOrderPay = ref(false);
//车辆
let arrBikeData = [];
const showBikeInfo = ref(false);
const bikeData = ref({});
const onLoadData = ref({});
let ismount = false;
let arrSiteData = [];
onLoad((query) => {
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) {
showModelMessage("登录后开始骑行", "登录提醒", true, "去登录").then(
(res) => {
if (res.confirm) {
tologin();
}
}
);
}
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-07-10 10:13:42 +08:00
}
}
});
//加载数据
function getLoalcationData() {
map.getLoalcation((res) => {
const { latitude, longitude } = res;
location.value = {
latitude,
longitude,
};
oMap.moveToLocation({});
const params = {
latitude,
longitude,
radius: 1,
};
console.log(params, "11111111111111");
callOrdereApi("userOrders/bikeList", params, "post").then((res) => {
const { code, data, message } = res;
if (code != 200) {
showModelMessage(message);
return;
}
console.log(res);
arrBikeData = data || [];
const arrData = markers.value || [];
arrBikeData.map((item, index) => {
const { longitude, latitude } = item;
arrData.push(
map.addMarker(index, longitude, latitude, "mapbike.png", true)
);
});
markers.value = arrData;
});
getSiteList(longitude, latitude);
});
// uni.getLocation({
// type: 'gcj02',
// geocode: true,
// success(res) {
// location.value = {
// latitude,
// longitude
// };
// },
// fail(res) {
// }
// });
}
function clickMess() {
uni.setStorageSync("kbike-mess", 1);
showMess.value = 1;
}
//刷新
function refresh() {
getLoalcationData();
}
//故障上报
function reportFault() {
if (!oUser) {
tologin();
return;
}
checkRealName((res) => {
if (!res) return;
uni.navigateTo({
url: "/pages/user/login/TroubleReportUser",
});
});
// 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"
// })
}
//申请站点
function applySite() {
if (!oUser) {
tologin();
return;
}
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-07-10 10:13:42 +08:00
}
//个人中心
function getMine() {
if (!oUser) {
tologin();
return;
}
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-07-10 10:13:42 +08:00
}
//扫描
function scanBike() {
if (!oUser) {
tologin();
return;
}
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-07-10 10:13:42 +08:00
}
//显示订单
function openOrderPay() {
showTools.value = false;
showOrderPay.value = true;
}
//获取订单
function getOrder(callBack) {
const { userId } = oUser;
callOrdereApi(
"userOrders/checkHistoryOrder",
{
userId,
},
"get"
).then((res) => {
const { code, data, message } = res;
if (code != 200) {
showModelMessage(message);
if (callBack) callBack(true);
return;
}
if (!data) {
//订单完成
completeRiding();
if (callBack) callBack(true);
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 来停止轮询
}
}, 1000);
}
if (tempLock == 1) {
getTracking();
return;
}
getTracking();
// if (!orderTimer) {
// orderTimer = setInterval(getTracking, 100000);
// }
});
}
const getOrderInfo = (bikeCode) => {
const params = {
userId: oUser.userId,
bikeCode: bikeCode,
};
callOrdereApi("userOrders/costCalculation", params).then((res) => {
if (res.code == 200) {
order.value.money = res.data;
}
});
};
//轨迹
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,
};
});
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,
});
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";
}
uni.navigateTo({
url: url,
});
}
//临时锁车
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) {
clearInterval(orderTimer);
orderTimer = null;
}
orderState.value = 1;
}
});
}
//结束用车
function endRiding() {
checkBikeEnding();
}
function checkBikeEnding(callback) {
const { bikeCode } = orderData;
const params = {
bikeCode,
};
//运营区和停车区检查
const arrMethod = [
callOrdereApi("userOrders/checkBikeInOperation", params, "get"),
callOrdereApi("userOrders/checkBikeInParking", params, "get"),
];
Promise.all(arrMethod).then(([res1, res2]) => {
if (res1.code != 200) {
showModelMessage(res1.message);
return;
}
if (res2.code != 200) {
showModelMessage(res2.message);
return;
}
doneRide();
});
}
//完成骑行
function doneRide() {
uni.showLoading({
title: "正在结束用车",
mask: true,
});
const { userId } = oUser;
const { bikeCode } = orderData;
const params = {
userId,
bikeCode,
};
callOrdereApi("userOrders/doneRide", params, "post")
.then((res) => {
uni.hideLoading();
const { code, data, message } = res;
if (code != 200) {
showModelMessage(message);
return;
}
completeRiding();
openOrderPay();
})
.catch((err) => {
uni.hideLoading();
console.error("结束骑行失败", err);
});
}
//继续骑行 需要开锁
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) {
clearInterval(orderTimer);
orderTimer = null;
}
orderState.value = 0;
}
});
//getOrder();
}
//查看车辆信息
function openBikeInfo(e) {
if (!oUser) {
tologin();
return;
}
const { markerId } = e.detail;
if (markerId == pointEnd || markerId == pointStart) {
return;
}
console.log(arrBikeData[markerId]);
bikeData.value = arrBikeData[markerId];
showBikeInfo.value = true;
showTools.value = false;
showOrderPay.value = false;
}
//关闭车辆信息
function closeBikeInfo() {
showBikeInfo.value = false;
showTools.value = true;
}
onShow(() => {
if (uni.getStorageSync("wechat_user")) {
oUser = JSON.parse(jkcBaseDecode(uni.getStorageSync("wechat_user")));
const { userId } = oUser;
if (userId) {
getOrder();
}
}
console.log("999999999999999999", ismount);
if (ismount) getLoalcationData();
});
onUnload(() => {});
function parseDate(createTime) {
// 将日期字符串转换为 iOS 支持的格式
createTime = createTime.replace(" ", "T"); // 将空格替换为 "T",使其符合 "yyyy-MM-ddTHH:mm:ss" 格式
return new Date(createTime); // 返回新的 Date 对象
}
function timeDifference(createTime) {
const currentTime = new Date();
const createDate = parseDate(createTime); // 使用转换后的日期字符串
const diffInSeconds = Math.floor((currentTime - createDate) / 1000);
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,
};
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));
}
});
polygons.value = arrData;
} else {
console.log("userOrders/siteRegionList", res);
}
});
}
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>
2025-07-10 10:13:42 +08:00
@import url("home.css");
</style>