stationList.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. <template>
  2. <view class="wrapper">
  3. <u-select v-model="selectCityVisible" :list="cityList" @confirm="citySelectConfirm"></u-select>
  4. <view
  5. class="top-wrapper"
  6. :style="{backgroundColor:theme === 'dark'?'#222336':'#fff',boxShadow:theme === 'dark'?'0px 0px 1px 1px rgba(161, 161, 161, 0.25)':'0px 0px 1px 1px rgba(232, 232, 232, 0.5)'}"
  7. >
  8. <view class="action-bar" >
  9. <view class="button city" @click="selectCityVisible = true">{{ selectedCity.city || selectedCity.nation }}</view>
  10. </view>
  11. </view>
  12. <view class="bottom-wrapper" @touchmove.stop.prevent="moveHandle">
  13. <view class="action-bar">
  14. <view class="button scan" @click="scan()">
  15. <img class="list_img" src="/static/map/scan.png" alt />扫码充电
  16. </view>
  17. <view class="right">
  18. <!-- <view class="button" @click="showChargingOrder()" v-if="showChargingBtn">
  19. <img class="list_img" src="/static/index/electric.png" alt />
  20. </view>-->
  21. <view class="floatBtn" v-if="showChargingBtn">
  22. <FloatBtn :connectorId="connectorId"></FloatBtn>
  23. </view>
  24. </view>
  25. </view>
  26. </view>
  27. <!-- 列表 -->
  28. <scroll-view scroll-y class="list">
  29. <view v-for="(station, cindex) in stationList" :key="cindex" class="stationCard" @click="handleClick(station)">
  30. <view class="title">
  31. <view class="name">{{ station.info.stationName }}</view>
  32. <view class="tag">
  33. <img src="/static/map/location.png" alt />
  34. {{station.userDistance + 'km'}}
  35. </view>
  36. <view class="tag nearest" v-if="station.nearest">最近</view>
  37. </view>
  38. <view class="address">
  39. {{
  40. station.info.address
  41. }}
  42. </view>
  43. <view class="tags">
  44. <view
  45. v-for="(t, index) in station.tagList"
  46. :key="index"
  47. class="tag"
  48. style="margin: 10rpx 10rpx 0 0"
  49. >{{t.tagName}}</view>
  50. </view>
  51. <view class="bottom">
  52. <view class="left coupon-tag" style='position: relative;'>
  53. <text class="price">{{ station.currentPrice }}</text>
  54. <text class="unit">元/度</text>
  55. </view>
  56. <view class="right">
  57. <view class="label fast" v-if="station.totalFastGun>0">空闲 {{ station.freeFastGun }}/{{ station.totalFastGun }}</view>
  58. <view class="label slow" v-if="station.totalGun - station.totalFastGun>0">
  59. 空闲
  60. {{ station.freeGun - station.freeFastGun }}/{{
  61. station.totalGun -
  62. station.totalFastGun
  63. }}
  64. </view>
  65. </view>
  66. </view>
  67. </view>
  68. <u-empty v-if="stationList.length == 0" text=" " margin-top="100"></u-empty>
  69. <view style="height:160rpx;text-align:center;padding-top:10rpx;"></view>
  70. </scroll-view>
  71. </view>
  72. </template>
  73. <script>
  74. import config from '@/config/config'
  75. import * as API_Station from "@/api/station";
  76. import { wxGeocoder } from "@/api/common";
  77. import FloatBtn from "@/components/float-btn/float-btn";
  78. import { mpScan } from "@/utils/tools.js";
  79. import { getOrderList } from "@/api/order";
  80. // const citySelector = requirePlugin('citySelector');
  81. export default {
  82. components: {
  83. FloatBtn
  84. },
  85. onHide() {
  86. this.isHide = true;
  87. },
  88. data() {
  89. return {
  90. config,
  91. cityList: [
  92. {
  93. label: "上海市",
  94. value: { latitude: 31.230525, longitude: 121.473667 },
  95. },
  96. {
  97. label: "北京市",
  98. value: { latitude: 39.905023, longitude: 116.384502 },
  99. },
  100. ],
  101. selectCityVisible: false,
  102. selectedCity: { city: "", nation: "" },
  103. background: {
  104. backgroundColor: "transparent",
  105. },
  106. id: 0, // 使用 marker点击事件 需要填写id
  107. title: 'map',
  108. mapLayerStyle: 1,
  109. mapStartLocation: {
  110. lat: 39.909,
  111. lon: 116.39742,
  112. },
  113. mapCenterLocation: {
  114. lat: 39.909,
  115. lon: 116.39742,
  116. },
  117. userLocation: {},
  118. stationList: [],
  119. currentPosition: {},
  120. showCurrent: true,
  121. lightColor: this.$lightColor,
  122. // 站点栏右侧滑动按钮
  123. options: [{
  124. text: "删除",
  125. style: {
  126. backgroundColor: this.$lightColor, //高亮颜色
  127. },
  128. },],
  129. isInvalid(val) {
  130. //是否无效站点/没库存站点
  131. if (val.invalid == 1 || (!val.checked && val.errorMessage)) {
  132. return true;
  133. } else {
  134. return false;
  135. }
  136. },
  137. orderParams: {
  138. pageNum: 1,
  139. pageSize: 10,
  140. isOnlyCharing: 1,
  141. },
  142. connectorId: null,
  143. showChargingBtn: false,
  144. isHide: false,
  145. theme: "",
  146. scrollTop: 0, // 列表的滚动位置
  147. topWrapperBackground: 'red', // top-wrapper的背景色
  148. };
  149. },
  150. async onLoad() {
  151. this.userLocation = this.mapStartLocation
  152. },
  153. // 从城市选择器插件返回后,在页面的onShow生命周期函数中能够调用插件接口,获取cityInfo结果对象
  154. onShow() {
  155. this.updateChargingBtn()
  156. this.isHide = false;
  157. this.shouldGetCenterLanLat = false;
  158. this.getCenterLanLat()
  159. // this.getStationList();
  160. if(uni.getSystemInfoSync().platform == 'devtools'){
  161. this.getStationList();
  162. }
  163. },
  164. // onUnload() {
  165. // // 页面卸载时清空插件数据,防止再次进入页面,getCity返回的是上次的结果
  166. // citySelector.clearCity();
  167. // },
  168. onReady() {
  169. // 检查深浅模式,确定地图样式
  170. let _this = this
  171. uni.getSystemInfo({
  172. success: function (res) {
  173. console.log("getSystemInfo:", res)
  174. _this.theme = res.hostTheme || 'light'
  175. _this.mapLayerStyle = _this.theme === 'dark' ? 2 : 1
  176. }
  177. });
  178. },
  179. mounted() {
  180. // #ifdef MP-WEIXIN
  181. uni.showShareMenu({
  182. withShareTicket: true
  183. });
  184. // #endif
  185. },
  186. methods: {
  187. /**
  188. * 获取站点数据
  189. */
  190. async getStationList() {
  191. let _this = this
  192. uni.showLoading({
  193. title: "加载中",
  194. });
  195. let userLocation = {
  196. userLat: this.userLocation.lat,
  197. userLon: this.userLocation.lon
  198. }
  199. let query = Object.assign({}, userLocation, this.mapCenterLocation, { isDetail: 1 })
  200. //处理搜索半径
  201. if(query.keywd == null || query.keywd == ''){
  202. delete query.keywd
  203. query.radius = 100
  204. }else{
  205. //关键字不为空时,半径为零
  206. query.radius = 0
  207. }
  208. let response = await API_Station.getStations(query);
  209. if (response && response.data && response.data.code === 200) {
  210. uni.stopPullDownRefresh();
  211. _this.stationList = response.data.data;
  212. // 计算站点与用户位置的距离
  213. _this.calUserDistance()
  214. _this.stationList.forEach((station, index) => {
  215. // 将站点放入marker数组
  216. let labelContent = `¥${station.currentPrice}\n`
  217. labelContent += station.totalFastGun > 0 ? `快${station.freeFastGun}/${station.totalFastGun} ` : ' '
  218. labelContent += (station.totalGun - station.totalFastGun) > 0 ? `慢${station.freeGun - station.freeFastGun}/${station.totalGun - station.totalFastGun}` : ''
  219. station.latitude = Number(Number(station.lat).toFixed(5));
  220. station.longitude = Number(Number(station.lon).toFixed(5));
  221. station.labelContent = labelContent;
  222. })
  223. }
  224. uni.hideLoading();
  225. },
  226. onListScroll(e) {
  227. this.scrollTop = e.detail.scrollTop; // 更新滚动位置
  228. if (this.scrollTop > 100) {
  229. this.topWrapperBackground = '#ffffff'; // 当滚动位置超过100时,修改top-wrapper的背景为红色
  230. } else {
  231. this.topWrapperBackground = 'transparent'; // 否则将top-wrapper的背景设置为透明
  232. }
  233. },
  234. moveHandle() { },
  235. calUserDistance() {
  236. this.stationList.forEach((p, i) => {
  237. const lon = Number(p.lon)
  238. const lat = Number(p.lat)
  239. // this.$set(p, 'userDistance', Number(p.userDistance).toFixed(2))
  240. let userDistance = Math.round(this.$options.filters.calcDistance(this.userLocation.lon, this.userLocation.lat, lon, lat) / 100) / 10;
  241. this.$set(p, 'userDistance', userDistance)
  242. })
  243. // 按用户距离排序
  244. this.$options.filters.arraySort(this.stationList, 'userDistance')
  245. // 将第一个地点标为最近
  246. if (this.stationList.length > 0) {
  247. this.stationList[0].nearest = true
  248. }
  249. },
  250. // 获取用户当前位置
  251. getUserLocation() {
  252. let _this = this
  253. uni.getLocation({
  254. type: 'gcj02', // 默认为 wgs84 返回 gps 坐标,gcj02 返回可用于 wx.openLocation 的坐标
  255. success: (res) => {
  256. //赋值经纬度
  257. _this.$set(_this.userLocation, 'lat', parseFloat(res.latitude))
  258. _this.$set(_this.userLocation, 'lon', parseFloat(res.longitude))
  259. _this.calUserDistance()
  260. _this.mapStartLocation = Object.assign(_this.userLocation, {})
  261. },
  262. fail: function (res) {
  263. console.log(res)
  264. },
  265. })
  266. },
  267. async getCenterLanLat() {
  268. let _this = this
  269. uni.getLocation({
  270. success: function(res) {
  271. const lat = parseFloat(res.latitude)
  272. const lon = parseFloat(res.longitude)
  273. _this.userLocation.lat = lat
  274. _this.userLocation.lon = lon
  275. _this.mapCenterLocation.lat = lat
  276. _this.mapCenterLocation.lon = lon
  277. // 逆解析获取当前城市
  278. wxGeocoder(`${lat},${lon}`).then(res => {
  279. if (res.data.result) {
  280. _this.selectedCity = res.data.result.address_component
  281. }
  282. })
  283. _this.getStationList()
  284. },
  285. fail: function(res) {
  286. console.log(res)
  287. }
  288. })
  289. },
  290. handleClick(item) {
  291. if (item.stationStatus == 50) {
  292. uni.navigateTo({
  293. url: `/pages/station/index?id=${item.stationId}&d=${item.distance}`,
  294. });
  295. } else {
  296. uni.showToast({
  297. title: "站点未开放",
  298. duration: 2000,
  299. icon: "none",
  300. });
  301. }
  302. },
  303. /**
  304. * 跳转
  305. */
  306. navigateTo(url) {
  307. uni.navigateTo({
  308. url,
  309. });
  310. },
  311. scan() {
  312. mpScan()
  313. },
  314. citySelectConfirm(e) {
  315. let _this = this
  316. let location = e[0].value;
  317. let cityName = e[0].label;
  318. this.$set(this.mapCenterLocation, 'lat', location.latitude)
  319. this.$set(this.mapCenterLocation, 'lon', location.longitude)
  320. this.selectedCity = {city: cityName}
  321. this.getStationList()
  322. },
  323. async updateChargingBtn() {
  324. let res = await getOrderList(this.orderParams);
  325. if (res && res.data.code == 200 && res.data.rows.length > 0) {
  326. this.showChargingBtn = true;
  327. let rows = res.data.rows;
  328. this.connectorId = rows[0].connectorId;
  329. } else {
  330. this.showChargingBtn = false;
  331. this.connectorId = null;
  332. }
  333. },
  334. },
  335. };
  336. </script>
  337. <style scoped lang="scss">
  338. @import "./stationList.scss";
  339. </style>
  340. <style lang="scss">
  341. page {
  342. background-color: #f7f7f7;
  343. }
  344. /* DarkMode 下的样式 start */
  345. @media (prefers-color-scheme: dark) {
  346. page {
  347. background-color: #121425;
  348. }
  349. }
  350. </style>