index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. <template>
  2. <ax-body hide-indicator-area :style="[StyleSheet]">
  3. <!-- 标题栏 -->
  4. <template #title>
  5. <view class="titlebar">
  6. <image src="@/static/img/title.png" class="page-title"></image>
  7. <!-- <text class="page-subtitle">“特惠充电享不停”</text> -->
  8. </view>
  9. </template>
  10. <view class="base">
  11. <!-- 搜索块 -->
  12. <view id="search" class="app-flex search-view">
  13. <view class="locate-city">
  14. <image src="@/static/img/locate.svg" class="_icon"></image>
  15. <text class="__name">{{city.data[city.index].text}}</text>
  16. </view>
  17. <label class="search-bar" @click="$app.url.goto('/pages/search/search')">
  18. <input placeholder-class="app-placeholder" placeholder="输入目的地/电站名" />
  19. <image src="@/static/img/search.svg" class="_icon-search"></image>
  20. </label>
  21. </view>
  22. </view>
  23. <view class="arrears-tips" v-if="payment_msg!=null">
  24. <view class="arrears-left">
  25. <image class="arrears-icon" src="@/static/img/arrears-icon.svg" mode=""></image>
  26. <view class="arrears-text">您有一笔超充订单{{(payment_msg.maspAmount+payment_msg.maspRealAmount).toFixed(2)}}元待补缴</view>
  27. </view>
  28. <view class="arrears-btn" @click="topage_coupon">去补缴</view>
  29. </view>
  30. <!-- 主滚动 -->
  31. <view class="main-scroll-wrap">
  32. <scroll-view class="root-scroll app-hide-scrollbar" @scrolltolower="scrollLock=true" @scrolltoupper="scrollLock=false" scroll-y>
  33. <view class="contet-root">
  34. <!-- 内容顶部 -->
  35. <view id="roller" class="base">
  36. <!-- 快捷栏 -->
  37. <view class="shortcut-bar">
  38. <view class="_item" @click="$app.url.goto('/pages/order/order')">
  39. <image src="@/static/img/shortcut1.png" class="_icon"></image>
  40. <view class="_name">订单中心</view>
  41. </view>
  42. <view class="_item" @click="$app.url.goto('/pages/coupon-buy/coupon-buy')">
  43. <image src="@/static/img/shortcut2.png" class="_icon"></image>
  44. <view class="_name">购充电券</view>
  45. </view>
  46. <view class="_item" @click="customerService()">
  47. <image src="@/static/img/shortcut3.png" class="_icon"></image>
  48. <view class="_name">在线客服</view>
  49. </view>
  50. <view class="_item" @click="$app.url.goto('/pages/feedback/feedback')">
  51. <image src="@/static/img/shortcut4.png" class="_icon"></image>
  52. <view class="_name">意见反馈</view>
  53. </view>
  54. </view>
  55. <!-- 版头广告 -->
  56. <swiper class="banner" v-if="banners.length>0" autoplay="true" >
  57. <swiper-item v-for="(item,index) in banners" :key="index" @click="$app.url.goto(item.jumpPage)">
  58. <view class="swiper-item">
  59. <image @load="bannerLoadCompleted()" :src="showImg(item.pic)" class="swiper-item-image" mode="widthFix"></image>
  60. </view>
  61. </swiper-item>
  62. </swiper>
  63. </view>
  64. <view id="fixed" class="base">
  65. <!-- 选项条 -->
  66. <view class="app-flex options-bar">
  67. <view class="app-flex middle option-wrap">
  68. <view v-for="(item,index) in sorts.data" :key="index" @click="changeSort(index)"
  69. class="option-item" :class="{active:sorts.index==index}">{{item.name}}</view>
  70. </view>
  71. <view class="app-flex c-center separ"></view>
  72. <view @click="$app.url.goto('/pages/map/map',false)" class="app-flex middle map-mode">
  73. <image src="@/static/img/map.svg" class="_icon"></image>
  74. <text>地图模式</text>
  75. </view>
  76. </view>
  77. </view>
  78. <!-- 电站列表 -->
  79. <view id="list-box" class="list-scroll-wrap">
  80. <scroll-view class="list-scroll" :scroll-y="scrollLock">
  81. <view class="list">
  82. <view v-for="(item,index) in list.data" :key="index" @click="gotoSiteDetail(item)" class="item">
  83. <view class="contet">
  84. <view class="name">
  85. <view class="icon"><image src="@/static/img/plug.svg" mode="widthFix"></image></view>
  86. <view class="txt">{{item.name}}</view>
  87. </view>
  88. <view class="parkade">
  89. <view class="icon"><image src="@/static/img/parkade.svg" mode="widthFix"></image></view>
  90. <!-- <view class="txt"><rich-text :nodes="item.parkTips"></rich-text></view> -->
  91. <view class="txt">充电减免2小时停车费,超出时长部分计时收费</view>
  92. </view>
  93. <view class="app-flex c-between info">
  94. <view class="app-flex middle">
  95. <view class="charge"><text class="icon">快</text><text class="value">{{item.params.emptyFast}}</text><text class="max">{{item.params.totalFast}}</text></view>
  96. <view class="charge"><text class="icon blue">慢</text><text class="value">{{item.params.emptySlow}}</text><text class="max">{{item.params.totalSlow}}</text></view>
  97. </view>
  98. <view class="discount" v-if="discountInfo">
  99. <view>
  100. {{discountInfo.temp2}}
  101. </view>
  102. </view>
  103. <view class="distance">
  104. <view class="icon"><image src="@/static/img/distance.svg" mode="widthFix"></image></view>
  105. <text>{{item.params.rangeShow}}</text>
  106. </view>
  107. </view>
  108. </view>
  109. <view class="price">
  110. <!-- v-if="user_info.firmId===null" -->
  111. <view class="app-flex middle" style="color: #FF5D50;" v-if="user_info.firmType===0||user_info.firmId===null||user_info===null">
  112. <text class="value">{{item.params.nowPrice?item.params.nowPrice.toFixed(4):"0.0000"}}</text>
  113. <text class="unit">元/度</text>
  114. </view>
  115. <view class="app-flex middle" v-else>
  116. <view class="card-bottom-text">
  117. <text>{{item.params.firmPrice.toFixed(4)}}</text>
  118. <text class="mini-text">元/度</text>
  119. </view>
  120. <view class="operation-price-btn">
  121. 企业专享价
  122. </view>
  123. <view class="ordinary-price">{{item.params.nowPrice?item.params.nowPrice.toFixed(4):"0.0000"}}</view>
  124. </view>
  125. <view>{{item.params.priceShow}}</view>
  126. </view>
  127. </view>
  128. </view>
  129. </scroll-view>
  130. </view>
  131. <!-- <view style="height: 158px;"></view> -->
  132. </view>
  133. </scroll-view>
  134. </view>
  135. <ax-popup ref="filter" position="" maskType="black" maskEnable maskClose>
  136. <view class="ad-popup">
  137. <view class="close-get" @click="closeAd">X</view>
  138. <swiper class="ad-swiper" :autoplay="true" :interval="3000" :duration="1000">
  139. <swiper-item class="ad-swiper-item" v-for="(item,index) in adBanner" :key="index">
  140. <image class="ad-image" :src="showImg(item.picture)" @click="goImgLink(item)" mode="widthFix"></image>
  141. </swiper-item>
  142. </swiper>
  143. </view>
  144. </ax-popup>
  145. <app-navigation id="app-navigation" active="home"></app-navigation>
  146. </ax-body>
  147. </template>
  148. <script>
  149. var bmap = require('static/js/bmap-wx.js');
  150. export default {
  151. async onLoad(options) {
  152. const permit = await this.queryPermit();
  153. if(permit.privacy){
  154. // 没有通过隐私协议
  155. this.privacy.visible = true;
  156. }else{
  157. // 已通过隐私协议
  158. if(permit.location===true){
  159. // 可以调用定位能力
  160. this.updateLocation();
  161. }else if(permit.location===false){
  162. // 通过了隐私协议,但是定位被拒绝
  163. this.location.visible = true;
  164. this.updateLocation();
  165. }else if(permit.location===undefined){
  166. // 没有申请过定位能力
  167. this.updateLocation();
  168. }
  169. }
  170. if (options.hasOwnProperty('q') && options.q) {
  171. // 通过下面这步解码,可以拿到url的值
  172. const url = decodeURIComponent(options.q)
  173. // 对url中携带的参数提取处理
  174. console.log("url:"+url)
  175. var device_no = this.getQueryParams(url,"connectorCode")
  176. console.log("device_no:"+device_no)
  177. if(device_no){
  178. this.getDeviceInfo(device_no)
  179. }
  180. }
  181. if(this.closeAdvertising){
  182. this.getAdswiper()
  183. }
  184. // this.user_info=this.$app.storage.get('USER_INFO')
  185. },
  186. mounted() {
  187. if(this.adBanner.length>0&&!this.$app.storage.get('AD_STATUS')){
  188. this.$refs.filter.open();
  189. }
  190. this.setListHeight();
  191. this.setAppNavigationHeight();
  192. this.get_frimid()
  193. this.get_userinfo()
  194. this.get_paymentMsg()
  195. this.getBanners()
  196. },
  197. data() {
  198. return {
  199. payment_msg:null,
  200. user_info:{},
  201. // 导航栏高度
  202. appNavigationHeight: 0,
  203. // 页面滚动锁
  204. scrollLock: true,
  205. sorts:{
  206. index: 0,
  207. data: [{name:'离我最近',code:"range"},{name:'空闲最多',code:"device"},{name:'电费最低',code:"price"}]
  208. },
  209. list:{
  210. height: 0,
  211. data: []
  212. },
  213. banners:[],
  214. adBanner:[],
  215. location:{
  216. visible: false,
  217. value: '',
  218. },
  219. privacy:{
  220. visible: false,
  221. },
  222. city:{
  223. index: 0,
  224. data:[
  225. {text:'贵阳',areaCode:"5201"},
  226. {text:'六盘水',areaCode:"5202"},
  227. {text:'遵义',areaCode:"5203"},
  228. {text:'安顺',areaCode:"5204"},
  229. {text:'毕节',areaCode:"5205"},
  230. {text:'铜仁',areaCode:"5206"},
  231. {text:'黔东南',areaCode:"5226"},
  232. {text:'黔南',areaCode:"5227"},
  233. {text:'黔西南',areaCode:"5223"},
  234. ]
  235. },
  236. discountInfo:null,
  237. closeAdvertising:false
  238. }
  239. },
  240. onShow() {
  241. this.getAdswiper()
  242. },
  243. onHide() {
  244. this.$app.storage.remove('AD_STATUS')
  245. },
  246. computed:{
  247. StyleSheet(){
  248. return {
  249. '--app-navigation-heiht': `${this.appNavigationHeight}px`,
  250. '--list-heiht': `${this.list.height}px`
  251. }
  252. }
  253. },
  254. onShareAppMessage(res) {
  255. if (res.from === 'button') {
  256. // 来自页面内分享按钮
  257. console.log(res.target);
  258. }
  259. return {
  260. title: "用券充天天都享会员价", // 标题
  261. path: "/pages/index/index", // 分享路径
  262. imageUrl: '../../static/img/share.jpg', // 分享图
  263. desc: '用券充天天都享会员价'
  264. };
  265. },
  266. onShareTimeline() {
  267. return {
  268. title: "用券充天天都享会员价", // 标题
  269. path: "/pages/index/index", // 分享路径
  270. imageUrl: '../../static/img/share.jpg'// 分享图
  271. };
  272. },
  273. methods: {
  274. closeAd(){
  275. this.closeAdvertising=true
  276. this.$refs.filter.close()
  277. this.$app.storage.set('AD_STATUS',this.closeAdvertising);
  278. },
  279. get_userinfo(){
  280. this.$api.base("post", "/userApi/getUserAccount", {}, {error:false}).then(res => {
  281. this.user_info = res.accountInfo
  282. this.$app.storage.set('USER_INFO', res.accountInfo);
  283. })
  284. },
  285. // 企业用户扫码进入
  286. get_frimid(){
  287. if(this.$app.storage.get('FRIM_ID')){
  288. if(this.$app.storage.get('USER_TOKEN')){
  289. this.$api.base("post","/userApi/add-firm-user?firmId="+parseInt(this.$app.storage.get('FRIM_ID')),{},{error: false}).then(res=>{
  290. this.get_userinfo()
  291. setTimeout(()=>{
  292. this.$app.storage.remove('FRIM_ID')
  293. },500)
  294. this.$app.popup.alert(res.msg);
  295. }).catch(err=>{
  296. setTimeout(()=>{
  297. this.$app.storage.remove('FRIM_ID')
  298. },500)
  299. // this.$app.popup.alert(err.msg)
  300. })
  301. }else{
  302. uni.showModal({
  303. title:'未登录',
  304. content:'你还未进行登录,请去登录',
  305. showCancel:false,
  306. success:function(res) {
  307. if(res.confirm){
  308. uni.navigateTo({
  309. url:'/pages/login/login'
  310. })
  311. }
  312. }
  313. })
  314. }
  315. }
  316. },
  317. getDeviceInfo(sn){
  318. this.$api.base("post","/chargeApi/checkDevicesBySn",{"sn":sn},{}).then(res=>{
  319. var item = res.device;
  320. //设备状态 0:离网1:空闲2:占用(未充电)3:占用(充电中)4:占用(预约锁定)255:故障
  321. if(item.deviceStatus == 0 || item.deviceStatus == 255 ){
  322. return;
  323. }
  324. this.$app.url.goto('/pages/terminal/terminal?deviceId='+item.id+"&deviceStatus="+item.deviceStatus);
  325. })
  326. },
  327. getQueryParams(url,key) {
  328. const queryString = url.split('?')[1] || '';
  329. const params = {};
  330. const pairs = queryString.split('&');
  331. pairs.forEach(pair => {
  332. const [key, value] = pair.split('=');
  333. params[decodeURIComponent(key)] = decodeURIComponent(value || '');
  334. });
  335. return params[key];
  336. },
  337. showImg(img){
  338. return this.$config.url.request+img
  339. },
  340. goImgLink(e){
  341. this.$app.url.goto(e.skipUrl);
  342. },
  343. // 打开客服
  344. customerService(){
  345. const cs = this.$config.customerService;
  346. this.$app.act.customerService(cs.id,cs.url).catch(err=>{
  347. console.log(err);
  348. this.$app.popup.alert('客服中心失联啦,请联系管理员!');
  349. });
  350. },
  351. // 查询许可
  352. queryPermit(){
  353. return new Promise((resolve,reject)=>{
  354. const data = {};
  355. const check = ()=>{
  356. if( Object.keys(data).length == 2 ) resolve(data);
  357. }
  358. if(uni.getPrivacySetting){
  359. uni.getPrivacySetting({
  360. success: res => {
  361. data.privacy = res.needAuthorization;
  362. },
  363. complete: () => {
  364. if(typeof data.privacy !='boolean' && typeof data.privacy !='undefined') data.privacy = null;
  365. check();
  366. },
  367. });
  368. }else{
  369. data.privacy = false;
  370. }
  371. uni.getSetting({
  372. success: res => {
  373. data.location = uni.getLocation ? res.authSetting['scope.userLocation'] : undefined;
  374. },
  375. complete: () => {
  376. if(typeof data.location !='boolean' && typeof data.location !='undefined') data.location = null;
  377. check();
  378. },
  379. })
  380. });
  381. },
  382. // 更新位置
  383. updateLocation(){
  384. this.getLocation().then(res=>{
  385. this.location.value = [res.longitude,res.latitude].join(',');
  386. this.getStations(res.longitude,res.latitude)
  387. this.$app.storage.set('USER_LOCATION',this.location.value);
  388. return this.reverseGeocoder([res.latitude,res.longitude].join(','))
  389. });
  390. },
  391. // 获取定位
  392. getLocation(){
  393. return new Promise((resolve,reject)=>{
  394. // this.loading.visible = true;
  395. if(uni.getLocation){
  396. uni.getLocation({
  397. success: res => resolve(res),
  398. fail: err => {
  399. console.log(err)
  400. console.log('定位失败');
  401. // this.location.visible = true;
  402. this.getStations("","")
  403. },
  404. complete: () => {
  405. }
  406. })
  407. }else{
  408. console.log('微信版本太低,无定位接口可用');
  409. resolve({longitude:'',latitude:''});
  410. }
  411. });
  412. },
  413. reverseGeocoder(latlon){
  414. console.log(latlon)
  415. let lat = latlon.split(",")[0]
  416. let lng = latlon.split(",")[1]
  417. let baiduLoc = this.convertGcj02ToBd09(lng,lat)
  418. latlon = baiduLoc.lat+","+baiduLoc.lng
  419. console.log(latlon)
  420. return new Promise((resolve,reject)=>{
  421. var BMap = new bmap.BMapWX({
  422. ak: 'vtQgaPzonb3H4qeUOWGr53ePcNCsmdMj'
  423. });
  424. BMap.regeocoding({
  425. location:latlon,
  426. success:res=>{
  427. let code = res.originalData.result.addressComponent.adcode.substr(0,4)
  428. for (var i = 0; i < this.city.data.length; i++) {
  429. if(this.city.data[i].areaCode==code){
  430. this.city.index = i
  431. break;
  432. }
  433. }
  434. console.log(res)
  435. },
  436. fail:err=>{
  437. console.log(err)
  438. }
  439. })
  440. });
  441. },
  442. get_paymentMsg(){
  443. // maspStatus(1:待补缴,2:已补缴)realPredictServiceCost平台;maspAmount第三方
  444. this.$api.base("post","/chargeApi/queryOrderList-arrearage",{},{}).then(res=>{
  445. this.payment_msg=res.data
  446. })
  447. },
  448. getBanners(){
  449. this.$api.base("post","/userApi/getBanners",{},{}).then(res=>{
  450. this.banners = res.banners
  451. })
  452. },
  453. getAdswiper(){
  454. this.$api.base("post","/userApi/getAdvertising",{},{}).then(res=>{
  455. this.adBanner = res.banners
  456. })
  457. },
  458. convertBdToTx(lng, lat) {
  459. // 百度坐标系(BD09)转火星坐标系(GCJ-02,即腾讯地图使用的坐标系)
  460. // 这里的转换公式是基于经验公式,可能存在一定的误差
  461. let x_pi = 3.14159265358979324 * 3000.0 / 180.0;
  462. let x = lng - 0.0065;
  463. let y = lat - 0.006;
  464. let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
  465. let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
  466. let lngs = z * Math.cos(theta);
  467. let lats = z * Math.sin(theta);
  468. return { lng: lngs, lat: lats };
  469. },
  470. getStations(lng,lat){
  471. this.$api.base("post","/chargeApi/getStations",{order:this.sorts.index,lat,lng},{}).then(res=>{
  472. res.stationList.forEach(i=>{
  473. var txPoint = this.convertBdToTx(i.lng,i.lat)
  474. i.lng = txPoint.lng
  475. i.lat = txPoint.lat
  476. })
  477. this.list.data = res.stationList
  478. if(res.discountInfo){
  479. this.discountInfo = res.discountInfo
  480. }
  481. })
  482. },
  483. // 设定导航栏高度
  484. setAppNavigationHeight(){
  485. this.$nextTick(()=>{
  486. uni.createSelectorQuery().in(this).select("#app-navigation").boundingClientRect(data=>{
  487. this.appNavigationHeight = data.height;
  488. }).exec();
  489. });
  490. },
  491. // 设置列表高度
  492. setListHeight(){
  493. this.$app.act.selectorQuery(this,"#list-box,#roller",true).then(res=>{
  494. const win = uni.getWindowInfo();
  495. const roller = res.find(i=>i.id=='roller');
  496. const list = res.find(i=>i.id=='list-box');
  497. this.list.height = win.windowHeight - list.top - this.appNavigationHeight + roller.height;
  498. });
  499. },
  500. // 版头加载完成
  501. bannerLoadCompleted(){
  502. this.setListHeight();
  503. },
  504. changeSort(index){
  505. this.sorts.index = index;
  506. switch(index){
  507. case 0:
  508. this.list.data.sort((a,b)=>a.params.range-b.params.range)
  509. break;
  510. case 1:
  511. this.list.data.sort((a,b)=>b.params.totalEmpty-a.params.totalEmpty)
  512. break;
  513. case 2:
  514. this.list.data.sort((a,b)=>a.params.nowPrice-b.params.nowPrice)
  515. break;
  516. }
  517. },
  518. scrolltolower(){
  519. console.log('到底')
  520. },
  521. gotoSiteDetail(item){
  522. this.$app.url.goto('/pages/site/site?item='+JSON.stringify(item));
  523. },
  524. topage_coupon(){
  525. let payment=this.payment_msg.realPredictServiceCost+this.payment_msg.maspAmount
  526. this.$app.url.goto('/pages/coupon-buy/coupon-buy?payment='+payment)
  527. },
  528. // 确认隐私协议
  529. agreePrivacyAuthorization(){
  530. this.privacy.visible = false;
  531. this.updateLocation();
  532. },
  533. // 打开隐私协议
  534. openPrivacyContract(){
  535. uni.openPrivacyContract();
  536. },
  537. // 拒绝隐私协议
  538. refusePrivacy(){
  539. this.privacy.visible = false;
  540. },
  541. convertGcj02ToBd09(lng, lat) {
  542. const x_pi = 3.14159265358979324 * 3000.0 / 180.0;
  543. const z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_pi);
  544. const theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_pi);
  545. const bd_lng = z * Math.cos(theta) + 0.0065;
  546. const bd_lat = z * Math.sin(theta) + 0.006;
  547. return {
  548. lng: bd_lng,
  549. lat: bd_lat
  550. };
  551. }
  552. }
  553. }
  554. </script>
  555. <style>
  556. @import url('index.css');
  557. .discount{
  558. flex: 1;
  559. text-align: right;
  560. padding-right: 5px;
  561. }
  562. .discount view{
  563. display: inline-flex;
  564. align-items: center;
  565. height: 22px;
  566. border: 1px solid #ccc;
  567. border-radius: 5px;
  568. font-size: 12px;
  569. color: #F59C79;
  570. padding: 0 7px;
  571. overflow: hidden;
  572. }
  573. </style>