map.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  1. <template>
  2. <view class="container">
  3. <navigation-bar @ready="handleNavReady"></navigation-bar>
  4. <view class="dialog" v-if="styleData.dialog" :style="styleData.dialog">
  5. <view class="height-88 flex-align-center bg-fff">
  6. <view class="dialog_logo ml-24"></view>
  7. <view class="dialog_search ml-24" @click.stop="toSearch"></view>
  8. </view>
  9. <!-- <view class="height-72 flex" style="background-color: #f9f9f9">
  10. <view class="width-half flex-center" @click.stop="checkFilterDistance">
  11. <view class="fs-26 color-000-6 mr-8">距离</view>
  12. <view
  13. class="width-20 height-20 br-round bg-000-08 lh-10 text-center transition"
  14. :style="{
  15. transform: filterDialog.distanceSelector ? 'rotate(180deg)' : '',
  16. }"
  17. >
  18. <uni-icons
  19. type="bottom"
  20. size="8"
  21. color="rgba(0,0,0,0.4)"
  22. ></uni-icons>
  23. </view>
  24. </view>
  25. <view class="width-half flex-center">
  26. <view
  27. class="width-32 height-32 br-round lh-20 text-center"
  28. :style="{
  29. border: filterDialog.discounts
  30. ? '1px solid var(--color-primary)'
  31. : '1px solid rgba(0, 0, 0, 0.4)',
  32. backgroundColor: filterDialog.discounts
  33. ? 'var(--color-primary)'
  34. : '#fff',
  35. }"
  36. >
  37. <uni-icons
  38. type="checkmarkempty"
  39. size="10"
  40. color="#ffffff"
  41. ></uni-icons>
  42. </view>
  43. <view
  44. :class="[
  45. 'fs-26',
  46. 'ml-8',
  47. filterDialog.discounts ? 'color-primary' : 'color-000-6',
  48. ]"
  49. >支持省钱充电</view
  50. >
  51. </view>
  52. </view> -->
  53. <view
  54. class="dialog_selector"
  55. :style="{
  56. height: filterDialog.distanceSelector ? '190rpx' : '0rpx',
  57. borderTop: `1rpx solid rgba(0, 0, 0, ${
  58. filterDialog.distanceSelector ? '0.1' : '0'
  59. })`,
  60. }"
  61. >
  62. <view class="flex-center flex-wrap pb-14">
  63. <view
  64. :class="[
  65. 'type',
  66. 'flex-shrink',
  67. 'flex-center',
  68. 'mt-20',
  69. (index + 1) % 5 === 0 ? 'mr-0' : 'mr-20',
  70. `type-${
  71. item.value === filterDialog.options.distance ? 'active' : ''
  72. }`,
  73. ]"
  74. v-for="(item, index) in filterDialog.distanceRange"
  75. :key="index"
  76. @click.stop="changeFilterDistance(index)"
  77. style="width: 117rpx"
  78. >{{ item.value }}km</view
  79. >
  80. </view>
  81. </view>
  82. <view class="dialog_event" v-if="ready && mapBanner.length > 0">
  83. <swiper
  84. class="swiper"
  85. circular
  86. :indicator-dots="true"
  87. :autoplay="mapBanner.length > 1"
  88. :interval="3000"
  89. >
  90. <swiper-item
  91. class="swiper-item full-percent"
  92. v-for="(item, index) in mapBanner"
  93. :key="index"
  94. @click="to(item.linkUrl)"
  95. >
  96. <view
  97. class="full-percent"
  98. :style="{
  99. backgroundImage: `url(${item.bannerUrl})`,
  100. }"
  101. ></view>
  102. </swiper-item>
  103. </swiper>
  104. </view>
  105. </view>
  106. <view
  107. v-if="styleData.dialogPlaceHolderHeight"
  108. :style="{ height: `${styleData.dialogPlaceHolderHeight}px` }"
  109. ></view>
  110. <map
  111. v-if="ready"
  112. id="map"
  113. :style="{
  114. width: '100%',
  115. height: styleData.dialogHeight
  116. ? `calc(100vh - ${styleData.dialogHeight}px - ${
  117. styleData.cardHeight - 24
  118. }px)`
  119. : '50vh',
  120. zIndex: 1,
  121. pointerEvents: loading || !mapMode ? 'none' : 'auto',
  122. }"
  123. :latitude="mapProps.latitude"
  124. :longitude="mapProps.longitude"
  125. :markers="markers"
  126. min-scale="1"
  127. :scale="mapProps.scale"
  128. @regionchange="mapChange"
  129. @updated="mapUpdated"
  130. @labeltap="tapMarker"
  131. @markertap="tapMarker"
  132. :show-scale="true"
  133. ></map>
  134. <block v-else>
  135. <view
  136. v-if="styleData.dialogHeight"
  137. class="mock-map flex-center"
  138. :style="{
  139. height: `calc(100vh - ${styleData.dialogHeight}px - ${
  140. styleData.cardHeight - 24
  141. }px)`,
  142. }"
  143. >
  144. <image
  145. src="/static/images/map-bg.jpg"
  146. mode="widthFix"
  147. style="width: 100%"
  148. ></image>
  149. <image
  150. src="/static/images/map-current.png"
  151. mode="widthFix"
  152. class="absolute-center"
  153. style="width: 34px"
  154. ></image>
  155. </view>
  156. </block>
  157. <view
  158. class="card"
  159. :style="{
  160. height: mapMode
  161. ? `${styleData.cardHeight}px`
  162. : `calc(100vh - ${styleData.navHeight}px)`,
  163. bottom: '0px',
  164. borderRadius: mapMode ? '16rpx 16rpx 0px 0px' : '0px',
  165. overflowY: mapMode ? 'visible' : 'auto',
  166. }"
  167. @touchstart="touchCardStart"
  168. @touchmove="touchCardMove"
  169. >
  170. <view
  171. v-if="mapMode"
  172. class="card_location height-64 width-64 bg-fff flex-center"
  173. @touchstart.stop="resetLocation"
  174. >
  175. <image
  176. src="/static/images/map-re-location.png"
  177. mode="widthFix"
  178. class="width-48"
  179. ></image>
  180. </view>
  181. <block v-if="station.length">
  182. <!-- 列表 -->
  183. <block v-if="!mapMode">
  184. <view class="station" v-for="(item, index) in station" :key="index">
  185. <view v-if="index !== 0" class="card_line"></view>
  186. <charge-station
  187. :title="item.stationName"
  188. :address="item.address"
  189. :price="item.totalFee"
  190. :fast="item.fastEquipmentInfos"
  191. :slow="item.slowEquipmentInfos"
  192. :sId="item.StationID"
  193. :distance="item.stationLatDistance"
  194. :latitude="item.location.stationLat"
  195. :longitude="item.location.stationLng"
  196. :fromMap="true"
  197. ></charge-station>
  198. </view>
  199. <view class="station-placeholder"></view>
  200. <view class="station-iphonex"></view>
  201. </block>
  202. <block v-else>
  203. <!-- 单个 -->
  204. <view class="station">
  205. <charge-station
  206. :title="station[markersIndex].stationName"
  207. :address="station[markersIndex].address"
  208. :price="station[markersIndex].totalFee"
  209. :fast="station[markersIndex].fastEquipmentInfos"
  210. :slow="station[markersIndex].slowEquipmentInfos"
  211. :sId="station[markersIndex].StationID"
  212. :distance="station[markersIndex].stationLatDistance"
  213. :latitude="station[markersIndex].location.stationLat"
  214. :longitude="station[markersIndex].location.stationLng"
  215. :fromMap="true"
  216. ></charge-station>
  217. </view>
  218. </block>
  219. </block>
  220. <block v-else>
  221. <view class="card_empty flex-column flex-align-center pt-20">
  222. <view v-if="loading" class="mt-60 animation-loading"
  223. ><uni-icons
  224. type="spinner-cycle"
  225. size="20"
  226. color="rgba(0, 0, 0, 0.5)"
  227. ></uni-icons
  228. ></view>
  229. <image
  230. class="image"
  231. v-else
  232. src="/static/images/map-empty.png"
  233. mode="widthFix"
  234. />
  235. <view class="fs-22 mt-14 color-000-5">{{
  236. loading
  237. ? "加载中"
  238. : token
  239. ? "暂无充电站信息"
  240. : "登录后查看更多电站信息"
  241. }}</view>
  242. </view>
  243. </block>
  244. </view>
  245. <view
  246. class="charging flex-align-center"
  247. v-if="charging"
  248. @click="toCharging"
  249. >
  250. <image
  251. class="width-64 ml-12"
  252. src="/static/images/map-charging.png"
  253. mode="widthFix"
  254. ></image>
  255. <view class="fs-26 color-fff ml-12">{{
  256. charging.chargeStatus === 0 ? "已预约" : "充电中"
  257. }}</view>
  258. </view>
  259. </view>
  260. <view class="login-mask" v-if="!token">
  261. <button open-type="getPhoneNumber" @getphonenumber="loginMask" class="full">
  262. 登录按钮
  263. </button>
  264. </view>
  265. </template>
  266. <script setup lang="ts">
  267. const defaulDistance = 3;
  268. const defaultScale = 12;
  269. const pointSize = {
  270. width: 34,
  271. height: 58,
  272. fontSize: 10,
  273. iconPath: "/static/images/map-point.png",
  274. currentWidth: 52,
  275. currentHeight: 86,
  276. currentFontSize: 11,
  277. currentIconPath: "/static/images/map-point-current.png",
  278. androidX: -14,
  279. androidCurrentX: -20,
  280. };
  281. import { fetchHomeBanner } from "@/api";
  282. import { deCode } from "../../utils/code";
  283. import { rpxToPx } from "../../utils/device";
  284. import { fetchToken, login, onLogin } from "@/api/auth";
  285. import { fetchStations, fetchChargeStatus } from "@/api/charge";
  286. import { fetchCollectList } from "@/api/user";
  287. import { fetchLocation } from "@/utils/location";
  288. import { to } from "@/utils/navigate";
  289. import { onLoad, onShow } from "@dcloudio/uni-app";
  290. import { ref } from "vue";
  291. const isIOS = ref(false);
  292. const token = ref<string>();
  293. const ready = ref(false);
  294. const loading = ref(false);
  295. const styleData = ref({
  296. dialog: "",
  297. dialogHeight: 0,
  298. dialogPlaceHolderHeight: 0,
  299. cardHeight: 0,
  300. navHeight: 0,
  301. });
  302. const filterDialog = ref({
  303. discounts: false,
  304. distanceSelector: false,
  305. distanceRange: [
  306. {
  307. value: 1,
  308. scale: defaultScale + 3,
  309. },
  310. {
  311. value: 2,
  312. scale: defaultScale + 1,
  313. },
  314. {
  315. value: 3,
  316. scale: defaultScale,
  317. },
  318. {
  319. value: 5,
  320. scale: defaultScale - 0.2,
  321. },
  322. {
  323. value: 10,
  324. scale: defaultScale - 0.5,
  325. },
  326. {
  327. value: 20,
  328. scale: defaultScale - 1.5,
  329. },
  330. {
  331. value: 30,
  332. scale: defaultScale - 2,
  333. },
  334. {
  335. value: 50,
  336. scale: defaultScale - 2.5,
  337. },
  338. {
  339. value: 100,
  340. scale: defaultScale - 3.5,
  341. },
  342. {
  343. value: 200,
  344. scale: defaultScale - 4.5,
  345. },
  346. ],
  347. options: {
  348. distance: defaulDistance,
  349. status: 0,
  350. },
  351. status: [
  352. {
  353. title: "全部",
  354. },
  355. {
  356. title: "空闲",
  357. },
  358. {
  359. title: "忙碌",
  360. },
  361. ],
  362. });
  363. const stationPage = ref({
  364. page: 1,
  365. pageSize: 6,
  366. hasNext: false,
  367. });
  368. const station = ref<any[]>([]);
  369. const charging = ref<any>();
  370. const mapMode = ref(true);
  371. const mapProps = ref({
  372. latitude: 23.098994,
  373. longitude: 113.32252,
  374. selflatitude: 23.098994,
  375. selflongitude: 113.32252,
  376. scale: defaultScale,
  377. });
  378. const markersIndex = ref(-1);
  379. const markers = ref<any[]>([]);
  380. const mapBanner = ref<any[]>([]);
  381. let isIgnoreChangeLocation = false;
  382. const refreshStation = (location: any) => {
  383. let length = 0;
  384. let available = 0;
  385. const { latitude, longitude } = location;
  386. if (!token.value) {
  387. return;
  388. }
  389. return fetchStations(
  390. stationPage.value.page,
  391. stationPage.value.pageSize,
  392. latitude,
  393. longitude,
  394. mapProps.value.selflatitude,
  395. mapProps.value.selflongitude,
  396. {
  397. distance: filterDialog.value.options.distance,
  398. status: filterDialog.value.options.status,
  399. }
  400. ).then((res) => {
  401. const _markersIndex = stationPage.value.page === 1 ? 0 : markersIndex.value;
  402. const _markers: any[] = res.map((item, index) => {
  403. length = 0;
  404. available = 0;
  405. item.equipmentInfos &&
  406. item.equipmentInfos.forEach((eq: any) => {
  407. eq.connectorInfos &&
  408. eq.connectorInfos.forEach((co: any) => {
  409. length += 1;
  410. if (
  411. co.connectorStatusInfo &&
  412. co.connectorStatusInfo.status === 1
  413. ) {
  414. available += 1;
  415. }
  416. });
  417. });
  418. return {
  419. id: Number(item.StationID),
  420. latitude: item.location.stationLat,
  421. longitude: item.location.stationLng,
  422. iconPath:
  423. index === _markersIndex
  424. ? pointSize.currentIconPath
  425. : pointSize.iconPath,
  426. width:
  427. index === _markersIndex ? pointSize.currentWidth : pointSize.width,
  428. height:
  429. index === _markersIndex ? pointSize.currentHeight : pointSize.height,
  430. label: {
  431. content: `${available}/${length}`,
  432. color: "#ffffff",
  433. fontSize:
  434. index === _markersIndex
  435. ? pointSize.currentFontSize
  436. : pointSize.fontSize,
  437. textAlign: isIOS.value ? "center" : "left",
  438. anchorX: isIOS.value
  439. ? 0
  440. : index === _markersIndex
  441. ? pointSize.androidCurrentX
  442. : pointSize.androidX,
  443. anchorY: -(
  444. (index === _markersIndex
  445. ? pointSize.currentHeight
  446. : pointSize.height) - 3
  447. ),
  448. },
  449. };
  450. });
  451. if (stationPage.value.page === 1) {
  452. _markers.push({
  453. id: -1,
  454. latitude: mapProps.value.selflatitude,
  455. longitude: mapProps.value.selflongitude,
  456. iconPath: "/static/images/map-current.png",
  457. width: 34,
  458. height: 34,
  459. });
  460. }
  461. isIgnoreChangeLocation = markers.value.length !== _markers.length;
  462. stationPage.value.hasNext = res.length >= stationPage.value.pageSize;
  463. // empty.value = stationPage.value.page === 1 ? res.length <= 0 : false;
  464. station.value =
  465. stationPage.value.page === 1 ? res : [...station.value, ...res];
  466. markersIndex.value = _markersIndex;
  467. markers.value = _markers;
  468. return res;
  469. });
  470. };
  471. const refresh = () => {
  472. if (loading.value) {
  473. return;
  474. }
  475. console.log("刷新电站");
  476. uni.showLoading({
  477. title: "加载中",
  478. });
  479. loading.value = true;
  480. stationPage.value.page = 1;
  481. stationPage.value.hasNext = false;
  482. station.value = [];
  483. markers.value = [];
  484. markersIndex.value = 0;
  485. fetchLocation()
  486. .then((res: any) => {
  487. mapProps.value.latitude = res.latitude;
  488. mapProps.value.longitude = res.longitude;
  489. mapProps.value.selflatitude = res.latitude;
  490. mapProps.value.selflongitude = res.longitude;
  491. isIgnoreChangeLocation = true;
  492. return refreshStation(res);
  493. })
  494. .then(() => {
  495. uni.hideLoading();
  496. loading.value = false;
  497. ready.value = true;
  498. })
  499. .catch((err) => {
  500. console.log(err);
  501. uni.hideLoading();
  502. loading.value = false;
  503. uni.showModal({
  504. content: `${err.errMsg},请重试`,
  505. });
  506. });
  507. };
  508. const handleNavReady = (e: any) => {
  509. console.log(e);
  510. styleData.value.dialog = `padding-top:${e.detail.statusBarHeight - 6}px;`;
  511. const searchHeight = rpxToPx(88);
  512. const filterHeight = 0; // rpxToPx(72);
  513. styleData.value.dialogHeight =
  514. e.detail.statusBarHeight - 6 + searchHeight + filterHeight;
  515. styleData.value.dialogPlaceHolderHeight =
  516. styleData.value.dialogHeight - e.detail.navigationBarHeight;
  517. styleData.value.cardHeight = rpxToPx(402) + e.detail.statusBarHeight;
  518. styleData.value.navHeight = e.detail.navigationBarHeight;
  519. };
  520. const toSearch = () => {
  521. if (!ready.value) {
  522. return;
  523. }
  524. uni.navigateTo({
  525. url: "/pages-charge/search/search",
  526. });
  527. };
  528. onLoad((query: any) => {
  529. // 只为了打包进tab-bar使用
  530. console.log(fetchToken, login, onLogin);
  531. // 扫普通码
  532. if (query.q) {
  533. console.log("扫普通码", decodeURIComponent(query.q));
  534. getApp<any>().globalData.normalCode = decodeURIComponent(query.q); // 获取到二维码原始链接内容
  535. }
  536. const device = uni.getSystemInfoSync();
  537. isIOS.value = device.osName === "ios";
  538. setTimeout(() => {
  539. token.value = getApp<any>().globalData.token || "";
  540. if (!token.value) {
  541. isIgnoreChangeLocation = true;
  542. fetchLocation().then((res: any) => {
  543. mapProps.value.latitude = res.latitude;
  544. mapProps.value.longitude = res.longitude;
  545. mapProps.value.selflatitude = res.latitude;
  546. mapProps.value.selflongitude = res.longitude;
  547. markers.value = [
  548. {
  549. id: -1,
  550. latitude: res.latitude,
  551. longitude: res.longitude,
  552. iconPath: "/static/images/map-current.png",
  553. width: 34,
  554. height: 34,
  555. },
  556. ];
  557. });
  558. onLogin((_token) => {
  559. if (getApp<any>().globalData.normalCode) {
  560. const code: string = getApp<any>().globalData.normalCode;
  561. getApp<any>().globalData.normalCode = "";
  562. deCode(code);
  563. }
  564. token.value = _token;
  565. fetchCollectList().then(() => {
  566. refresh();
  567. fetchCharging();
  568. fetchBanner();
  569. });
  570. });
  571. return;
  572. }
  573. fetchCollectList().then(() => {
  574. if (getApp<any>().globalData.normalCode) {
  575. const code: string = getApp<any>().globalData.normalCode;
  576. getApp<any>().globalData.normalCode = "";
  577. deCode(code);
  578. }
  579. refresh();
  580. fetchCharging();
  581. fetchBanner();
  582. });
  583. }, 300);
  584. });
  585. onShow(() => {
  586. if (token.value) {
  587. fetchBanner();
  588. charging.value = undefined;
  589. setTimeout(() => {
  590. fetchCharging();
  591. }, 2000);
  592. }
  593. });
  594. const fetchCharging = () => {
  595. fetchChargeStatus().then((res) => {
  596. if (res && [0, 1, 2, 3].includes(res.chargeStatus)) {
  597. charging.value = res;
  598. }
  599. });
  600. };
  601. const fetchBanner = () => {
  602. fetchHomeBanner().then((res) => {
  603. mapBanner.value = res.filter((item: any) => item.status === 1);
  604. });
  605. };
  606. // const checkDiscounts = () => {
  607. // filterDialog.value.discounts = !filterDialog.value.discounts;
  608. // };
  609. const checkFilterDistance = () => {
  610. if (isIgnoreChangeLocation) {
  611. return;
  612. }
  613. if (!mapMode.value) {
  614. mapMode.value = true;
  615. }
  616. filterDialog.value.distanceSelector = !filterDialog.value.distanceSelector;
  617. };
  618. const changeFilterDistance = (index: number) => {
  619. filterDialog.value.options.distance =
  620. filterDialog.value.distanceRange[index].value;
  621. if (mapProps.value.scale === filterDialog.value.distanceRange[index].scale) {
  622. refresh();
  623. return;
  624. }
  625. mapProps.value.scale = filterDialog.value.distanceRange[index].scale;
  626. checkFilterDistance();
  627. };
  628. const resetLocation = () => {
  629. if (loading.value) {
  630. return;
  631. }
  632. // eslint-disable-next-line promise/catch-or-return
  633. fetchLocation().then((res: any) => {
  634. const mapCtx = uni.createMapContext("map");
  635. const { latitude, longitude } = res;
  636. mapCtx.moveToLocation({
  637. latitude,
  638. longitude,
  639. });
  640. mapProps.value.scale = defaultScale;
  641. });
  642. };
  643. const mapUpdated = (e: any) => {
  644. // console.log('map updated', isIgnoreChangeLocation)
  645. setTimeout(() => {
  646. isIgnoreChangeLocation = false;
  647. }, 500);
  648. };
  649. const mapChange = (e: any) => {
  650. if (isIgnoreChangeLocation) {
  651. return;
  652. }
  653. if (e.type === "end" && markers.value.length) {
  654. // console.log("map change end", {
  655. // ...e.detail.centerLocation,
  656. // });
  657. const current = e.target.centerLocation;
  658. const { latitude, longitude } = current;
  659. stationPage.value.page = 1;
  660. refreshStation({
  661. latitude,
  662. longitude,
  663. });
  664. }
  665. };
  666. const _changeMarker = (current: number) => {
  667. const _markers = JSON.parse(JSON.stringify(markers.value));
  668. const markersNewIndex = current;
  669. _markers[markersIndex.value].iconPath = pointSize.iconPath;
  670. _markers[markersIndex.value].width = pointSize.width;
  671. _markers[markersIndex.value].height = pointSize.height;
  672. _markers[markersIndex.value].label.fontSize = pointSize.fontSize;
  673. _markers[markersIndex.value].label.anchorY = -(pointSize.height - 3);
  674. if (!isIOS) {
  675. _markers[markersIndex.value].label.anchorX = pointSize.androidX;
  676. }
  677. _markers[markersNewIndex].iconPath = pointSize.currentIconPath;
  678. _markers[markersNewIndex].width = pointSize.currentWidth;
  679. _markers[markersNewIndex].height = pointSize.currentHeight;
  680. _markers[markersNewIndex].label.fontSize = pointSize.currentFontSize;
  681. _markers[markersNewIndex].label.anchorY = -(pointSize.currentHeight - 3);
  682. if (!isIOS) {
  683. _markers[markersNewIndex].label.anchorX = pointSize.androidCurrentX;
  684. }
  685. isIgnoreChangeLocation = true;
  686. markers.value = _markers;
  687. markersIndex.value = markersNewIndex;
  688. if (stationPage.value.hasNext && markersNewIndex >= _markers.length - 2) {
  689. stationPage.value.page += 1;
  690. refreshStation({
  691. latitude: mapProps.value.selflatitude,
  692. longitude: mapProps.value.selflongitude,
  693. });
  694. }
  695. };
  696. const tapMarker = (e: any) => {
  697. if (e.detail.markerId === -1) {
  698. return;
  699. }
  700. const findIndex = station.value.findIndex(
  701. (item) => Number(item.StationID) === Number(e.detail.markerId)
  702. );
  703. if (findIndex >= 0) {
  704. _changeMarker(findIndex);
  705. }
  706. };
  707. const loginMask = (e: any) => {
  708. login(e);
  709. };
  710. let startpageY = 0;
  711. const touchCardStart = (e: any) => {
  712. if (loading.value || station.value.length <= 0) {
  713. return;
  714. }
  715. if (e.touches && e.touches.length) {
  716. startpageY = e.touches[0].pageY;
  717. }
  718. };
  719. const touchCardMove = (e: any) => {
  720. if (!startpageY) {
  721. return;
  722. }
  723. const threshold = 200;
  724. if (e.touches && e.touches.length) {
  725. if (mapMode.value && startpageY - e.touches[0].pageY > threshold) {
  726. mapMode.value = false;
  727. }
  728. if (!mapMode.value && e.touches[0].pageY - startpageY > threshold) {
  729. mapMode.value = true;
  730. }
  731. }
  732. };
  733. const toCharging = () => {
  734. to(
  735. charging.value.chargeStatus === 0
  736. ? `/pages-charge/appointment/appointment?sn=${charging.value.connectorId}`
  737. : `/pages-charge/ordering/ordering?sn=${charging.value.connectorId}&start=1`
  738. );
  739. };
  740. </script>
  741. <style lang="scss">
  742. page {
  743. background-color: #ffffff;
  744. }
  745. .container {
  746. position: relative;
  747. height: 100vh;
  748. width: 100vw;
  749. background-color: #ffffff;
  750. }
  751. .mock-map {
  752. position: relative;
  753. width: 100vw;
  754. background-color: #ffffff;
  755. overflow: hidden;
  756. }
  757. .login-mask {
  758. position: fixed;
  759. left: 0;
  760. top: 0;
  761. width: 100%;
  762. height: 100%;
  763. z-index: 999999;
  764. opacity: 0;
  765. .full {
  766. width: 100%;
  767. height: 100%;
  768. }
  769. }
  770. .dialog {
  771. position: fixed;
  772. top: 0;
  773. left: 0;
  774. width: 100%;
  775. z-index: 1000;
  776. &_logo {
  777. width: 156rpx;
  778. height: 100%;
  779. background-position: center;
  780. background-size: 100% auto;
  781. background-repeat: no-repeat;
  782. background-image: url("/static/images/map-logo.png");
  783. }
  784. &_search {
  785. width: 352rpx;
  786. height: 100%;
  787. background-position: center;
  788. background-size: 100% auto;
  789. background-repeat: no-repeat;
  790. background-image: url("/static/images/map-input.png");
  791. }
  792. &_event {
  793. margin-top: 20rpx;
  794. padding: 0rpx 32rpx;
  795. .swiper {
  796. height: 160rpx;
  797. width: 100%;
  798. border-radius: 16rpx;
  799. overflow: hidden;
  800. .swiper-item {
  801. border-radius: 16rpx;
  802. overflow: hidden;
  803. }
  804. view {
  805. background-position: center;
  806. background-repeat: no-repeat;
  807. background-size: 100% 100%;
  808. }
  809. }
  810. }
  811. &_selector {
  812. background-color: #f9f9f9;
  813. transition: all 0.3s;
  814. overflow: hidden;
  815. .type {
  816. width: 160rpx;
  817. height: 60rpx;
  818. background: var(--color-sec);
  819. border-radius: 4rpx;
  820. color: #666;
  821. font-size: 26rpx;
  822. border: 1px solid var(--color-sec);
  823. }
  824. .type-active {
  825. border: 1px solid var(--color-primary);
  826. color: var(--color-primary);
  827. }
  828. }
  829. /* .slider {
  830. position: relative;
  831. height: 12rpx;
  832. width: 100%;
  833. border-radius: 8rpx;
  834. background-color: var(--color-sec);
  835. margin-top: 10rpx;
  836. &_active {
  837. position: absolute;
  838. left: 0;
  839. top: 0;
  840. background-color: var(--color-primary);
  841. border-radius: 8rpx;
  842. height: 12rpx;
  843. width: 0%;
  844. }
  845. &_block {
  846. position: absolute;
  847. width: 40rpx;
  848. height: 40rpx;
  849. border-radius: 50%;
  850. top: -15rpx;
  851. left: 0;
  852. background: rgba(255, 255, 255, 1);
  853. box-shadow: 0px 4rpx 6rpx rgba(52, 125, 255, 0.4);
  854. }
  855. &_wx {
  856. position: absolute;
  857. width: 100%;
  858. left: 0px;
  859. top: -5px;
  860. margin: 0;
  861. opacity: 0;
  862. }
  863. } */
  864. }
  865. .card {
  866. position: fixed;
  867. width: 100%;
  868. left: 0px;
  869. z-index: 1000;
  870. transition: all 0.3s;
  871. box-shadow: 0px 8rpx 20rpx rgba(0, 0, 0, 0.2);
  872. background-color: #fff;
  873. &_location {
  874. position: absolute;
  875. border-radius: 16rpx;
  876. box-shadow: 0px 8rpx 20rpx 0px rgba(0, 0, 0, 0.2);
  877. right: 20rpx;
  878. top: -104rpx;
  879. z-index: 99;
  880. }
  881. &_line {
  882. height: 1rpx;
  883. background-color: rgba(0, 0, 0, 0.1);
  884. margin-left: 30rpx;
  885. margin-right: 30rpx;
  886. }
  887. &_empty {
  888. width: 100%;
  889. height: 100%;
  890. .image {
  891. width: 160rpx;
  892. }
  893. }
  894. .station-placeholder {
  895. min-height: 104rpx;
  896. }
  897. .station-iphonex {
  898. box-sizing: content-box;
  899. padding-bottom: constant(safe-area-inset-bottom);
  900. padding-bottom: env(safe-area-inset-bottom);
  901. }
  902. }
  903. .charging {
  904. position: fixed;
  905. z-index: 1000;
  906. right: 0;
  907. bottom: 164rpx;
  908. width: 186rpx;
  909. height: 88rpx;
  910. border-radius: 88rpx 0px 0px 88rpx;
  911. background: #2d9e95;
  912. margin-bottom: constant(safe-area-inset-bottom);
  913. margin-bottom: env(safe-area-inset-bottom);
  914. }
  915. </style>