2025-04-07 19:54:07 +08:00

902 lines
27 KiB
Vue

<template>
<view class="main">
<view
:class="showListPage ? 'mapBox moveLeft' : 'mapBox'"
v-if="!showListPage"
>
<map
id="myMap"
:longitude="longitude"
:latitude="latitude"
class="map"
:scale="17"
:show-location="true"
:markers="markers"
:enable-scroll="!isDragging"
@markertap="handleClickMarker"
></map>
<view class="topBox">
<view class="topRight">
<image
class="searchIcon"
src="https://eshangtech.com/wanmeiyizhanImg/home/searchIcon.png"
/>
<input
style="margin-left: 16rpx; font-size: 28rpx"
placeholder="请输入服务区"
v-model="searchText"
@confirm="handleConfirm"
/>
<!-- <span class="searchText">请输入服务区</span> -->
</view>
<view class="listBox" @click="handleChangePageType">
<image class="listIcon" src="/static/home/listIcon.svg" />
<text class="text">列表</text>
</view>
</view>
<view class="statusBox">
<!-- 国网 -->
<view class="statusItem">
<!-- <image
class="statusIcon"
src="https://eshangtech.com/minTestImg/stateGridIcon.png"
/> -->
<view class="colorBox" style="background-color: #ff9929"></view>
<text class="brandCharge">国网</text>
<span class="empty"></span>
<view class="valueBox">
<span class="emptyValue"
>{{
chargeData && chargeData.GWDetail
? chargeData.GWDetail.GWEmpty
: 0
}}
</span>
<span class="sum"
>/{{
chargeData && chargeData.GWDetail
? chargeData.GWDetail.GWSum
: 0
}}</span
>
</view>
</view>
<!-- 理想 -->
<view class="statusItem">
<view class="colorBox" style="background-color: #d81e06"></view>
<!-- <image
class="statusIcon"
src="https://eshangtech.com/minTestImg/LXIcon.png"
/> -->
<text class="brandCharge">理想</text>
<span class="empty"></span>
<view class="valueBox">
<span class="emptyValue">{{
chargeData && chargeData.LXDetail
? chargeData.LXDetail.LXEmpty
: 0
}}</span>
<span class="sum"
>/{{
chargeData && chargeData.LXDetail
? chargeData.LXDetail.LXSum
: 0
}}</span
>
</view>
</view>
<!-- 蔚来 -->
<view class="statusItem" v-if="false">
<!-- <image
class="statusIcon"
src="https://eshangtech.com/minTestImg/WLIcon.png"
/> -->
<view class="colorBox" style="background-color: #f4ea2a"></view>
<text class="brandCharge">蔚来</text>
<span class="empty"></span>
<view class="valueBox">
<span class="emptyValue">{{
chargeData && chargeData.WLDetail
? chargeData.WLDetail.WLEmpty
? chargeData.WLDetail.WLEmpty
: 0
: 0
}}</span>
<span class="sum"
>/{{
chargeData && chargeData.WLDetail
? chargeData.WLDetail.WLSum
? chargeData.WLDetail.WLSum
: 0
: 0
}}</span
>
</view>
</view>
<!-- 交控 -->
<view class="statusItem">
<!-- <image
class="statusIcon"
src="https://eshangtech.com/wanmeiyizhanImg/home/sunIcon.svg"
/> -->
<view class="colorBox" style="background-color: #57d16e"></view>
<text class="brandCharge">交控新能源</text>
<span class="empty"></span>
<view class="valueBox">
<span class="emptyValue"
>{{
chargeData && chargeData.JKDetail
? chargeData.JKDetail.JKEmpty
: 0
}}
</span>
<span class="sum"
>/{{
chargeData && chargeData.JKDetail
? chargeData.JKDetail.JKSum
: 0
}}</span
>
</view>
</view>
</view>
<view class="serviceDetailBox" v-if="showChargeBox">
<charge-box
:serviceAreaList="currentServiceList"
:pageType="'mapIndex'"
@allChargeData="handleGetChargeData"
@allLXDataList="handleLXAddMarker"
@allJKDataList="handleJKAddMarker"
@allGWDataList="handleGWAddMarker"
/>
</view>
<view
class="scanBox"
@click="handleScan"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
:style="{ top: positionY + 'px', left: positionX + 'px' }"
>
<view class="scanIconBox">
<image class="scanIcon" src="/static/tabs/scanCode.svg" />
</view>
</view>
</view>
<view
:class="showListPage ? 'listPage moveRight' : 'listPage '"
v-if="showListPage"
>
<!-- 搜索框 -->
<view class="searchBox">
<view class="topRight">
<image
class="searchIcon"
src="https://eshangtech.com/wanmeiyizhanImg/home/searchIcon.png"
/>
<input
style="margin-left: 16rpx; font-size: 28rpx"
placeholder="请输入服务区"
v-model="searchText"
@confirm="handleConfirm"
/>
<!-- <span class="searchText">请输入服务区</span> -->
</view>
<view class="listBox" @click="handleChangePageType">
<image class="listIcon" src="/static/home/mapFixed.svg" />
<text class="text">地图</text>
</view>
</view>
<scroll-view class="scrollListBox" :scroll-y="true">
<view v-if="showChargeList">
<charge-box
:serviceAreaList="allServiceNameList"
:pageStyleType="1"
:pageType="'mapList'"
/>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import ChargeBox from "../../components/chargeBox.vue";
export default {
components: { ChargeBox },
data() {
return {
longitude: "",
latitude: "",
seatInfo: {}, // 经纬度数据
currentServiceObj: {}, // 当前选择的服务区
currentServiceList: [], // 当前服务区的名称数组
allServiceNameList: [], // 全部服务区的名字列表
defaultAllServiceNameList: [], // 所有服务区的名称列表
chargeData: {}, // 理想的数据
markers: [], // 点位数据
serviceList: [], // 所有服务区的数据
searchText: "", // 搜索的内容
showChargeBox: true,
showChargeList: true,
showListPage: false, // 是否显示列表页面
isTouchMove: false, // 用于判断是否开始拖动
loginType: "",
menu: {},
startX: 0, // 拖动开始时的 X 坐标
startY: 0, // 拖动开始时的 Y 坐标
positionX: 0, // 元素当前的 X 坐标
positionY: 60, // 元素当前的 Y 坐标
isDragging: false, // 是否正在拖动
screenWidth: 0, // 屏幕宽度
screenHeight: 0, // 屏幕高度
ticking: false, // 用于requestAnimationFrame节流
};
},
onLoad() {
let systemInfo = uni.getSystemInfoSync();
console.log("systemInfo", systemInfo);
this.positionX = systemInfo.safeArea.width - 66;
this.screenWidth = systemInfo.safeArea.width;
this.screenHeight = systemInfo.safeArea.height;
let storgeList = uni.getStorageSync("serviceList");
if (storgeList) {
this.serviceList = JSON.parse(storgeList);
}
let nearService = uni.getStorageSync("nearService");
if (nearService) {
this.seatInfo = {
longitude: nearService.SERVERPART_X,
latitude: nearService.SERVERPART_Y,
};
this.longitude = this.seatInfo.longitude;
this.latitude = this.seatInfo.latitude;
// this.longitude = 116.894166;
// this.latitude = 31.920213;
this.currentServiceObj = nearService;
this.currentServiceList = [nearService.SERVERPART_NAME];
// this.currentServiceList = ["新桥服务区"];
// 全部服务区的名称
this.handleGetServiceNameList();
}
},
methods: {
touchStart(e) {
this.isDragging = true;
this.ticking = false; // 重置ticking状态
const touch = e.touches[0];
this.startX = touch.clientX - this.positionX;
this.startY = touch.clientY - this.positionY;
},
touchMove(e) {
if (this.isDragging) {
// 使用requestAnimationFrame优化渲染性能
if (!this.ticking) {
this.ticking = true;
this.$nextTick(() => {
const touch = e.touches[0];
let newPosX = touch.clientX - this.startX;
let newPosY = touch.clientY - this.startY;
// 限制拖动范围,不让元素移出屏幕
newPosX = Math.max(0, Math.min(newPosX, this.screenWidth - 50)); // 限制 X 轴范围
newPosY = Math.max(0, Math.min(newPosY, this.screenHeight - 50)); // 限制 Y 轴范围
this.positionX = newPosX;
this.positionY = newPosY;
this.ticking = false;
});
}
}
},
touchEnd(e) {
this.isDragging = false;
this.ticking = false; // 重置ticking状态
},
// 取问号后面的参数
getQueryParams(url) {
let queryStr = url.split("?")[1]; // 获取 ? 后面的部分
let params = {};
if (queryStr) {
let pairs = queryStr.split("&");
pairs.forEach((pair) => {
let [key, value] = pair.split("=");
params[key] = decodeURIComponent(value || "");
});
}
return params;
},
// 扫码
handleScan() {
let _this = this;
uni.scanCode({
success: function (res) {
console.log("条码类型:" + res.scanType);
console.log("条码内容:" + res.result);
let url = res.result;
if (url.indexOf("lixiang") !== -1) {
let obj = _this.getQueryParams(url);
console.log("obj", obj);
uni.showModal({
title: "",
content: `识别二维码类型为【理想】,确认跳转?`,
success(res) {
uni.navigateToMiniProgram({
appId: "wxefd5d8119561aaca",
path: `/pages/electricity/pile/index?connectorId=${obj.qrcode}`,
success(res) {},
});
},
});
} else if (url.indexOf("jksdxny") !== -1) {
// 交控
uni.showModal({
title: "",
content: `识别二维码类型为【交控新能源】,确认跳转?`,
success(res) {
uni.navigateToMiniProgram({
appId: "wx01617ba079061ca9",
path: `/pages/map/index`,
success(res) {},
});
},
});
} else if (url.indexOf("app.nio") !== -1) {
// 蔚来
uni.showModal({
title: "",
content: `识别二维码类型为【蔚来】,确认跳转?`,
success(res) {
uni.navigateToMiniProgram({
appId: "wx35849c7f0cf7f7a9",
path: `/pages/index/index`,
success(res) {},
});
},
});
}
},
});
},
// 拿到全部服务区的名称
handleGetServiceNameList() {
let name = [];
if (this.serviceList && this.serviceList.length > 0) {
this.serviceList.forEach((item) => {
name.push(item.SERVERPART_NAME);
});
}
console.log("name", name);
this.allServiceNameList = name;
this.defaultAllServiceNameList = name;
},
// 改变页面显示的内容
handleChangePageType() {
this.showListPage = !this.showListPage;
},
// 搜索服务区的方法
async handleConfirm() {
if (this.showListPage) {
this.showChargeList = false;
} else {
this.showChargeBox = false;
}
this.chaegeBoxList = [];
let req = {
// longitude: this.longitude,
Province_Code: "340000",
longitude: this.seatInfo.longitude,
latitude: this.seatInfo.latitude,
Serverpart_Name: this.searchText,
ShowService: true,
};
const data = await this.$api.$get(
"/CommercialApi/BaseInfo/GetServerpartList",
req
);
let list = data.Result_Data.List;
console.log("listlistlist", list);
let obj = list[0];
if (this.showListPage) {
this.showChargeList = true;
if (this.searchText) {
this.allServiceNameList = [obj.SERVERPART_NAME];
} else {
this.handleGetServiceNameList();
}
} else {
this.seatInfo = {
longitude: obj.SERVERPART_X,
latitude: obj.SERVERPART_Y,
};
this.longitude = this.seatInfo.longitude;
this.latitude = this.seatInfo.latitude;
this.currentServiceObj = obj;
this.currentServiceList = [obj.SERVERPART_NAME];
this.showChargeBox = true;
}
this.searchText = "";
},
// 给理想的充电站标点
handleLXAddMarker(e) {
let stationList = e.res;
let pointList = [];
// 确保一个服务区点位 只用加一个
let pointIdList = [];
if (this.serviceList && this.serviceList.length > 0) {
this.serviceList.forEach((item) => {
if (stationList && stationList.length > 0) {
stationList.forEach((subItem) => {
if (subItem.Address.indexOf(item.SERVERPART_NAME) !== -1) {
const date = new Date();
if (
pointIdList.indexOf(Number(`1${item.SERVERPART_ID}`)) === -1
) {
pointIdList.push(Number(`1${item.SERVERPART_ID}`));
pointList.push({
id: Number(`1${item.SERVERPART_ID}`), // 使用时间戳作为唯一ID
markerId: `${item.SERVERPART_ID}LX`,
serviceId: item.SERVERPART_ID,
serviceName: `${item.SERVERPART_NAME}`,
latitude: subItem.StationLat,
longitude: subItem.StationLng,
iconPath: "/static/home/redFixed.svg",
width: 30,
height: 30,
// label: {
// // 文本标签
// content: "",
// color: "#3EC273",
// fontSize: 14,
// bgColor: "#ffffff",
// borderRadius: 4,
// padding: 5,
// textAlign: "center",
// },
});
}
}
});
}
});
}
this.markers = this.markers.concat(pointList);
},
// 给交控的充电站标点
handleJKAddMarker(e) {
console.log("交控的全部数据", e);
let stationList = e.res;
let pointList = [];
// 确保一个服务区点位 只用加一个
let pointIdList = [];
if (this.serviceList && this.serviceList.length > 0) {
this.serviceList.forEach((item) => {
if (stationList && stationList.length > 0) {
stationList.forEach((subItem) => {
if (subItem.areaName.indexOf(item.SERVERPART_NAME) !== -1) {
const date = new Date();
if (
pointIdList.indexOf(Number(`2${item.SERVERPART_ID}`)) === -1
) {
pointIdList.push(Number(`2${item.SERVERPART_ID}`));
pointList.push({
id: Number(`2${item.SERVERPART_ID}`), // 使用时间戳作为唯一ID
markerId: `${item.SERVERPART_ID}JK`,
serviceId: item.SERVERPART_ID,
serviceName: `${item.SERVERPART_NAME}`,
latitude: subItem.lat,
longitude: subItem.lng,
iconPath: "/static/home/greenFixed.svg",
width: 30,
height: 30,
});
}
}
});
}
});
}
this.markers = this.markers.concat(pointList);
},
// 给国网的充电站标点
handleGWAddMarker(e) {
let stationList = e.res.data.Data.StationInfos;
console.log("stationList国网国网", stationList);
let pointList = [];
// 确保一个服务区点位 只用加一个
let pointIdList = [];
if (this.serviceList && this.serviceList.length > 0) {
this.serviceList.forEach((item) => {
if (stationList && stationList.length > 0) {
stationList.forEach((subItem) => {
if (subItem.Address.indexOf(item.SERVERPART_NAME) !== -1) {
if (
pointIdList.indexOf(Number(`3${item.SERVERPART_ID}`)) === -1
) {
pointIdList.push(Number(`3${item.SERVERPART_ID}`));
pointList.push({
id: Number(`3${item.SERVERPART_ID}`), // 使用时间戳作为唯一ID
markerId: `${item.SERVERPART_ID}GW`,
serviceId: item.SERVERPART_ID,
serviceName: `${item.SERVERPART_NAME}`,
latitude: subItem.StationLat,
longitude: subItem.StationLng,
iconPath: "/static/home/orangeFixed.svg",
width: 30,
height: 30,
});
}
}
});
}
});
}
console.log("国网点位", pointList);
this.markers = this.markers.concat(pointList);
},
// 拿到当前服务区的充电数据
handleGetChargeData(e) {
console.log("当前服务区的充电数据", e);
let obj = e.res[0];
// 因为只返回一个服务区 所以直接e[0]就可以拿到服务区数据
this.chargeData = obj;
// this.markers = [
// {
// id: Number(obj.ServerPart_Id), // 使用时间戳作为唯一ID
// latitude: obj.SERVERPART_Y,
// longitude: obj.SERVERPART_X,
// width: 20,
// height: 30,
// label: {
// // 文本标签
// content: obj.name,
// color: "#3EC273",
// fontSize: 14,
// bgColor: "#ffffff",
// borderRadius: 4,
// padding: 5,
// textAlign: "center",
// },
// },
// ];
},
// 点击地图上的锚点
handleClickMarker(e) {
console.log("e", e);
const clickedMarker = this.markers.find(
(item) => item.id === e.detail.markerId // 用小程序返回的id匹配
);
console.log("业务ID:", clickedMarker);
this.showChargeBox = false;
const serviceDetail = this.serviceList.find(
(item) => item.SERVERPART_ID === Number(clickedMarker.serviceId) // 用小程序返回的id匹配
);
console.log("serviceDetail:", serviceDetail);
this.longitude = this.longitude;
this.latitude = this.latitude;
this.currentServiceObj = serviceDetail;
this.currentServiceList = [clickedMarker.serviceName];
let _this = this;
setTimeout(() => {
_this.showChargeBox = true;
}, 500);
},
},
};
</script>
<style scoped lang="less">
.main {
width: 100vw;
height: 100vh;
position: relative;
overflow: hidden;
.mapBox {
width: 100vw;
height: 100vh;
position: absolute;
top: 0;
left: 0;
transition: transform 0.5s ease;
.map {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
.topBox {
width: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 2;
box-sizing: border-box;
padding: 16rpx;
display: flex;
align-items: center;
justify-content: space-between;
.topRight {
width: calc(100% - 240rpx);
height: 72rpx;
background: #fff;
border-radius: 36rpx;
box-sizing: border-box;
padding: 16rpx 20rpx;
display: flex;
align-items: center;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
.searchIcon {
width: 32rpx;
height: 32rpx;
}
.searchText {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 28rpx;
color: #9fa1aa;
line-height: 40rpx;
text-align: left;
font-style: normal;
margin-left: 8rpx;
}
}
.listBox {
width: 180rpx;
height: 72rpx;
background: #fff;
border-radius: 36rpx;
box-sizing: border-box;
padding: 16rpx 20rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
.listIcon {
width: 40rpx;
height: 40rpx;
margin-right: 12rpx;
}
.text {
font-family: "PingFangSC";
font-weight: 400;
font-size: 30rpx;
color: #130f05;
line-height: 36rpx;
text-align: justify;
font-style: normal;
}
}
}
.statusBox {
box-sizing: border-box;
padding: 16rpx;
border-radius: 16rpx;
background: #fff;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
position: absolute;
top: 120rpx;
left: 16rpx;
z-index: 2;
.statusItem {
display: flex;
align-items: center;
padding: 8rpx 0;
.colorBox {
width: 18rpx;
height: 18rpx;
border-radius: 50%;
overflow: hidden;
margin-right: 16rpx;
}
.statusIcon {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
overflow: hidden;
margin-right: 16rpx;
}
.brandCharge {
font-family: "PingFang SC", "Noto Sans CJK SC", "Microsoft YaHei",
sans-serif;
font-weight: 400;
font-size: 24rpx;
color: #130f05;
line-height: 40rpx;
font-style: normal;
display: inline-block;
width: 120rpx;
margin-right: 16rpx;
}
.empty {
font-family: "PingFangSC";
font-weight: 400;
font-size: 24rpx;
color: #130f05;
line-height: 36rpx;
text-align: left;
font-style: normal;
margin-right: 4rpx;
}
.valueBox {
display: flex;
justify-content: flex-end;
width: 100rpx;
.emptyValue {
font-family: "DINAlternate";
font-weight: 400;
font-size: 28rpx;
color: #130f05;
line-height: 36rpx;
text-align: left;
font-style: normal;
margin-right: 4rpx;
}
.sum {
font-family: "DINAlternate";
font-weight: 400;
font-size: 28rpx;
color: #716f69;
line-height: 36rpx;
text-align: left;
font-style: normal;
}
}
}
}
.serviceDetailBox {
width: calc(100% - 64rpx);
box-sizing: border-box;
padding: 16rpx;
border-radius: 16rpx;
position: absolute;
left: 32rpx;
// bottom: 160rpx;
bottom: 80rpx;
z-index: 2;
background: #fff;
}
.scanBox {
// width: 100%;
width: 100rpx;
height: 100rpx;
// height: 100rpx;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
// bottom: 40rpx;
top: 120rpx;
// left: 0;
right: 16rpx;
z-index: 1;
.scanIconBox {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
background: #ba922f;
display: flex;
justify-content: center;
align-items: center;
.scanIcon {
width: 70rpx;
height: 70rpx;
}
}
}
}
.moveLeft {
transform: translateX(-100%);
}
.listPage {
width: 100%;
height: 100vh;
position: absolute;
top: 0;
left: 100%;
transition: transform 0.5s ease;
box-sizing: border-box;
padding: 16rpx;
z-index: 2;
.searchBox {
width: 100%;
height: 72rpx;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
.topRight {
width: calc(100% - 240rpx);
height: 72rpx;
background: #fff;
border-radius: 36rpx;
box-sizing: border-box;
padding: 16rpx 20rpx;
display: flex;
align-items: center;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
.searchIcon {
width: 32rpx;
height: 32rpx;
}
.searchText {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 28rpx;
color: #9fa1aa;
line-height: 40rpx;
text-align: left;
font-style: normal;
margin-left: 8rpx;
}
}
.listBox {
width: 180rpx;
height: 72rpx;
// background: #fff;
background-image: url("https://eshangtech.com/minTestImg/mapBg.png");
background-repeat: no-repeat;
background-size: 100% 100%;
border-radius: 36rpx;
box-sizing: border-box;
padding: 16rpx 20rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
.listIcon {
width: 40rpx;
height: 40rpx;
margin-right: 12rpx;
}
.text {
font-family: "PingFangSC";
font-weight: 400;
font-size: 30rpx;
color: #130f05;
line-height: 36rpx;
text-align: justify;
font-style: normal;
}
}
}
.scrollListBox {
width: 100%;
height: calc(100% - 100rpx);
margin-top: 16rpx;
}
}
.moveRight {
transform: translateX(-100%);
}
}
</style>