Răsfoiți Sursa

feat:主页

needcode 2 ani în urmă
părinte
comite
12f6e3badc
3 a modificat fișierele cu 564 adăugiri și 45 ștergeri
  1. 526 11
      src/pages/map/index.vue
  2. 0 34
      src/pages/map/index.wxs
  3. 38 0
      src/utils/location.ts

+ 526 - 11
src/pages/map/index.vue

@@ -1,23 +1,537 @@
 <template>
-  <view class="map pt-50">
-    <button @click="search">搜索</button>
+  <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.StationLat"
+                :longitude="item.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">
+      <view class="filter-dialog">
+        <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"
+      bindgetphonenumber="login"
+      class="full"
+    >登陆按钮</button>
   </view>
 </template>
 
-<script module="mapwxs" lang="wxs" src="./index.wxs"></script>
-<script lang="ts">
-export default {
-  methods: {
-    search() {
-      uni.navigateTo({
-        url: "/pages-charge/search/search",
-      });
+<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 { 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;
+  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.StationLat,
+        longitude: item.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) => {
+  // 扫普通码
+  if (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) {
+      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 = "";
+          getApp<any>().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 = "";
+        getApp<any>().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",
+  });
 };
 </script>
 
 <style lang="scss">
+@import "../../styles/dialog.scss";
 page {
   background-color: #ffffff;
 }
@@ -35,7 +549,8 @@ page {
   top: 0;
   width: 100%;
   height: 100%;
-  z-index: 9999;
+  z-index: 999999;
+  opacity: 0;
 
   .full {
     width: 100%;

+ 0 - 34
src/pages/map/index.wxs

@@ -1,34 +0,0 @@
-function changing(event, ownerInstance) {
-  setActiveBarPercent(
-    ownerInstance,
-    event.detail.value,
-    event.currentTarget.dataset.max
-  );
-  ownerInstance.callMethod("setFilterDistance", event);
-  return false;
-}
-
-function changeValue(newValue, oldValue, ownerInstance, instance) {
-  setActiveBarPercent(ownerInstance, newValue, instance.getDataset().max);
-  return false;
-}
-
-function setActiveBarPercent(ownerInstance, value, max) {
-  console.log(ownerInstance);
-  var active = ownerInstance.selectComponent(".slider_active");
-  var block = ownerInstance.selectComponent(".slider_block");
-  var width = (parseInt(value) / parseInt(max)) * 100;
-  if (width < 1) {
-    width = 0;
-  }
-  active.setStyle({ width: width + "%" });
-  block.setStyle({
-    left: width + "%",
-    transform: "translateX(-" + width + "%)",
-  });
-}
-
-module.exports = {
-  changing: changing,
-  changeValue: changeValue,
-};

+ 38 - 0
src/utils/location.ts

@@ -0,0 +1,38 @@
+let cacheLocation = {
+  latitude: 0,
+  longitude: 0
+}
+
+export function fetchLocation() {
+  return new Promise(resolve => {
+    uni.getLocation({
+      type: 'gcj02',
+      success: res => {
+        const latitude = res.latitude
+        const longitude = res.longitude
+        cacheLocation = {
+          latitude,
+          longitude
+        }
+        resolve(cacheLocation)
+      },
+      fail: err => {
+        // console.log(err)
+        if (/auth/.test(err.errMsg)) {
+          resolve({
+            latitude: 23.098994,
+            longitude: 113.32252
+          })
+          return
+        }
+        if (/电量/.test(err.errMsg)) {
+          resolve(cacheLocation)
+          return
+        }
+        uni.showModal({
+          content: `${err.errMsg},请重试`
+        })
+      }
+    })
+  })
+}