parkingLists.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. <template>
  2. <view class="parking">
  3. <view class="loading" v-show="loading">
  4. <u-loadmore status="loading" icon-type="flower" :load-text="{ loading: '正在定位中...' }" />
  5. </view>
  6. <view class="parking-header">
  7. <u-search placeholder="搜索停车点" v-model="searchContent" :show-action="false" @change="searchInputChange"> </u-search>
  8. <u-icon
  9. v-if="!searchContent && isShowSearchParking == false"
  10. class="icon"
  11. name="list"
  12. size="44"
  13. color="#ffffff"
  14. placeholder-color="#B5B5B5"
  15. search-icon-color="#B3B3B3"
  16. @click="listIconClick"
  17. />
  18. <u-icon
  19. v-if="searchContent || isShowSearchParking == true"
  20. class="icon"
  21. name="close"
  22. size="36"
  23. color="#ffffff"
  24. placeholder-color="#B5B5B5"
  25. search-icon-color="#B3B3B3"
  26. @click="clearSearchInput"
  27. />
  28. </view>
  29. <view class="parking-map">
  30. <map
  31. id="pagemap"
  32. style="width: 100%; height: calc(100vh - 240rpx)"
  33. :show-location="true"
  34. :latitude="latitude"
  35. :longitude="longitude"
  36. @markertap="markertap"
  37. :enable-traffic="true"
  38. :enable-zoom="true"
  39. :scale="scale"
  40. :markers="covers"
  41. />
  42. </view>
  43. <view class="address-box" :class="nearParkingObj.type == 'down' ? 'address-down' : 'address-up'" v-if="nearParkingFlag">
  44. <view class="address-box-down-icon" :class="{ 'up-icon': nearParkingObj.type === 'up' }" @click="pullDown"> </view>
  45. <!-- tab -->
  46. <template v-if="projectFlag !== 'zhenning'">
  47. <u-tabs :list="tabObj.tabList" :is-scroll="false" :current="tabObj.current" bg-color="transparent" @change="tabChange" />
  48. </template>
  49. <scroll-view scroll-y class="address-box-scroll" :style="{ height: `calc(${nearParkingObj.height} - 164rpx)` }">
  50. <view class="address-box-list" v-if="nearParkingList.length > 0">
  51. <view class="address-box-list-item" v-for="(item, index) in nearParkingList" :key="index" @click="positionAddress(item)">
  52. <view class="abli-header">
  53. <view class="abli-header-title"
  54. >{{ item.roadName || item.parkName }} <text class="abli-header-subtitle">{{ item.areaName }}</text></view
  55. >
  56. <view class="abli-header-surplus">
  57. <view class="abli-header-surplus-left">
  58. 余位<text>{{ item.spaceIdle || item.surplusPlace }}</text></view
  59. >
  60. <template v-if="tabObj.current === 1">
  61. <view class="abli-header-surplus-right" @click.stop="createMonth(item)">办理包月</view>
  62. </template>
  63. <template v-else-if="item.monthAmount">
  64. <view class="abli-header-surplus-right" @click.stop="createMonth(item)">办理包月</view>
  65. </template>
  66. <template v-else>
  67. <view class="abli-header-surplus-right" :class="{ disabled: !item.monthAmount }"> 办理包月</view>
  68. </template>
  69. </view>
  70. </view>
  71. <view class="abli-bottom">
  72. <view class="abli-bottom-left">
  73. <view
  74. class="abli-bottom-left-navigation"
  75. v-if="currentPosition.latitude && currentPosition.longitude"
  76. @click.stop="navigation(item.latitude, item.longitude, item.roadName || item.parkName)"
  77. >导航</view
  78. >
  79. <view class="abli-bottom-left-navigation-disabled" @click="disabledNavigation" v-else>导航</view>
  80. <view class="abli-bottom-left-distance">{{ item.distance | kmUnit }}</view>
  81. </view>
  82. <view class="abli-bottom-right" @click.stop="lookParkingRule(item)">收费规则</view>
  83. </view>
  84. </view>
  85. </view>
  86. <view class="address-box-list" v-else>
  87. <u-empty text="暂无数据" mode="list"></u-empty>
  88. </view>
  89. </scroll-view>
  90. </view>
  91. <view class="parking-address-list" v-if="isShowSearchParking">
  92. <view class="parking-address-list-item" v-for="(item, index) in searchParkingList" :key="index + 's'" @click="clickSearchParking(item)">
  93. <view class="pali-left">
  94. <view>{{ item.roadName || item.parkName }}</view>
  95. <view>{{ item.areaName }}</view>
  96. </view>
  97. <view class="pali-right" v-if="currentPosition.latitude && currentPosition.longitude">
  98. <image
  99. src="/static/img/distance-icon.png"
  100. mode=""
  101. @click.stop="navigation(item.latitude, item.longitude, item.roadName || item.parkName)"
  102. ></image>
  103. <view>路线</view>
  104. </view>
  105. <view class="pali-right" v-else>
  106. <image src="/static/img/distance-icon.png" mode="" @click.stop="disabledNavigation"></image>
  107. <view>路线</view>
  108. </view>
  109. </view>
  110. </view>
  111. <u-select v-model="mapSelect" :list="mapSelectList" @confirm="mapSelectConfirm" />
  112. <map id="map" hidden="true" />
  113. <u-toast ref="uToast" />
  114. </view>
  115. </template>
  116. <script>
  117. import { qqMapTransBMap } from '@/utils/mapTrans.js';
  118. export default {
  119. data() {
  120. return {
  121. tabObj: {
  122. current: 0,
  123. tabList: [
  124. {
  125. name: '路段'
  126. },
  127. {
  128. name: '停车场'
  129. }
  130. ]
  131. },
  132. searchContent: '',
  133. page_map: '',
  134. loading: false,
  135. latitude: 26.64969,
  136. longitude: 106.636453,
  137. scale: 16,
  138. currentPosition: {
  139. latitude: '',
  140. longitude: ''
  141. },
  142. covers: [],
  143. // 附近列表是否显示
  144. nearParkingFlag: false,
  145. // 轮播选中
  146. swiperCurrent: 0,
  147. // 附近停车列表
  148. nearParkingList: [],
  149. // 是否显示停车场列表
  150. isShowSearchParking: false,
  151. // 搜索停车场列表
  152. searchParkingList: [],
  153. // 显示单个停车场数据
  154. isShowParkingDetail: false,
  155. // 单个停车场数据
  156. parkingDetailData: {},
  157. mapSelect: false,
  158. mapSelectList: [
  159. {
  160. value: '1',
  161. label: '腾讯地图'
  162. },
  163. {
  164. value: '2',
  165. label: '百度地图'
  166. },
  167. {
  168. value: '3',
  169. label: '高德地图'
  170. }
  171. ],
  172. // 选中位置经纬度
  173. currentPositionHover: {},
  174. nearParkingObj: {
  175. height: '60vh',
  176. type: 'down'
  177. }
  178. };
  179. },
  180. onLoad(page) {
  181. this.getLocation();
  182. if (page.keyword) {
  183. this.searchContent = page.keyword;
  184. this.searchInputChange(page.keyword);
  185. }
  186. },
  187. methods: {
  188. /**
  189. * 查询输入框发生变化
  190. * @date 2021-08-10
  191. * @param {String} value
  192. */
  193. searchInputChange(value) {
  194. // 为空时关闭搜索列表
  195. if (value === '') {
  196. this.isShowSearchParking = false;
  197. }
  198. this.isShowParkingDetail = false;
  199. const obj = {
  200. 0: 'getNearRoadsl',
  201. 1: 'getParkingLotList'
  202. };
  203. this[obj[this.tabObj.current]]();
  204. },
  205. /**
  206. * 获取定位
  207. * @date 2021-08-10
  208. * @returns {any}
  209. */
  210. getLocation() {
  211. const that = this;
  212. console.log('请求定位');
  213. that.loading = true;
  214. if (navigator.geolocation) {
  215. const obj = {
  216. 0: 'getNearRoadsl',
  217. 1: 'getParkingLotList'
  218. };
  219. // 判断是否有这个对象
  220. navigator.geolocation.getCurrentPosition(
  221. function (pos) {
  222. console.log('浏览器获取位置成功:', JSON.stringify(pos));
  223. console.log('经度:' + pos.coords.longitude + '纬度:' + pos.coords.latitude);
  224. that.latitude = pos.coords.latitude;
  225. that.longitude = pos.coords.longitude;
  226. that.currentPosition.latitude = pos.coords.latitude;
  227. that.currentPosition.longitude = pos.coords.longitude;
  228. that.loading = false;
  229. that[obj[that.tabObj.current]]();
  230. },
  231. function (err) {
  232. console.log('浏览器获取位置失败:', JSON.stringify(err));
  233. that.loading = false;
  234. that.$refs.uToast.show({
  235. title: '您已拒绝授权位置信息或者获取位置信息失败!',
  236. type: 'error',
  237. duration: 4000
  238. });
  239. that[obj[that.tabObj.current]]();
  240. },
  241. {
  242. timeout: 15000
  243. }
  244. );
  245. } else {
  246. that.loading = false;
  247. that.$refs.uToast.show({
  248. title: '当前系统不支持GPS API',
  249. type: 'error',
  250. duration: 4000
  251. });
  252. that[obj[that.tabObj.current]]();
  253. }
  254. },
  255. /**
  256. * 导航
  257. * @date 2021-08-10
  258. * @param {Number} latitude
  259. * @param {Number} longitude
  260. * @returns {any}
  261. */
  262. navigation(latitude, longitude, areaName) {
  263. this.currentPositionHover = {
  264. latitude,
  265. longitude,
  266. areaName
  267. };
  268. this.mapSelect = true;
  269. },
  270. disabledNavigation() {
  271. this.$refs.uToast.show({
  272. title: '您已拒绝授权位置信息或者获取位置信息失败,无法使用导航功能!',
  273. type: 'error'
  274. });
  275. },
  276. // 多地图选择
  277. mapSelectConfirm(item) {
  278. const name = item[0].label;
  279. switch (name) {
  280. case '腾讯地图':
  281. location.href = `https://apis.map.qq.com/uri/v1/routeplan?type=drive&from=我的位置&fromcoord=${this.currentPosition.latitude},${this.currentPosition.longitude}&to=${this.currentPositionHover.areaName}&tocoord=${this.currentPositionHover.latitude},${this.currentPositionHover.longitude}&policy=1&referer=BOGBZ-2BZ33-O4L32-Y3QJR-PGN66-RFFEL`;
  282. break;
  283. case '百度地图':
  284. const lnglatObj = qqMapTransBMap(this.currentPositionHover.longitude, this.currentPositionHover.latitude);
  285. location.href = `http://api.map.baidu.com/marker?location=
  286. ${lnglatObj.lat},${lnglatObj.lng}&title=目的地&content=${this.currentPositionHover.areaName}
  287. &output=html&src=webapp.baidu.openAPIdemo`;
  288. break;
  289. case '高德地图':
  290. location.href = `https://uri.amap.com/navigation?from=${this.currentPosition.longitude},${this.currentPosition.latitude},我的位置&to=${this.currentPositionHover.longitude},${this.currentPositionHover.latitude},${this.currentPositionHover.areaName}&mode=car&policy=1&src=mypage&coordinate=gaode&callnative=0`;
  291. break;
  292. }
  293. },
  294. /**
  295. * 清空搜索框内容
  296. * @date 2021-08-10
  297. * @returns {any}
  298. */
  299. clearSearchInput() {
  300. this.searchContent = '';
  301. this.isShowSearchParking = false;
  302. const obj = {
  303. 0: 'getNearRoadsl',
  304. 1: 'getParkingLotList'
  305. };
  306. this[obj[this.tabObj.current]]();
  307. },
  308. /**
  309. * 默认首个点放大 如果有传入经纬度则对应的点放大
  310. * @date 2021-08-10
  311. * @param {Number} lon
  312. * @param {Number} lat
  313. * @returns {any}
  314. */
  315. getNearRoadsl(lon, lat) {
  316. this.$u.api
  317. .nearRoadsl({
  318. latitude: this.currentPosition.latitude || undefined,
  319. longitude: this.currentPosition.longitude || undefined,
  320. roadName: this.searchContent || undefined
  321. })
  322. .then((res) => {
  323. const nearParkingList = []; // 附近停车场列表
  324. this.covers = [];
  325. res.data.forEach((item, index, arr) => {
  326. if (item.latitude && item.longitude) {
  327. nearParkingList.push(item);
  328. const marker = {
  329. latitude: item.latitude,
  330. longitude: item.longitude,
  331. id: String(index),
  332. iconPath: require('./../../static/img/parking-icon.png'),
  333. width: 20,
  334. height: 25
  335. };
  336. // 选中经纬度图标变大
  337. if (lon && lat) {
  338. if (lon === item.longitude && lat === item.latitude) {
  339. marker.width = 40;
  340. marker.height = 50;
  341. }
  342. } else {
  343. if (this.covers.length > 0) {
  344. this.covers[0].width = 40;
  345. this.covers[0].height = 50;
  346. }
  347. }
  348. this.covers.push(marker);
  349. }
  350. });
  351. this.nearParkingList = nearParkingList;
  352. // if (nearParkingList.length > 0) {
  353. // this.latitude = nearParkingList[0]?.latitude || this.currentPosition.latitude;
  354. // this.longitude = nearParkingList[0]?.longitude || this.currentPosition.longitude;
  355. // }
  356. this.nearParkingFlag = true;
  357. if (this.searchContent) {
  358. this.searchParkingList = nearParkingList;
  359. this.isShowSearchParking = true;
  360. this.nearParkingFlag = false;
  361. }
  362. })
  363. .catch((err) => {
  364. this.$refs.uToast.show({
  365. title: err.msg,
  366. type: 'error'
  367. });
  368. });
  369. },
  370. getParkingLotList(lon, lat) {
  371. this.$u.api
  372. .nearParkingLot({
  373. status: 1,
  374. latitude: this.currentPosition.latitude || undefined,
  375. longitude: this.currentPosition.longitude || undefined,
  376. parkName: this.searchContent || undefined
  377. })
  378. .then((res) => {
  379. const nearParkingList = []; // 附近停车场列表
  380. this.covers = [];
  381. res?.data?.rows.forEach((item, index, arr) => {
  382. if (item.latitude && item.longitude) {
  383. nearParkingList.push(item);
  384. const marker = {
  385. latitude: item.latitude,
  386. longitude: item.longitude,
  387. id: String(index),
  388. iconPath: require('./../../static/img/parking-icon.png'),
  389. width: 20,
  390. height: 25
  391. };
  392. // 选中经纬度图标变大
  393. if (lon && lat) {
  394. if (lon === item.longitude && lat === item.latitude) {
  395. marker.width = 40;
  396. marker.height = 50;
  397. }
  398. } else {
  399. if (this.covers.length > 0) {
  400. this.covers[0].width = 40;
  401. this.covers[0].height = 50;
  402. }
  403. }
  404. this.covers.push(marker);
  405. }
  406. });
  407. this.nearParkingList = nearParkingList;
  408. // if (nearParkingList.length > 0) {
  409. // this.latitude = nearParkingList[0]?.latitude || this.currentPosition.latitude;
  410. // this.longitude = nearParkingList[0]?.longitude || this.currentPosition.longitude;
  411. // }
  412. this.nearParkingFlag = true;
  413. if (this.searchContent) {
  414. this.searchParkingList = nearParkingList;
  415. this.isShowSearchParking = true;
  416. this.nearParkingFlag = false;
  417. }
  418. })
  419. .catch((err) => {
  420. this.$refs.uToast.show({
  421. title: err.msg,
  422. type: 'error'
  423. });
  424. });
  425. },
  426. /**
  427. * 点击地图上的标记点触发
  428. **/
  429. markertap(e) {
  430. let lon, lat;
  431. this.covers.forEach((item, index) => {
  432. if (e.detail.markerId === item.id) {
  433. lon = item.longitude;
  434. lat = item.latitude;
  435. this.swiperCurrent = index;
  436. }
  437. });
  438. const obj = {
  439. 0: 'getNearRoadsl',
  440. 1: 'getParkingLotList'
  441. };
  442. this[obj[this.tabObj.current]](lon, lat);
  443. },
  444. /**
  445. * 地址发生变化
  446. * @date 2021-08-10
  447. * @param {Object} item
  448. * @returns {any}
  449. */
  450. swiperChange(item) {
  451. const map = uni.createMapContext('pagemap');
  452. map.moveToLocation({
  453. longitude: this.nearParkingList[item.detail.current].longitude,
  454. latitude: this.nearParkingList[item.detail.current].latitude
  455. });
  456. const obj = {
  457. 0: 'getNearRoadsl',
  458. 1: 'getParkingLotList'
  459. };
  460. this[obj[this.tabObj.current]](this.nearParkingList[item.detail.current].longitude, this.nearParkingList[item.detail.current].latitude);
  461. },
  462. /**
  463. * 点击单个地址
  464. * @date 2022-08-31
  465. * @param {any} item
  466. * @returns {any}
  467. */
  468. positionAddress(item) {
  469. const map = uni.createMapContext('pagemap');
  470. map.moveToLocation({
  471. longitude: item.longitude,
  472. latitude: item.latitude
  473. });
  474. const obj = {
  475. 0: 'getNearRoadsl',
  476. 1: 'getParkingLotList'
  477. };
  478. this[obj[this.tabObj.current]](item.longitude, item.latitude);
  479. },
  480. /**
  481. * 点击单个停车场看详情
  482. * @date 2021-08-10
  483. * @param {Object} item 为选中项参数
  484. * @returns {any}
  485. */
  486. clickSearchParking(item) {
  487. if (item.monthAmount) {
  488. this.$u.route({
  489. url: 'pages/parkingInformation/parkingInformation',
  490. params: {
  491. longitude: this.currentPosition.longitude,
  492. latitude: this.currentPosition.latitude,
  493. id: item.id,
  494. current: this.tabObj.current
  495. }
  496. });
  497. }
  498. },
  499. /**
  500. * 跳转停车标准页面
  501. * @date 2021-08-10
  502. * @param {Object} item
  503. * @returns {any}
  504. */
  505. lookParkingRule(item) {
  506. const obj = {
  507. 0: 'roadNo',
  508. 1: 'parkNo'
  509. };
  510. const params = {};
  511. params[obj[this.tabObj.current]] = item[obj[this.tabObj.current]];
  512. this.$u.route({
  513. url: 'pages/chargeStandard/chargeStandard',
  514. params
  515. });
  516. },
  517. /**
  518. * 搜索右侧按钮点击
  519. **/
  520. listIconClick() {
  521. this.isShowSearchParking = true;
  522. this.nearParkingFlag = false;
  523. this.searchParkingList = this.nearParkingList;
  524. },
  525. /**
  526. * 跳转包月
  527. * @date 2021-08-10
  528. * @param {Object} item
  529. * @returns {any}
  530. */
  531. createMonth(item) {
  532. const obj = {
  533. 0: 'roadNo',
  534. 1: 'parkNo'
  535. };
  536. const params = {};
  537. params[obj[this.tabObj.current]] = item[obj[this.tabObj.current]];
  538. this.$u.route({
  539. url: 'pages/handleMonthly/handleMonthly',
  540. params
  541. });
  542. },
  543. pullDown() {
  544. if (this.nearParkingObj.height === '20vh') {
  545. this.nearParkingObj.height = '60vh';
  546. this.nearParkingObj.type = 'down';
  547. } else {
  548. this.nearParkingObj.height = '20vh';
  549. this.nearParkingObj.type = 'up';
  550. }
  551. },
  552. /**
  553. * tab切换触发
  554. * @param {Object} val
  555. */
  556. tabChange(val) {
  557. this.tabObj.current = val;
  558. const obj = {
  559. 0: 'getNearRoadsl',
  560. 1: 'getParkingLotList'
  561. };
  562. this[obj[val]]();
  563. }
  564. }
  565. };
  566. </script>
  567. <style lang="scss" scoped>
  568. .wrap {
  569. margin-top: 20vh;
  570. }
  571. @import './parkingLists.scss';
  572. </style>