| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693 |
- <template>
- <view class="container">
- <map
- id="map"
- style="width: 100%; height: 100%; z-index: 1"
- :latitude="mapProps.latitude"
- :longitude="mapProps.longitude"
- :markers="markers"
- min-scale="1"
- :scale="mapProps.scale"
- @regionchange="mapChange"
- @updated="mapUpdated"
- @labeltap="tapMarker"
- @markertap="tapMarker"
- :show-scale="true"
- ></map>
- <view class="card" v-if="ready">
- <swiper
- class="mt-68"
- :autoplay="false"
- @change="changeMarker"
- :current="markersIndex"
- >
- <block v-if="!empty">
- <swiper-item v-for="(item, index) in station" :key="index">
- <view class="station">
- <charge-station
- :title="item.stationName"
- :address="item.address"
- :price="item.totalFee"
- :fast="item.fastEquipmentInfos"
- :slow="item.slowEquipmentInfos"
- :sId="item.StationID"
- :distance="item.stationLatDistance"
- :latitude="item.location.stationLat"
- :longitude="item.location.stationLng"
- :fromMap="true"
- ></charge-station>
- </view>
- </swiper-item>
- </block>
- <block v-else>
- <swiper-item>
- <view class="station">
- <view class="station-empty flex-column flex-align-center pt-20">
- <image src="/static/images/map-empty.png" mode="widthFix" />
- <view class="fs-22 mt-14" style="color: rgba(0, 0, 0, 0.5)"
- >暂无充电站信息</view
- >
- </view>
- </view>
- </swiper-item>
- </block>
- </swiper>
- </view>
- <view class="icon-menu" v-if="menuStyle.menu1" :style="menuStyle.menu1">
- <view class="flex-center mt-40" @click="search" hover-class="hover">
- <image src="/static/images/map-search.png" mode="widthFix" />
- </view>
- <view
- class="flex-center mt-40"
- @click="toggleDialogVisible"
- hover-class="hover"
- >
- <image src="/static/images/map-filter.png" mode="widthFix" />
- </view>
- </view>
- <view class="icon-menu" v-if="menuStyle.menu2" :style="menuStyle.menu2">
- <view class="flex-center" hover-class="hover" @click="resetLocation">
- <image src="/static/images/map-location.png" mode="widthFix" />
- </view>
- </view>
- <view
- class="dialog"
- v-if="filterDialog.visible"
- @click="toggleDialogVisible"
- >
- <view class="filter-dialog" @click.stop="emptyTap">
- <view :style="filterDialog.style"></view>
- <view class="pl-40 pr-40">
- <view class="pt-20 pb-20">
- <text class="fs-30 fw-500">距离</text>
- </view>
- <view class="flex-wrap pb-14">
- <view
- :class="[
- 'type',
- 'flex-shrink',
- 'flex-center',
- 'mt-20',
- (index + 1) % 5 === 0 ? 'mr-0' : 'mr-20',
- `type-${
- item.value === filterDialog.options.distance ? 'active' : ''
- }`,
- ]"
- v-for="(item, index) in filterDialog.range"
- :key="index"
- @click.stop="changeFilterDistance(index)"
- style="width: 117rpx"
- >{{ item.value }}km</view
- >
- </view>
- <view class="fs-30 fw-500 pt-38 pb-20">充电状态</view>
- <view class="flex pb-30">
- <view
- :class="[
- 'type',
- 'flex-center',
- 'mr-20',
- `type-${index === filterDialog.options.status ? 'active' : ''}`,
- ]"
- v-for="(item, index) in filterDialog.status"
- :key="index"
- @click.stop="changeFilterStatus(index)"
- >{{ item.title }}</view
- >
- </view>
- <view class="foot flex-align-center">
- <style-button size="small" @click.stop="resetFilter"
- >重置</style-button
- >
- <view style="width: 30rpx"></view>
- <style-button size="small" type="primary" @click.stop="submitFilter"
- >确定</style-button
- >
- </view>
- </view>
- </view>
- </view>
- </view>
- <view class="login-mask" v-if="!token">
- <button open-type="getPhoneNumber" @getphonenumber="loginMask" class="full">
- 登录按钮
- </button>
- </view>
- </template>
- <script setup lang="ts">
- const defaulDistance = 3;
- const defaultScale = 12;
- const pointSize = {
- width: 34,
- height: 58,
- fontSize: 10,
- iconPath: "/static/images/map-point.png",
- currentWidth: 52,
- currentHeight: 86,
- currentFontSize: 11,
- currentIconPath: "/static/images/map-point-current.png",
- androidX: -14,
- androidCurrentX: -20,
- };
- import { deCode } from "../../utils/code";
- import { fetchToken, login, onLogin } from "@/api/auth";
- import { fetchStations } from "@/api/charge";
- import { fetchCollectList } from "@/api/user";
- import { fetchLocation } from "@/utils/location";
- import { onLoad } from "@dcloudio/uni-app";
- import { ref } from "vue";
- const isIOS = ref(false);
- const token = ref<string>();
- const ready = ref(false);
- const empty = ref(true);
- const mapProps = ref({
- latitude: 23.098994,
- longitude: 113.32252,
- selflatitude: 23.098994,
- selflongitude: 113.32252,
- scale: defaultScale,
- });
- const filterDialog = ref({
- visible: false,
- style: {},
- range: [
- {
- value: 1,
- scale: defaultScale + 3,
- },
- {
- value: 2,
- scale: defaultScale + 1,
- },
- {
- value: 3,
- scale: defaultScale,
- },
- {
- value: 5,
- scale: defaultScale - 0.2,
- },
- {
- value: 10,
- scale: defaultScale - 0.5,
- },
- {
- value: 20,
- scale: defaultScale - 1.5,
- },
- {
- value: 30,
- scale: defaultScale - 2,
- },
- {
- value: 50,
- scale: defaultScale - 2.5,
- },
- {
- value: 100,
- scale: defaultScale - 3.5,
- },
- {
- value: 200,
- scale: defaultScale - 4.5,
- },
- ],
- options: {
- distance: defaulDistance,
- status: 0,
- },
- status: [
- {
- title: "全部",
- },
- {
- title: "空闲",
- },
- {
- title: "忙碌",
- },
- ],
- });
- const menuStyle = ref({
- menu1: {},
- menu2: {},
- });
- const stationPage = ref({
- page: 1,
- pageSize: 6,
- hasNext: false,
- });
- const station = ref<any[]>([]);
- const markersIndex = ref(0);
- const markers = ref<any[]>([]);
- let isIgnoreChangeLocation = false;
- const refreshStation = (location: any) => {
- let length = 0;
- let available = 0;
- const { latitude, longitude } = location;
- if (!token.value) {
- return;
- }
- return fetchStations(
- stationPage.value.page,
- stationPage.value.pageSize,
- latitude,
- longitude,
- mapProps.value.selflatitude,
- mapProps.value.selflongitude,
- {
- distance: filterDialog.value.options.distance,
- status: filterDialog.value.options.status,
- }
- ).then((res) => {
- const _markersIndex = stationPage.value.page === 1 ? 0 : markersIndex.value;
- const _markers: any[] = res.map((item, index) => {
- length = 0;
- available = 0;
- item.equipmentInfos &&
- item.equipmentInfos.forEach((eq: any) => {
- eq.connectorInfos &&
- eq.connectorInfos.forEach((co: any) => {
- length += 1;
- if (
- co.connectorStatusInfo &&
- co.connectorStatusInfo.status === 1
- ) {
- available += 1;
- }
- });
- });
- return {
- id: Number(item.StationID),
- latitude: item.location.stationLat,
- longitude: item.location.stationLng,
- iconPath:
- index === _markersIndex
- ? pointSize.currentIconPath
- : pointSize.iconPath,
- width:
- index === _markersIndex ? pointSize.currentWidth : pointSize.width,
- height:
- index === _markersIndex ? pointSize.currentHeight : pointSize.height,
- label: {
- content: `${available}/${length}`,
- color: "#ffffff",
- fontSize:
- index === _markersIndex
- ? pointSize.currentFontSize
- : pointSize.fontSize,
- textAlign: isIOS.value ? "center" : "left",
- anchorX: isIOS.value
- ? 0
- : index === _markersIndex
- ? pointSize.androidCurrentX
- : pointSize.androidX,
- anchorY: -(
- (index === _markersIndex
- ? pointSize.currentHeight
- : pointSize.height) - 3
- ),
- },
- };
- });
- if (stationPage.value.page === 1) {
- _markers.push({
- id: -1,
- latitude: mapProps.value.selflatitude,
- longitude: mapProps.value.selflongitude,
- iconPath: "/static/images/map-current.png",
- width: 34,
- height: 34,
- });
- }
- isIgnoreChangeLocation = true;
- stationPage.value.hasNext = res.length >= stationPage.value.pageSize;
- empty.value = stationPage.value.page === 1 ? res.length <= 0 : false;
- station.value =
- stationPage.value.page === 1 ? res : [...station.value, ...res];
- markersIndex.value = _markersIndex;
- markers.value = _markers;
- return res;
- });
- };
- const refresh = () => {
- console.log("刷新电站");
- uni.showLoading({
- title: "加载中",
- });
- stationPage.value.page = 1;
- stationPage.value.hasNext = false;
- station.value = [];
- markers.value = [];
- markersIndex.value = 0;
- filterDialog.value.visible = false;
- fetchLocation()
- .then((res: any) => {
- mapProps.value.latitude = res.latitude;
- mapProps.value.longitude = res.longitude;
- mapProps.value.selflatitude = res.latitude;
- mapProps.value.selflongitude = res.longitude;
- isIgnoreChangeLocation = true;
- return refreshStation(res);
- })
- .then(() => {
- uni.hideLoading();
- ready.value = true;
- })
- .catch((err) => {
- console.log(err);
- uni.hideLoading();
- uni.showModal({
- content: `${err.errMsg},请重试`,
- });
- });
- };
- onLoad((query: any) => {
- // 只为了打包进tab-bar使用
- console.log(fetchToken, login, onLogin);
- // 扫普通码
- if (query.q) {
- console.log("扫普通码", decodeURIComponent(query.q));
- getApp<any>().globalData.normalCode = decodeURIComponent(query.q); // 获取到二维码原始链接内容
- }
- const menu = uni.getMenuButtonBoundingClientRect();
- const window = uni.getWindowInfo();
- const device = uni.getSystemInfoSync();
- isIOS.value = device.osName === "ios";
- menuStyle.value.menu1 = `top:${menu.top + menu.height}px;right:${
- window.windowWidth - menu.right
- }px;`;
- menuStyle.value.menu2 = `bottom:420rpx;right:${
- window.windowWidth - menu.right
- }px;margin-bottom: constant(safe-area-inset-bottom);margin-bottom: env(safe-area-inset-bottom);`;
- filterDialog.value.style = `height:${menu.bottom + 6}px;`;
- setTimeout(() => {
- token.value = getApp<any>().globalData.token || "";
- if (!token.value) {
- isIgnoreChangeLocation = true;
- fetchLocation().then((res: any) => {
- mapProps.value.latitude = res.latitude;
- mapProps.value.longitude = res.longitude;
- mapProps.value.selflatitude = res.latitude;
- mapProps.value.selflongitude = res.longitude;
- markers.value = [
- {
- id: -1,
- latitude: res.latitude,
- longitude: res.longitude,
- iconPath: "/static/images/map-current.png",
- width: 34,
- height: 34,
- },
- ];
- });
- onLogin((_token) => {
- if (getApp<any>().globalData.normalCode) {
- const code: string = getApp<any>().globalData.normalCode;
- getApp<any>().globalData.normalCode = "";
- deCode(code);
- }
- token.value = _token;
- fetchCollectList().then(() => {
- refresh();
- });
- });
- return;
- }
- fetchCollectList().then(() => {
- if (getApp<any>().globalData.normalCode) {
- const code: string = getApp<any>().globalData.normalCode;
- getApp<any>().globalData.normalCode = "";
- deCode(code);
- }
- refresh();
- });
- }, 300);
- });
- const toggleDialogVisible = () => {
- filterDialog.value.visible = !filterDialog.value.visible;
- };
- const changeFilterDistance = (index: number) => {
- filterDialog.value.options.distance = filterDialog.value.range[index].value;
- };
- const changeFilterStatus = (index: number) => {
- filterDialog.value.options.status = index;
- };
- const resetFilter = () => {
- filterDialog.value.options.distance = defaulDistance;
- filterDialog.value.options.status = 0;
- refresh();
- };
- const submitFilter = () => {
- const findIndex = filterDialog.value.range.findIndex(
- (item) => item.value === filterDialog.value.options.distance
- );
- if (mapProps.value.scale === filterDialog.value.range[findIndex].scale) {
- filterDialog.value.visible = false;
- refresh();
- return;
- }
- filterDialog.value.visible = false;
- mapProps.value.scale = filterDialog.value.range[findIndex].scale;
- };
- const resetLocation = () => {
- // eslint-disable-next-line promise/catch-or-return
- fetchLocation().then((res: any) => {
- const mapCtx = uni.createMapContext("map");
- const { latitude, longitude } = res;
- mapCtx.moveToLocation({
- latitude,
- longitude,
- });
- mapProps.value.scale = defaultScale;
- });
- };
- const mapUpdated = (e: any) => {
- setTimeout(() => {
- isIgnoreChangeLocation = false;
- }, 500);
- };
- const mapChange = (e: any) => {
- if (isIgnoreChangeLocation) {
- return;
- }
- if (e.type === "end" && markers.value.length) {
- // console.log("refreshStation");
- const { latitude, longitude } = e.detail.centerLocation;
- stationPage.value.page = 1;
- refreshStation({
- latitude,
- longitude,
- });
- }
- };
- const _changeMarker = (current: number) => {
- const _markers = JSON.parse(JSON.stringify(markers.value));
- const markersNewIndex = current;
- _markers[markersIndex.value].iconPath = pointSize.iconPath;
- _markers[markersIndex.value].width = pointSize.width;
- _markers[markersIndex.value].height = pointSize.height;
- _markers[markersIndex.value].label.fontSize = pointSize.fontSize;
- _markers[markersIndex.value].label.anchorY = -(pointSize.height - 3);
- if (!isIOS) {
- _markers[markersIndex.value].label.anchorX = pointSize.androidX;
- }
- _markers[markersNewIndex].iconPath = pointSize.currentIconPath;
- _markers[markersNewIndex].width = pointSize.currentWidth;
- _markers[markersNewIndex].height = pointSize.currentHeight;
- _markers[markersNewIndex].label.fontSize = pointSize.currentFontSize;
- _markers[markersNewIndex].label.anchorY = -(pointSize.currentHeight - 3);
- if (!isIOS) {
- _markers[markersNewIndex].label.anchorX = pointSize.androidCurrentX;
- }
- isIgnoreChangeLocation = true;
- markers.value = _markers;
- markersIndex.value = markersNewIndex;
- if (stationPage.value.hasNext && markersNewIndex >= _markers.length - 2) {
- stationPage.value.page += 1;
- refreshStation({
- latitude: mapProps.value.selflatitude,
- longitude: mapProps.value.selflongitude,
- });
- }
- };
- const changeMarker = (e: any) => {
- _changeMarker(e.detail.current);
- };
- const tapMarker = (e: any) => {
- if (e.detail.markerId === -1) {
- return;
- }
- const findIndex = station.value.findIndex(
- (item) => Number(item.StationID) === Number(e.detail.markerId)
- );
- if (findIndex >= 0) {
- _changeMarker(findIndex);
- }
- };
- const search = () => {
- uni.navigateTo({
- url: "/pages-charge/search/search",
- });
- };
- const loginMask = (e: any) => {
- login(e);
- };
- const emptyTap = () => {};
- </script>
- <style lang="scss">
- @import "../../styles/dialog.scss";
- page {
- background-color: #ffffff;
- }
- .container {
- position: relative;
- height: 100vh;
- width: 100vw;
- background-color: #ffffff;
- }
- .login-mask {
- position: fixed;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- z-index: 999999;
- opacity: 0;
- .full {
- width: 100%;
- height: 100%;
- }
- }
- .icon-menu {
- position: absolute;
- z-index: 9;
- image {
- width: 60rpx;
- }
- & > view {
- height: 96rpx;
- width: 96rpx;
- border-radius: 50%;
- background-color: #fff;
- box-shadow: 0px 8rpx 20rpx rgba(0, 0, 0, 0.2);
- }
- .hover {
- box-shadow: none;
- }
- }
- .filter-dialog {
- background-color: #fff;
- .slider {
- position: relative;
- height: 12rpx;
- width: 100%;
- border-radius: 8rpx;
- background-color: var(--color-sec);
- margin-top: 10rpx;
- &_active {
- position: absolute;
- left: 0;
- top: 0;
- background-color: var(--color-primary);
- border-radius: 8rpx;
- height: 12rpx;
- width: 0%;
- }
- &_block {
- position: absolute;
- width: 40rpx;
- height: 40rpx;
- border-radius: 50%;
- top: -15rpx;
- left: 0;
- background: rgba(255, 255, 255, 1);
- box-shadow: 0px 4rpx 6rpx rgba(52, 125, 255, 0.4);
- }
- &_wx {
- position: absolute;
- width: 100%;
- left: 0px;
- top: -5px;
- margin: 0;
- opacity: 0;
- }
- }
- .type {
- width: 160rpx;
- height: 60rpx;
- background: var(--color-sec);
- border-radius: 4rpx;
- color: var(--color-gray);
- font-size: 26rpx;
- border: 1px solid var(--color-sec);
- }
- .type-active {
- border: 1px solid var(--color-primary);
- color: var(--color-primary);
- }
- .foot {
- height: 120rpx;
- border-top: 1rpx solid var(--color-sec);
- }
- }
- .card {
- position: absolute;
- width: 100%;
- height: 450rpx;
- left: 0px;
- bottom: 0rpx;
- z-index: 9;
- background: linear-gradient(180deg, rgba(87, 104, 133, 0) 0%, #576885 100%);
- padding-left: 10rpx;
- margin-bottom: constant(safe-area-inset-bottom);
- margin-bottom: env(safe-area-inset-bottom);
- swiper,
- swiper-item {
- width: 100%;
- height: 300rpx;
- }
- .station {
- width: 100%;
- height: 100%;
- padding: 0rpx 20rpx;
- }
- .station-empty {
- width: 100%;
- height: 100%;
- background-color: #fff;
- border-radius: 20rpx 20rpx 0 0;
- image {
- width: 160rpx;
- }
- }
- }
- </style>
|