Files
gjt_mini/pages/map/index.vue
2025-12-30 09:44:46 +08:00

1640 lines
52 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="content">
<u-sticky>
<view style="background-color: #fff">
<u-subsection
mode="subsection"
:list="list"
:current="current"
@change="sectionChange"
activeColor="#7ba746"
:fontSize="30"
>
</u-subsection>
<view class="searchBox">
<view class="item" v-if="current === 0">
<u-picker
:show="showPlateNumberPicker"
:columns="[truckList]"
keyName="name"
:immediateChange="true"
@confirm="confirmPlateNumber"
@cancel="showPlateNumberPicker = false"
>
</u-picker>
<u-input
border="surround"
:value="datas.plateNumber"
disabled
fontSize="26"
:disabledColor="'#ffffff'"
placeholder="车牌号"
@tap="searchPlatNumber"
>
</u-input>
</view>
<view class="item" v-else>
<u-picker
:show="showHydrogenPicker"
:columns="[hydrogenList]"
keyName="name"
:immediateChange="true"
@confirm="confirmHydrogen"
@cancel="showHydrogenPicker = false"
>
</u-picker>
<u-input
border="surround"
:value="datas.hydrogenStationName"
disabled
fontSize="26"
:disabledColor="'#ffffff'"
placeholder="加氢站"
@tap="searchHydrogen()"
>
</u-input>
</view>
<image
src="/static/detail.png"
style="width: 32px; height: 32px"
@tap="showPicker"
></image>
</view>
</view>
<ba-tree-picker
ref="treePicker"
:isShowOrgPicker="_showOrgPicker"
@select-change="selectChange"
@emitOrgId="emitOrgId"
:title="` `"
:localdata="listData"
multiple
valueKey="id"
textKey="name"
childrenKey="children"
/>
<page-container
:show="checkListShow"
:duration="200"
:overlay="false"
@beforeleave="onBeforeLeave"
>
<!-- @afterShow="onAfterShow"
@afterHide="onAfterHide" -->
<view class="right-panel" @tap.native.stop="banIosChuanTou">
<view class="panel-header">
<view class="panel-title"
>该区域有以下{{ current === 0 ? "车辆" : "加氢站" }}
</view>
<view v-if="current === 0"
>当前数量:{{ _clusterSelList.length || 0 }}()</view
>
<view class="close-btn" @tap="checkListShow = false">
<u-icon name="close" color="#333" size="22"></u-icon>
</view>
</view>
<view v-if="current === 0" class="tableOption">
<view class="optionItem">
<view
class="item right-u-popup u-border"
style="border-radius: 4px"
>
<u-picker
:show="showOrgPicker"
:columns="[_orgList]"
keyName="nameAndCount"
@confirm="confirmOrg"
:immediateChange="true"
@cancel="showOrgPicker = false"
>
</u-picker>
<u-input
v-model="orgName"
border="surround"
:disabledColor="'#ffffff'"
style="font-size: 13px"
disabled
placeholder="请选择车辆主体"
@tap="showOrgPicker = true"
>
<template slot="suffix">
<view
class="close-btn"
v-if="orgName"
@tap.stop="clearClick"
>
<u-icon name="close" color="#333" size="20"></u-icon>
</view>
</template>
</u-input>
</view>
<view
class="item right-u-popup u-border"
style="border-radius: 4px"
>
<u-input
v-model="plateNumberInput"
border="surround"
:disabledColor="'#ffffff'"
style="font-size: 13px"
placeholder="请输入车牌号"
>
<template slot="suffix">
<view
class="close-btn"
v-if="plateNumberInput"
@tap.stop="clearNumberInput"
>
<u-icon name="close" color="#333" size="20"></u-icon>
</view>
</template>
</u-input>
</view>
</view>
<view class="optionItem">
<view
class="item right-u-popup u-border"
style="border-radius: 4px"
>
<u-picker
:show="showAreaPicker"
:columns="[_areaList]"
keyName="nameAndCount"
@confirm="confirmArea"
:immediateChange="true"
@cancel="showAreaPicker = false"
>
</u-picker>
<u-input
v-model="areaName"
border="surround"
:disabledColor="'#ffffff'"
style="font-size: 13px"
disabled
placeholder="请选择车辆地区代码"
@tap="showAreaPicker = true"
>
<template slot="suffix">
<view
class="close-btn"
v-if="areaName"
@tap.stop="clearClickArea"
>
<u-icon name="close" color="#333" size="20"></u-icon>
</view>
</template>
</u-input>
</view>
<view
class="item right-u-popup u-border"
style="border-radius: 4px"
>
<u-picker
:show="showDepartPicker"
:columns="[_departList]"
keyName="nameAndCount"
@confirm="confirmDepart"
:immediateChange="true"
@cancel="showDepartPicker = false"
>
</u-picker>
<u-input
v-model="departName"
border="surround"
:disabledColor="'#ffffff'"
style="font-size: 13px"
disabled
placeholder="请选择业务部门"
@tap="showDepartPicker = true"
>
<template slot="suffix">
<view
class="close-btn"
v-if="departName"
@tap.stop="clearClickDepart"
>
<u-icon name="close" color="#333" size="20"></u-icon>
</view>
</template>
</u-input>
</view>
</view>
</view>
<view v-else class="tableOption">
<view class="optionItem">
<view
class="item right-u-popup u-border"
style="border-radius: 4px"
>
<u-picker
:show="showCoopPicker"
:columns="[CoopList]"
keyName="dicName"
@confirm="confirmCoop"
:immediateChange="true"
@cancel="showCoopPicker = false"
>
</u-picker>
<u-input
v-model="CoopName"
border="surround"
:disabledColor="'#ffffff'"
style="font-size: 13px"
disabled
placeholder="请选择加氢站合作状态"
@tap="showCoopPicker = true"
>
<template slot="suffix">
<u-icon
v-if="CoopName"
name="close"
color="#bfc7d6"
size="50"
@tap.stop="clearClickCoop"
></u-icon>
</template>
</u-input>
</view>
</view>
</view>
<scroll-view scroll-y="true" style="height: calc(100vh - 200px)">
<view class="rightPop">
<view
v-if="current === 0"
style="
margin: 10px 0;
display: flex;
justify-content: space-between;
"
>
<view>里程单位(km)</view>
<view>
<view
style="
width: 10px;
height: 10px;
background-color: #ffd00e;
border-radius: 50%;
display: inline-block;
margin-right: 5px;
"
>
</view
>表示未对接车机数据</view
>
</view>
<u-row justify="space-between" gutter="10" v-if="current === 0">
<u-col span="3">
<view class="demo-layout">车牌</view>
</u-col>
<u-col span="3">
<view
class="demo-layout"
style="display: flex; align-items: center"
@tap="toggleMileageSort"
>
行驶里程
<text style="margin-left: 4px; font-size: 12px">{{
mileageSortOrder === "desc" ? "↓" : "↑"
}}</text>
</view>
</u-col>
<u-col span="3">
<view class="demo-layout">仪表盘</view>
</u-col>
<u-col span="3">
<view class="demo-layout">部门</view>
</u-col>
</u-row>
<view
v-for="(item, index) in _clusterSelList"
class="clusterItem"
:key="index"
>
<u-badge
v-if="current === 0"
class="dot"
:isDot="true"
:type="item.isOnline === '否' ? 'error' : 'success'"
></u-badge>
<u-badge
v-if="current === 1"
class="dot"
:isDot="true"
:type="item.cooperate ? 'success' : 'error'"
></u-badge>
<view style="display: flex" @tap="gotoDetail(item)">
<view class="item" style="padding-left: 5px">{{
current === 0 ? item.plateNumber : item.stationName
}}</view>
<view class="item" v-if="current === 0">{{
item.dayMileage || 0
}}</view>
<view class="item" v-if="current === 0">
<view v-if="item.totalMileage">{{
item.totalMileage
}}</view>
<view
v-else
style="
width: 10px;
height: 10px;
background-color: #ffd00e;
border-radius: 50%;
"
>
</view>
</view>
<view class="item" v-if="current === 0">{{
item.shortDepName || "--"
}}</view>
</view>
</view>
<!-- <view>查看详细分布</view> -->
</view>
</scroll-view>
</view>
</page-container>
<image
src="/static/reset.png"
style="
width: 26px;
height: 26px;
position: absolute;
left: 4px;
margin-top: 6px;
"
@tap="resetMap"
></image>
<image
v-if="clusterSelList && clusterSelList.length > 0"
src="/static/expand-left-line.png"
style="
position: absolute;
top: 45vh;
right: 4px;
width: 26px;
height: 26px;
"
@tap="backRight"
></image>
</u-sticky>
<!-- :style="{ display: checkListShow ? 'none' : 'block' }" 用来解决穿透问题的方法 但是会导致IOS定位到南极 -->
<view
class="page-section page-section-gap"
:style="{ visibility: checkListShow ? 'hidden' : 'visible' }"
>
<map
id="map"
style="width: 100%; height: calc(100vh - 116px)"
:markers="markers"
:latitude="latitude"
:longitude="longitude"
@tap="mapTap"
@markertap="markertap"
:scale="scale"
@regionchange="onRegionChange"
>
</map>
</view>
<!-- <cover-view class="popup_left"> </cover-view> -->
<cover-view class="popup" v-if="showPopup">
<cover-view class="popup-header">
<!-- <cover-view style="display: flex" :show-location="true"
><cover-image
:src="
current === 0 ? '/static/kachetou.png' : '/static/jiaqingzhan.png'
"
style="width: 40rpx; height: 40rpx; margin: 5px"
></cover-image
>1111</cover-view
> -->
<cover-view style="display: flex; padding: 5px; flex: 1">
<cover-image
:src="
current === 0 ? '/static/kachetou.png' : '/static/jiaqingzhan.png'
"
style="width: 40rpx; height: 40rpx; margin-right: 5px"
></cover-image>
<cover-view style="flex: 1">{{
currMarker.plateNumber || currMarker.name
}}</cover-view>
<cover-image
v-if="current === 0"
:src="
currMarker.isOnline === '否'
? '/static/offline.png'
: '/static/online.png'
"
style="width: 40rpx; height: 40rpx; margin: 0 5px"
>
</cover-image>
<cover-view v-if="current === 0">{{
currMarker.isOnline === "" ? "离线" : "在线"
}}</cover-view>
</cover-view>
<cover-view v-if="current === 0" style="display: flex; padding: 5px">
<cover-image
src="/static/hydrogen.png"
style="width: 36rpx; height: 36rpx; margin-right: 5px"
></cover-image>
<cover-view>{{ currMarker.remainHydrogen || 0 }}kg</cover-view>
<cover-image
src="/static/electricity.png"
style="width: 40rpx; height: 40rpx; margin: 0 5px 0 10px"
></cover-image>
<cover-view>{{ currMarker.soc || 0 }}%</cover-view>
</cover-view>
</cover-view>
<cover-view class="popup-content">
<cover-view style="display: flex">
<u-icon
name="map"
size="45"
slot="active-icon"
color="#2F6D47"
></u-icon>
{{ currMarker.address || "" }}</cover-view
>
<cover-view class="content-items" v-if="current === 0">
<cover-view class="item">
<cover-view>总里程Km</cover-view>
<cover-view>{{ currMarker.totalMileage || 0 }}</cover-view>
</cover-view>
<cover-view class="item">
<cover-view>今日用氢Kg</cover-view>
<cover-view>{{ currMarker.todayHydrogen || 0 }}</cover-view>
</cover-view>
<cover-view class="item">
<cover-view>今日里程Km</cover-view>
<cover-view>{{ currMarker.todayMileage || 0 }}</cover-view>
</cover-view>
</cover-view>
<cover-view v-else>
<cover-view class="content-items" style="text-align: left">
<cover-view style="flex: 1">
氢源{{ currMarker.hydrogenSource || "--" }}
</cover-view>
<cover-view style="flex: 1">
氢气价格{{ currMarker.price + currMarker.priceUnit || "--" }}
</cover-view>
</cover-view>
<cover-view class="content-items" style="text-align: left">
<cover-view style="flex: 1">
站点状态{{ currMarker.isOpenLabel || "--" }}
</cover-view>
<cover-view style="flex: 1">
营业时间{{ currMarker.tradeTimeLabel || "--" }}
</cover-view>
</cover-view>
<cover-view class="content-items" style="text-align: left">
<cover-view style="flex: 1">
联系人{{ currMarker.contact || "--" }}
</cover-view>
<cover-view style="flex: 1">
联系方式{{ currMarker.tel || "--" }}
</cover-view>
</cover-view>
</cover-view>
</cover-view>
</cover-view>
<!-- <h3>常见应用</h3> :markers="covers"-->
<!-- <button @click="gotoMap">进入地图</button> -->
<tab-bar></tab-bar>
</view>
</template>
<script>
// import axios from "@/utils/request";
import { checkButtonPermission } from "@/utils/permission.js";
import baTreePicker from "@/components/ba-tree-picker/ba-tree-picker.vue";
export default {
options: {
styleIsolation: "shared", // 解除样式隔离
},
components: {
baTreePicker,
},
data() {
return {
listData: [],
id: 0, // 使用 marker点击事件 需要填写id
title: "map",
latitude: 34.15394,
scale: 4,
longitude: 108.56325,
truckIcon: "https://lnh2etest.oss-cn-shanghai.aliyuncs.com/truck25.png", //货车图标
hydrogenRefuelingStationIcon:
"https://lnh2etest.oss-cn-shanghai.aliyuncs.com/station25.png", //氢能加电站图标
_mapContext: null,
current: 0,
list: ["车辆", "加氢站"],
showPopup: false,
showLeftPopup: false,
currMarker: null,
popTimer: false,
showPlateNumberPicker: false,
showHydrogenPicker: false,
truckList: [],
hydrogenList: [],
datas: {
plateNumber: "",
truckId: "",
hydrogenStationName: "",
hydrogenStationId: "",
},
covers: [], //用于搜索
markers: [], //用户实现不渲染地图显示callout内容
shouldCluster: true,
isSearch: false, //是否搜索过, 搜过完缩放地图后刷新marker
//includePoints: [], //用来实现缩放 scale不好用 ##25.12.8更新 直接诶用_mapContext.includePoints效果更好
//privatyShow: false,
//showMarkers: [], //用于显示marker
checkListShow: false,
clusterSelList: [],
showOrgPicker: false, //是否显示主体选择器
orgList: [], //组织列表
orgName: "",
areaList: [],
areaName: "", //地区代码
showAreaPicker: false, //是否显示主体选择器
CoopList: [],
CoopName: "", //合作状态
CoopCode: "", //合作状态
showCoopPicker: false, //是否显示合作状态
plateNumberInput: "", //车牌号输入框
departList: [], //业务部门
departName: "", //业务部门
showDepartPicker: false, //是否业务部门选择器
mileageSortOrder: "desc", // 行驶里程排序方向desc-从大到小asc-从小到大
};
},
computed: {
chooseCompany() {
return checkButtonPermission(
"mapOrgSelect",
"vehicle" //按钮在基础信息菜单的车辆信息下面
);
},
_showOrgPicker() {
return this.chooseCompany && this.current === 0;
},
_orgList() {
const arr = this.orgList.map((item) => {
const carNumber =
this.clusterSelList.filter((t) => {
return t.orgName == item.orgName;
})?.length || 0;
item.carNumber = carNumber;
item.nameAndCount = item.orgName + " (" + carNumber + ")";
return item;
});
return arr.filter((item) => item.carNumber) || [];
},
_departList() {
const arr = this.departList.map((item) => {
const carNumber =
this.clusterSelList.filter((t) => {
return (
item.dicName?.toString().indexOf(t.shortDepName) > -1 &&
t.shortDepName
);
})?.length || 0;
item.carNumber = carNumber;
item.nameAndCount = item.dicName + " (" + carNumber + ")";
return item;
});
return arr.filter((item) => item.carNumber) || [];
},
_areaList() {
const arr = this.areaList.map((item) => {
const carNumber =
this.clusterSelList.filter((t) => {
return t.plateNumber?.toString().indexOf(item.dicName) > -1;
})?.length || 0;
item.carNumber = carNumber;
item.nameAndCount = item.dicName + " (" + carNumber + ")";
return item;
});
return arr.filter((item) => item.carNumber) || [];
},
_clusterSelList() {
const isCooperate = this.CoopCode == 1 ? true : false;
console.log(isCooperate);
let filteredList =
this.current === 0
? this.clusterSelList.filter(
(item) =>
(this.orgName === "" || item.orgName === this.orgName) &&
(this.areaName === "" ||
item.plateNumber?.toString().indexOf(this.areaName) > -1) &&
(this.departName === "" ||
this.departName?.toString().indexOf(item.shortDepName) > 0) &&
(this.plateNumberInput === "" ||
item.plateNumber?.toString().indexOf(this.plateNumberInput) >
-1)
)
: this.clusterSelList.filter(
(item) => this.CoopName === "" || item.cooperate === isCooperate
);
// 按行驶里程排序(仅对车辆视图)
if (this.current === 0 && filteredList.length > 0) {
filteredList.sort((a, b) => {
const mileageA = parseFloat(a.dayMileage) || 0;
const mileageB = parseFloat(b.dayMileage) || 0;
// 根据排序方向决定排序方式
return this.mileageSortOrder === "desc"
? mileageB - mileageA // 从大到小
: mileageA - mileageB; // 从小到大
});
}
return filteredList;
},
},
onShow() {
console.log("onShow");
},
onPullDownRefresh(event) {},
mounted() {
console.log("mounted");
this.sectionChange(this.current);
this.getOrgList();
this.getAreaList();
this.getDepartList();
this.getCoopList();
// this.getVehicleMarkers();
//this.gotoMap();
},
beforeDestroy() {
// 清理定时器,防止内存泄露
if (this.popTimer) {
clearTimeout(this.popTimer);
this.popTimer = null;
}
// 清理地图事件监听器
if (this._mapContext) {
this._mapContext.off("markerClusterCreate");
this._mapContext.off("markerClusterClick");
this._mapContext = null;
}
},
methods: {
banIosChuanTou() {
// 阻止iOS事件穿透到地图
console.log("阻止事件穿透");
},
// 切换行驶里程排序方向
toggleMileageSort() {
this.mileageSortOrder = this.mileageSortOrder === "desc" ? "asc" : "desc";
},
// page-container 离开前的处理
onBeforeLeave() {
this.checkListShow = false;
},
// page-container 显示后的处理
// onAfterShow() {
// // 弹窗显示后,地图已经隐藏,无需额外操作
// },
// // page-container 隐藏后的处理
// onAfterHide() {
// // 弹窗隐藏后,地图已经显示,可以重置地图状态
// // this.$nextTick(() => {
// // // 如果需要,可以在这里刷新地图
// // this.createMapContext();
// // });
// },
clearNumberInput() {
this.plateNumberInput = ""; // 重置车牌号输入框
},
clearClickDepart() {
this.departName = ""; // 重置业务部门
},
clearClick() {
this.orgName = ""; // 重置组织名称
},
showOrgPickerFunc() {
this.showOrgPicker = true;
},
showAreaPickerFunc() {
this.showAreaPicker = true;
},
showDepartPickerFunc() {
this.showDepartPicker = true;
},
getOrgList() {
this.orgName = ""; // 重置组织名称
this.$api.map.getOrgsList().then((res) => {
console.log("res:\n", res);
const errList = ["羚牛总部", "嘉兴羚牛汽车服务有限公司"];
this.orgList =
res?.filter((item) => !errList.includes(item.orgName)) || [];
});
},
confirmOrg(e) {
console.log("confirmOrg:\n", e.value[0]);
this.orgName = e.value[0].orgName;
console.log(this.clusterSelList);
this.showOrgPicker = false;
},
clearClickArea() {
this.areaName = ""; //
},
getAreaList() {
this.areaName = ""; //
this.$api.map.getPlateAreaDic().then((res) => {
console.log("res:\n", res);
this.areaList = res || [];
});
},
getDepartList() {
this.departName = ""; //
this.$api.map.getOwnDepartDic().then((res) => {
console.log("res:\n", res);
this.departList = res || [];
});
},
confirmArea(e) {
console.log("confirmArea:\n", e.value[0]);
this.showAreaPicker = false;
this.areaName = e.value[0].dicName;
console.log(this.areaName);
},
confirmDepart(e) {
console.log("confirmDepart:\n", e.value[0]);
this.showDepartPicker = false;
this.departName = e.value[0].dicName;
console.log(this.areaName);
},
clearClickCoop() {
this.CoopName = "";
this.CoopCode = "";
},
getCoopList() {
this.CoopName = "";
this.CoopCode = "";
this.$api.map.getHydrogenCoopDic().then((res) => {
console.log("res:\n", res);
this.CoopList = res || [];
});
},
confirmCoop(e) {
this.CoopName = e.value[0].dicName;
this.CoopCode = e.value[0].dicCode;
this.showCoopPicker = false;
},
resetMap() {
this.sectionChange(this.current, {});
},
backRight() {
if (this.clusterSelList && this.clusterSelList.length > 0) {
//this.includePoints = this.clusterSelList; //返回聚合点视图
this.checkListShow = true;
this._mapContext.includePoints({
points: this.clusterSelList,
padding: [50, 50, 50, 50],
});
this.showPopup = false; //关闭底部弹窗
}
},
// 显示选择器
async showPicker() {
this.showPopup = false;
await this.getInfoTree();
this.$refs.treePicker._initTree();
this.$refs.treePicker._show();
if (this._showOrgPicker) this.$refs.treePicker.getOrgList();
},
//监听选择ids为数组
selectChange(obj) {
//cityFilter
this.sectionChange(this.current, obj);
},
zoomIn(single = null) {
//single为车牌/加氢站搜索功能 不传就是城市搜索
// 通过扩大或缩小 include-points 的范围来控制缩放
// const scale = this.scale * 0.01; // 缩放因子
// const latDelta = 0.01 * scale;
// const lngDelta = 0.01 * scale;
// this.includePoints = single ? [single] : this.covers;
this._mapContext.includePoints({
points: single ? [single] : this.covers,
padding: [50, 50, 50, 50],
});
},
onRegionChange(e) {
console.log(e);
if (e.type === "end") {
// 获取最新的缩放级别
const newScale = e.detail.scale;
console.log("新的缩放级别:", newScale);
// 根据缩放级别决定是否需要聚合
// 更新markers
console.log(newScale);
// if (
// //(this.shouldCluster && newScale < 18) ||
// !this.shouldCluster &&
// newScale >= 18
// ) {
// this.shouldCluster = newScale < 18 ? true : false;
// } else {
// this.shouldCluster = newScale < 18 ? true : false;
// }
if (
//(this.shouldCluster && newScale < 18) ||
this.shouldCluster &&
newScale > 18
) {
this.shouldCluster = false;
} else {
//&& newScale > 14
if (this.isSearch && newScale < 15) {
this.shouldCluster = true;
console.log("onRegionChange------------addMarkers");
//this.addMarkers();
this.markers = this.markers.map((item) => {
item.joinCluster = true;
if (item.id == this.currMarker.hashCode) {
item.callout.display = "ALWAYS";
} else {
item.callout.display = "BYCLICK";
}
return item;
});
this.isSearch = false;
}
// this.createMapContext();
// this.addMarkers();
}
}
},
emitOrgId(id = "") {
this.getInfoTree(id);
},
async getInfoTree(id = "") {
if (this.current === 0) {
await this.$api.map.getTruckInfoTree({ orgId: id }).then((res) => {
console.log("res:\n", res);
this.listData = res || [];
if (id && (!res || res.length === 0)) {
uni.showToast({
title: "该主体下无车辆",
icon: "none",
duration: 1500,
});
}
});
} else {
await this.$api.map.getStationInfoTree().then((res) => {
console.log("res:\n", res);
this.listData = res || [];
});
}
// this.listData = [
// {
// id: 1,
// name: "公司1",
// children: [
// {
// id: 11,
// name: "研发部",
// children: [
// {
// id: 111,
// name: "张三",
// },
// {
// id: 112,
// name: "李四",
// },
// ],
// },
// {
// id: 12,
// name: "综合部",
// },
// ],
// },
// ];
},
getHydrogenStationList(name) {
this.showPopup = false;
this.$api.map.getHydrogenList({ stationName: name }).then((res) => {
console.log("res:\n", res);
this.hydrogenList = res || [];
this.showHydrogenPicker = true;
});
},
confirmHydrogen(e) {
console.log("truckInfo:\n", e.value[0]);
this.datas.hydrogenStationId = e.value[0].id;
this.datas.hydrogenStationName = e.value[0].name;
this.showHydrogenPicker = false;
this.clusterSelList = []; //清除刷新按钮状态,不显示右侧数据
this.gotoMarker();
},
searchPlatNumber() {
console.log(`searchPlatNumber`);
//this.privatyShow = true;
uni.showModal({
title: "车牌号关键字",
confirmText: "搜索",
editable: true,
placeholderText: "请输入车牌号关键字用于检索",
success: (res) => {
res.confirm && this.queryAuthListByPlateNumber(res.content);
},
});
},
searchHydrogen() {
uni.showModal({
title: "加氢站名称关键字",
confirmText: "搜索",
editable: true,
placeholderText: "请输入加氢站名称关键字用于检索",
success: (res) => {
res.confirm && this.getHydrogenStationList(res.content);
},
});
},
queryAuthListByPlateNumber(plateNumber) {
this.$api.map.getAllplateNumbere({ plateNumber }).then((res) => {
console.log("res:\n", res);
this.truckList = res || [];
this.showPopup = false;
this.showPlateNumberPicker = true;
});
},
async confirmPlateNumber(e) {
console.log("truckInfo:\n", e.value[0]);
this.datas.truckId = e.value[0].id;
this.datas.plateNumber = e.value[0].name;
this.showPopup = false;
this.showPlateNumberPicker = false;
this.clusterSelList = []; //清除刷新按钮状态,不显示右侧数据
this.gotoMarker();
},
gotoDetail(item) {
console.log("item:\n", item);
if (this.current === 0) {
this.datas.truckId = item.id;
} else {
this.datas.hydrogenStationId = item.id;
}
this.gotoMarker();
this.checkListShow = false;
},
async gotoMarker() {
const obj =
this.current === 0
? this.covers.find((item) => item.id == this.datas.truckId)
: this.covers.find((item) => item.id == this.datas.hydrogenStationId);
if (!obj) {
console.log("123123");
console.log(this.datas);
console.log(this.covers);
uni.showToast({
title:
this.current === 0
? "该车辆不在当前区域内"
: "该站点不在当前区域内",
icon: "none",
duration: 1500,
});
return;
}
//this.showMarkers = [obj];
// this._mapContext.moveToLocation({
// latitude: Number(obj.latitude),
// longitude: Number(obj.longitude),
// });
this.latitude = Number(obj.latitude);
this.longitude = Number(obj.longitude);
this.zoomIn({ latitude: this.latitude, longitude: this.longitude });
this.scale = 19;
this.onRegionChange({ type: "end", detail: { scale: 19 } });
this.markertap(
{
detail: { markerId: obj.hashCode },
}
// true //用下刷新marker 2025.9.23重构 直接用markers map刷新 不用重新渲染了
);
},
mapTap(row) {
console.log(`mapTap-----------------------------`);
console.log(row);
// console.log(this.currMarker);
// if (
// this.currMarker &&
// this.currMarker.latitude > row.detail.latitude - 1 &&
// this.currMarker.latitude < row.detail.latitude + 1 &&
// this.currMarker.longitude > row.detail.longitude - 1 &&
// this.currMarker.longitude < row.detail.longitude + 1
// ) {
// return;
// }
//为了防止马上隐藏掉popup所以加了一个定时器
if (this.popTimer) {
return;
}
this.showPopup = false;
},
async markertap(row) {
// isUpdate = false
console.log(`markertap#################`);
console.log(row);
this.showPopup = true;
this.popTimer = true;
const currRow =
this.covers.find((item) => item.hashCode == row.detail.markerId) || {};
console.log(currRow);
if (this.current === 0) {
await this.$api.map
.getVehicleDetail({ id: currRow?.id })
.then((response) => {
this.currMarker = response || {};
console.log("currMarker:\n", this.currMarker);
});
} else {
await this.$api.map
.getHydrogenDetail({ id: currRow?.id })
.then((response) => {
this.currMarker = response || {};
console.log("currMarker:\n", this.currMarker);
});
}
const index = this.markers.findIndex((m) => m.id === row.detail.markerId);
this.$set(this.markers, index, {
...this.markers[index],
joinCluster: false,
callout: {
...this.markers[index].callout,
display: "ALWAYS", // 设置为 ALWAYS 显示
color: "#7ba746",
},
});
// const cMarker =
// this.covers.filter((item) => item.hashCode == row.detail.markerId) &&
// this.covers.filter((item) => item.id == row.detail.markerId).length ===
// 1
// ? this.covers.filter((item) => item.id == row.detail.markerId)[0]
// : {};
Object.assign(this.currMarker, currRow);
//获取地址翻译
await this.getAddressByLocation();
//为了实现点击地图空白关闭详情加了定时器
// if (isUpdate) { //都不用重新this.addMarkers()渲染了。 直接makrers.map就行了。。。
// console.log("markertap--------------------addMarkers");
// this.addMarkers(); //为了显示当前点击的marker需要重新渲染整个markers 放在regionchagne里
// }
// 清理之前的定时器,防止重复创建
if (this.popTimer) {
clearTimeout(this.popTimer);
}
this.popTimer = setTimeout(() => {
this.popTimer = null;
this.isSearch = true;
}, 1000);
},
// 在需要的地方导入必要的模块
async getAddressByLocation() {
const { latitude, longitude } = this.currMarker;
this.$api.map.getAddress({ longitude, latitude }).then((res) => {
console.log(res?.data);
this.currMarker.address = res?.data ?? "--";
});
// const key = "GZVBZ-NFU6T-3KKXM-VXORH-ALOT7-AKFBH"; // 替换为你的实际密钥
// const url = `https://apis.map.qq.com/ws/geocoder/v1/?location=${latitude},${longitude}&key=${key}`;
// try {
// const response = await uni.request({
// url: url,
// method: "GET",
// });
// console.log(response);
// if (response.statusCode === 200) {
// // 请求成功
// console.log(response.data.result.address);
// this.currMarker.address = response.data.result.address;
// // return response[1].data.result.address;
// } else {
// console.error("获取地址失败");
// }
// } catch (error) {
// console.error("请求出错:", error);
// }
},
async sectionChange(index, params = undefined) {
this.clusterSelList = []; //清除刷新按钮右侧列表状态
this.current = index;
this.showPopup = false;
this.datas = {
plateNumber: "",
truckId: "",
hydrogenStationName: "",
hydrogenStationId: "",
};
let obj = params || undefined;
if (index === 0) {
await this.getVehicleMarkers(obj);
} else {
await this.getHydrogenStationMarkers(obj);
}
},
createMapContext() {
// 清理之前的地图上下文,防止重复创建
if (this._mapContext) {
this._mapContext.off("markerClusterCreate");
this._mapContext.off("markerClusterClick");
this._mapContext = null;
}
// 创建地图对象
this._mapContext = uni.createMapContext("map", this);
// 仅调用初始化,才会触发 on.("markerClusterCreate", (e) => {})
this._mapContext.initMarkerCluster({
// 初始化点聚合的配置 文档https://developers.weixin.qq.com/miniprogram/dev/api/media/map/MapContext.initMarkerCluster.html
enableDefaultStyle: false, // 是否使用默认样式
zoomOnClick: true, //点击已经聚合的标记点时是否实现聚合分离
gridSize: 60, //聚合算法的可聚合距离,即距离小于该值的点会聚合至一起,以像素为单位
complete(res) {
console.log("initMarkerCluster", res);
},
});
// 新的聚合簇产生时触发 缩放或拖动导致新的聚合簇产生时触发,仅返回新创建的聚合簇信息
//https://developers.weixin.qq.com/miniprogram/dev/api/media/map/MapContext.on.html
this._mapContext.on("markerClusterCreate", (e) => {
let clusterMarkers = [];
const clusters = e.clusters; // 新产生的聚合簇
clusters.forEach((cluster, index) => {
const {
center, // 聚合点的经纬度数组
clusterId, // 聚合簇id
markerIds, // 已经聚合了的标记点id数组
} = cluster;
let color = "#419afcD9";
if (markerIds.length > 100) {
color = "#b700ffD9";
} else if (markerIds.length > 10) {
color = "#ffbf00D9";
}
let clusterObj = {
clusterId, //必须
...center,
width: 0,
height: 0,
iconPath: "",
label: {
// 定制聚合簇样式
content: markerIds.length + "",
fontSize: 16,
color: "#fff",
width: 50,
height: 50,
bgColor: color,
borderRadius: 25,
textAlign: "center",
anchorX: -0,
anchorY: -25,
},
};
clusterMarkers.push(clusterObj);
});
// 添加聚合簇
this._mapContext.addMarkers({
markers: clusterMarkers,
clear: false, //是否先清空地图上所有的marker
});
});
this._mapContext.on("markerClusterClick", (res) => {
this.clearNumberInput();
console.log("点击聚合簇", res);
// this._mapContext.getScale({
// success: (res) => {
// console.log("缩放级别", res.scale);
// this.scale = res.scale;
// },
// });
this.showPopup = false; //底部pop
this.checkListShow = true; //右侧pop
if (this.current === 0) {
//点击聚合簇时,清除筛选条件
this.orgName = "";
this.areaName = "";
} else {
this.CoopName = "";
this.CoopCode = "";
}
const numCluster = res.cluster.markerIds.map((item) => Number(item));
this.clusterSelList =
this.covers.filter((item) => numCluster.includes(item.hashCode)) ||
[];
console.log("聚合簇点击", this.clusterSelList);
});
},
// 调接口获取所有点标记经纬度
// 添加点标记
addMarkers() {
console.log(
"addMarkers----------------------------------------------=--"
);
let markers = [];
let iconPath = "";
let calloutText = "";
console.log("this.shouldCluster", this.shouldCluster);
console.log(this.shouldCluster);
console.log("this.covers", this.covers);
this.covers.forEach((item) => {
//根据点位类型不同定义不同的标记icon
switch (item.type) {
case "1":
iconPath =
item.isOnline === "否"
? `/static/mapcar2.png`
: `/static/mapcar.png`;
calloutText = item.plateNumber;
break;
case "2":
//iconPath = this.hydrogenRefuelingStationIcon;
iconPath = item.cooperate
? `/static/maph.png`
: `/static/maph2.png`;
calloutText = item.stationName;
break;
}
// let flag = false;
// if (this.currMarker && item.hashCode === this.currMarker.hashCode) {
// flag = true;
// console.log("currFlag=true", item); 不通过addMarkers改callout-display-ALWAYS了 直接用$set makrers
// }
let markerObj = {
width: 25,
height: 25,
id: item.hashCode,
iconPath,
latitude: Number(item.latitude),
longitude: Number(item.longitude),
joinCluster: this.shouldCluster, // 产生聚合簇,需添加该属性
callout: {
content: calloutText,
// color: flag ? "#7ba746" : "#000",
color: "#000",
fontSize: 12,
borderRadius: 5,
bgColor: "#fff",
padding: 5,
display: "BYCLICK", // 或 'BYCLICK'
// display: flag ? "ALWAYS" : "BYCLICK", // 或 'BYCLICK'
},
//title: item.plateNumber,
zIndex: 9999,
anchor: {
x: 0.5,
y: 1,
},
};
const newMarker = Object.assign({}, markerObj);
markers.push(newMarker);
});
this.markers = markers; //为了渲染callout
this._mapContext.addMarkers({
markers,
clear: true, // 是否先清空地图上所有marker
});
},
async getHydrogenStationMarkers(params = undefined) {
await this.$api.map.getHydrogenStationMarkers(params).then((response) => {
console.log("res:\n", response);
let arr = response.filter(
(item) =>
item.latitude > -90 &&
item.latitude < 90 &&
item.longitude > -180 &&
item.longitude < 180
);
// console.log(arr.filter((item) => item.id == 568809102995525));
// const tempType = this.current === 0 ? "1" : "2";
// this.covers = arr.filter((item) => item.type === tempType);
this.covers = arr.map((item) => {
item.hashCode = Number(item.hashCode);
item.type = "2";
return item;
}); //接口重写不用前端过滤了
if (params) {
console.log("如果是区域搜索重置地图视野");
if (this.covers && this.covers.length === 1) {
this.gotoDetail(this.covers[0]); //如果是一个加氢站走gotoMarker
// this.gotoDetail(params.cityFilter[0]); //如果是一个加氢站走gotoMarker
} else {
this.zoomIn();
}
} else {
this.latitude = 34.15394;
this.longitude = 108.56325;
this.scale = 4; //缩放
}
//this.showMarkers = [...this.covers];
console.log("arr", arr);
this.createMapContext();
this.addMarkers();
});
},
async getVehicleMarkers(params = undefined) {
await this.$api.map.getVehicleMarkers(params).then((response) => {
console.log("res:\n", response);
let arr =
response && response.length > 0
? response.filter(
(item) =>
item.latitude > -90 &&
item.latitude < 90 &&
item.longitude > -180 &&
item.longitude < 180
)
: [];
// console.log(arr.filter((item) => item.id == 568809102995525));
// const tempType = this.current === 0 ? "1" : "2";
// this.covers = arr.filter((item) => item.type === tempType);
this.covers = arr.map((item) => {
item.hashCode = Number(item.hashCode);
item.type = "1";
return item;
}); //接口重写不用前端过滤了
if (params) {
//如果是区域搜索重置地图视野
console.log("如果是区域搜索重置地图视野");
if (this.covers && this.covers.length === 1) {
this.gotoDetail(this.covers[0]); //如果是一辆车走gotoMarker
} else {
this.zoomIn();
}
} else {
this.latitude = 34.15394;
this.longitude = 108.56325;
this.scale = 4; //缩放
}
//this.showMarkers = [...this.covers];
console.log("getVehicleMarkers----------addMarkers", arr);
this.createMapContext();
this.addMarkers();
});
// axios
// .post(`http://47.99.166.38:20000/VehicleDataActual/getVehicleMarkers`)
// .then((response) => {
// //let arr = response.slice(0, 100);
// let arr = response.filter(
// (item) =>
// item.latitude > -90 &&
// item.latitude < 90 &&
// item.longitude > -180 &&
// item.longitude < 180
// );
// // console.log(arr.filter((item) => item.id == 568809102995525));
// const tempType = this.current === 0 ? "1" : "2";
// this.covers = arr.filter((item) => item.type === tempType);
// console.log("arr", arr);
// this.createMapContext();
// this.addMarkers();
// // this.covers = arr.map((item) => {
// // item.iconPath =
// // item.type == 2
// // ? this.hydrogenRefuelingStationIcon
// // : this.truckIcon;
// // item.width = 25;
// // item.height = 25;
// // item.joinCluster = item.type == 1 ? true : false;
// // return item;
// // });
// // console.log(this.covers);
// });
// this.hMarkers = HM;
},
// gotoMap() {
// uni.navigateTo({
// url: `/pages/webview/index?url=http://192.168.130.136:3000/baiduMap`,
// success: () => {},
// fail: (err) => {
// console.log("Failed to navigate back:", err);
// },
// });
// },
},
};
</script>
<style lang="less" scoped>
.banner {
height: 30vh;
width: 100%;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
.login-btn {
margin: 30rpx 0rpx;
}
.wexin-but::after {
border: unset !important;
}
.wexin-but {
border: unset !important;
border-radius: unset;
box-sizing: unset;
background-color: transparent;
padding-left: 0px;
padding-right: 0px;
}
</style>
<style lang="less" scoped>
/deep/ .right-u-popup.u-border {
border-width: 1rpx !important;
border-color: #d4c7c7 !important;
border-style: solid !important;
}
/deep/.u-picker__view {
height: 200px !important;
}
/deep/ .u-popup .uicon-close {
font-size: 25px !important;
}
/* 解决iOS点击穿透问题 */
/deep/ .u-popup__content {
background-color: #fff;
position: relative;
z-index: 9999;
}
/* page-container 右侧面板样式 */
.right-panel {
position: fixed;
top: 0;
right: 0;
width: 100%;
height: 100vh;
background-color: #fff;
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1);
z-index: 999;
display: flex;
flex-direction: column;
transition: transform 0.3s ease-in-out;
transform: translateX(0);
pointer-events: auto;
}
/* 页面区域过渡效果 */
.page-section {
transition: opacity 0.2s ease-in-out;
}
.panel-header {
padding: 15px;
border-bottom: 1px solid #eee;
display: flex;
align-items: center;
justify-content: space-between;
}
.close-btn {
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background-color: #f5f5f5;
}
.panel-title {
font-size: 16px;
font-weight: bold;
color: #333;
display: flex;
justify-content: space-between;
}
.tableOption {
display: flex;
flex-direction: column;
gap: 10px;
padding: 0 10px;
.optionItem {
display: flex;
gap: 10px;
.item {
flex: 1;
}
}
}
.rightPop {
padding: 0 15px 30px 25px;
// .demo-layout {
// margin-top: 15px;
// }
.clusterItem {
padding: 5px 0;
margin: 7px 0;
position: relative;
background-color: #f2f1f6;
/deep/ .u-badge--success {
background-color: #7ba746 !important;
}
/deep/ .u-badge--dot {
position: absolute;
top: 50%;
transform: translateY(-50%);
left: -12px;
}
.item {
flex: 1;
display: inline-block;
// max-width: 150px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 13px;
}
}
}
.content {
background: #e1eae5;
height: calc(100vh - 50px);
// /deep/ .u-tabbar-item {
// padding-bottom: 19px;
// }
.searchBox {
display: flex;
.item {
flex: 1;
}
}
// .popup_left {
// position: absolute;
// background-color: white;
// height: 500px;
// width: 100%;
// left: 0;
// bottom: 0;
// border-radius: 5px;
// box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
// }
.popup {
position: absolute;
background-color: white;
height: 200px;
width: 100%;
left: 0;
bottom: 0;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
.popup-header {
color: #fff;
line-height: 30px;
display: flex;
justify-content: space-between;
background-color: #7ba746;
}
.popup-content {
display: flex;
flex-direction: column;
padding: 10rpx;
.content-items {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
text-align: center;
font-size: 24rpx;
.item {
flex: 1;
margin: 10rpx 10rpx 0;
padding: 20rpx 0;
border: 1px solid #7ba746;
font-size: 28rpx;
border-radius: 20rpx;
}
}
}
}
}
</style>