海南旅游项目 前端仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

480 lines
14 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. <template>
  2. <view>
  3. <view class="lf-p-t-20 head" v-if="tab_list_father.length">
  4. <u-tabs :list="tab_list_father" :is-scroll="true" :current="current_father" @change="tabChangeFather()"></u-tabs>
  5. </view>
  6. <view>
  7. <map class="lf-map-height" :longitude="self_longitude" :latitude="self_latitude" :markers="markers_list" :scale="4" @markertap="markertap" @callouttap="callouttap">
  8. </map>
  9. </view>
  10. <view class="lf-m-t-40 lf-p-l-32 lf-p-r-32">
  11. <view class="lf-row-between lf-m-b-40">
  12. <view class="lf-font-32 lf-color-222">商品列表</view>
  13. <view class="lf-font-24 lf-color-blue lf-row-center" style="width: 520rpx; justify-content: flex-end;" v-if="self_latitude && self_longitude && address">
  14. <text class="lf-iconfont lf-icon-dingwei lf-m-r-10 lf-font-22"></text>
  15. <text class="lf-line-1">{{ address }}</text>
  16. </view>
  17. <view class="lf-font-24 lf-color-blue lf-row-center" @click="getShopDistance()" v-else>
  18. <text class="lf-iconfont lf-icon-dingwei lf-m-r-10 lf-font-22"></text>
  19. 我的位置
  20. </view>
  21. </view>
  22. <view class="special_tab" style="position: relative;">
  23. <u-tabs :list="tab_list" active-color="#1998FE" inactive-color='#777777' :is-scroll="true" @click="clicksort" :current="current" @change="tabChange"></u-tabs>
  24. <view style="position: absolute;right: 44rpx;top: 20rpx;display: flex;flex-direction: column;">
  25. <u-icon name="arrow-up" style="font-size: 20rpx;" :class="(current == 2 && sort == 0) ? 'lf-color-blue' : ''"></u-icon>
  26. <u-icon name="arrow-down" style="font-size: 20rpx;" :class="(current == 2 && sort == 1) ? 'lf-color-blue' : ''"></u-icon>
  27. </view>
  28. </view>
  29. <swiper :style="{height: 'calc('+ windowHeight +'px - 110rpx)', width: '100%'}" :current="current" @change="swiperChange">
  30. <swiper-item v-for="(tabItem, tabIndex) in tab_list" :key="tabIndex">
  31. <scroll-view class="com" :scroll-y="true" :refresher-enabled="true" :refresher-triggered="tabItem.isRefresher" @scrolltolower="onScrolltolower" @refresherrefresh="onRefresherrefresh">
  32. <view class="lf-m-t-20"></view>
  33. <view>
  34. <!-- 活动列表 -->
  35. <view class="content">
  36. <view class="item" v-for="(item,index) of tabItem.list" :key="index">
  37. <!-- <view class="cover">
  38. <image :src="item.picture" class="lf-w-100 lf-h-100" mode="aspectFill"></image>
  39. </view>
  40. <view style="width: 420rpx;">
  41. <view class="lf-font-28 lf-color-333 lf-line-2">{{item.title}}</view>
  42. <view class="lf-font-24 lf-color-gray lf-line-2 lf-m-t-10" style="min-height: 64rpx;">本套票只包含两个成人不可带小孩本套票只包含两个成人不可带小孩本套票只包含两个成人不可带小孩</view>
  43. <view class="lf-flex lf-m-t-25">
  44. <lf-price :price="item.price"></lf-price>
  45. <text class="lf-font-24 lf-color-gray lf-line-through lf-m-l-15">¥{{item.original_price}}</text>
  46. </view>
  47. </view> -->
  48. <view class="lf-row-between lf-m-t-40">
  49. <view class="lf-row-between" @click="$url('/pages/goodsDetail/index?goods_id='+item.id);">
  50. <view class="lf-m-r-20">
  51. <image style="width: 90rpx;height: 90rpx;border-radius: 10rpx;" :src="item.picture" mode="aspectFill"></image>
  52. </view>
  53. <view class="lf-flex-column">
  54. <view class="lf-font-28 lf-color-222 lf-line-1" style="width: 576rpx;">{{item.title}}</view>
  55. <view style="width: 100%; display: flex; justify-content: space-between; align-items: flex-end;">
  56. <view class="lf-font-24 lf-color-999 lf-flex lf-m-t-18" style="width: 440rpx;">
  57. <view>
  58. <text class="lf-iconfont lf-icon-dingwei1" style="font-size: 10px!important;"></text>
  59. </view>
  60. <view class="lf-line-2 lf-m-l-10" style="max-width: 440rpx;">
  61. <block v-if="item.address">
  62. <text>{{ item.address }}</text>
  63. <text class="lf-m-l-10 lf-m-r-10">|</text>
  64. </block>
  65. <text>{{item.distance_m | kmUnit}}</text>
  66. </view>
  67. </view>
  68. <view style="width: 134rpx;">
  69. <view @click="openMap(item.address,item.latitude,item.logitude)" style="display: flex; justify-content: flex-end;">
  70. <text class="lf-iconfont lf-icon-daohang"></text>
  71. </view>
  72. <view class="lf-font-24 lf-color-price lf-text-right">{{ item.price }}</view>
  73. </view>
  74. </view>
  75. </view>
  76. </view>
  77. </view>
  78. </view>
  79. </view>
  80. <!-- 加载 -->
  81. <view class="loading-more">
  82. <text v-if="tabItem.list.length" :class="{'loading-more-text': loadingClass}">{{ loadingText }}</text>
  83. <lf-nocontent v-else></lf-nocontent>
  84. </view>
  85. </view>
  86. </scroll-view>
  87. </swiper-item>
  88. </swiper>
  89. <!-- 回到顶部 -->
  90. <u-back-top :scroll-top="pageScrollTop" :custom-style="{background: 'rgba(51, 51 51, 0.3)'}"></u-back-top>
  91. </view>
  92. </view>
  93. </template>ß
  94. <script>
  95. let QQMapWX = require('@/common/qqmap-wx-jssdk.min.js');
  96. let qqmapsdk = new QQMapWX({
  97. key: 'GB3BZ-7W2CU-LW3VH-B7ZIF-XRKSF-D3FOL'
  98. });
  99. export default {
  100. data() {
  101. return {
  102. tab_list_father: [],
  103. current_father: 0,
  104. windowHeight: 0,
  105. markers_list: [],
  106. self_latitude: '',
  107. self_longitude: '',
  108. //排序
  109. tab_list: [
  110. {
  111. id: 1,
  112. name: '销量',
  113. list: [],
  114. isRefresher: false,
  115. loadingClass: true,
  116. loadingText: '正在加载中',
  117. page: 1,
  118. isPage: true,
  119. type: 1
  120. },
  121. {
  122. id: 2,
  123. name: '距离',
  124. list: [],
  125. isRefresher: false,
  126. loadingClass: true,
  127. loadingText: '正在加载中',
  128. page: 1,
  129. isPage: true,
  130. type: 4
  131. },
  132. {
  133. id: 4,
  134. name: '价格',
  135. list: [],
  136. isRefresher: false,
  137. loadingClass: true,
  138. loadingText: '正在加载中',
  139. page: 1,
  140. isPage: true,
  141. type: 3
  142. },
  143. ],
  144. current: 0,
  145. loadingClass: false,
  146. loadingText: '已加载全部数据~',
  147. page: 1,
  148. isPage: true,
  149. pageSize: 20,
  150. sort: 0,
  151. address: '',
  152. downloadImages: [] // 已下载过的图片缓存
  153. }
  154. },
  155. onLoad() {
  156. this.windowHeight = getApp().globalData.windowHeight;
  157. this.getShopDistance().then(() => {
  158. this.getCategory();
  159. }).catch(() => {
  160. uni.showModal({
  161. title: '',
  162. content: '获取位置失败!',
  163. showCancel: false
  164. })
  165. })
  166. // 腾讯地图KEY: GB3BZ-7W2CU-LW3VH-B7ZIF-XRKSF-D3FOL
  167. },
  168. filters: {
  169. kmUnit(m){
  170. var v;
  171. if(typeof m === 'number' && !isNaN(m)){
  172. if (m >= 1000) {
  173. v = (m / 1000).toFixed(2) + 'km'
  174. } else {
  175. v = m + 'm'
  176. }
  177. }else{
  178. v = '0m'
  179. }
  180. return v;
  181. }
  182. },
  183. methods: {
  184. // 点击标记时触发
  185. markertap(e){
  186. let id = e.detail.markerId;
  187. this.$url('/pages/goodsDetail/index?goods_id='+ id);
  188. },
  189. // 点击marker对应的气泡时触发
  190. callouttap(e){
  191. let id = e.detail.markerId;
  192. this.$url('/pages/goodsDetail/index?goods_id='+ id);
  193. },
  194. // 打开地图
  195. openMap(address, lat, lng) {
  196. // let { address, lat, lng } = this.goods_detail?.store || {};
  197. uni.openLocation({
  198. longitude: Number(lng),
  199. latitude: Number(lat),
  200. scale: 20,
  201. name: address
  202. });
  203. },
  204. //获取当前位置 计算商店距离
  205. getShopDistance() {
  206. let that = this;
  207. return new Promise((resolve, reject) => {
  208. uni.showLoading({
  209. title: '正在获取您的位置'
  210. })
  211. uni.getLocation({
  212. type: 'gcj02',
  213. isHighAccuracy: true,
  214. success (res) {
  215. uni.hideLoading();
  216. that.self_latitude = res.latitude;
  217. that.self_longitude = res.longitude;
  218. that.getAddressInfo();
  219. resolve();
  220. },
  221. fail(err) {
  222. console.log(err)
  223. uni.hideLoading();
  224. reject();
  225. }
  226. })
  227. })
  228. },
  229. // 根据坐标获取地址信息
  230. getAddressInfo(){
  231. qqmapsdk.reverseGeocoder({
  232. location: {
  233. latitude: this.self_latitude,
  234. longitude: this.self_longitude
  235. },
  236. success: res => {
  237. this.address = res.result.address;
  238. },
  239. fail: err => {
  240. console.log("调用失败!", err);
  241. }
  242. })
  243. },
  244. tabChangeFather(index){
  245. this.current_father = index;
  246. this.clearTabItem()
  247. if(this.tab_list_father[index].list.length <= 0){
  248. this.getActivityList(); // tab下没有数据,请求第一页
  249. }
  250. },
  251. clearTabItem(){
  252. let tab_item = this.tab_list[this.current];
  253. tab_item.page = 1;
  254. tab_item.isPage = true;
  255. tab_item.isRefresher = true;
  256. tab_item.loadingClass = true;
  257. tab_item.loadingText = '正在加载中';
  258. tab_item.list = [];
  259. this.markers_list = [];
  260. },
  261. getCategory(options = {}) {
  262. this.$http(this.API.API_CATEGORYLIST).then(res => {
  263. let res_list = res.data || [];
  264. let tab_list_father = res_list.map(item => {
  265. return {
  266. id: item.id,
  267. name: item.name,
  268. list: [],
  269. isRefresher: false,
  270. loadingClass: true,
  271. loadingText: '正在加载中',
  272. page: 1,
  273. isPage: true,
  274. pid: item.pid
  275. }
  276. });
  277. let list = []
  278. tab_list_father.forEach((item,index) => {
  279. if(item.pid == 0) {
  280. list.push(item)
  281. }
  282. })
  283. this.tab_list_father = list;
  284. this.getActivityList()
  285. }).catch(err => {
  286. })
  287. },
  288. clicksort(index) {
  289. if(index == 2) {
  290. if(this.sort == 0) {
  291. this.sort = 1
  292. }else {
  293. this.sort = 0
  294. }
  295. this.getActivityList()
  296. }else {
  297. return
  298. }
  299. },
  300. tabChange(index){
  301. this.current = index;
  302. this.getActivityList()
  303. },
  304. // 滑块下标值变化
  305. swiperChange(event){
  306. this.current = event.detail.current;
  307. if(event.detail.source == '') return; // 如果是被动出发,没有事件类型则不做处理
  308. },
  309. changeSort(sort) {
  310. this.sort != this.sort
  311. this.getActivityList()
  312. },
  313. // scroll-view 下拉刷新
  314. onRefresherrefresh(){
  315. this.tab_list[this.current].isRefresher = true;
  316. this.$u.throttle(() => {
  317. this.clearTabItem();
  318. this.getActivityList();
  319. }, 200);
  320. },
  321. // 页面触底,加载下一页
  322. onScrolltolower(){
  323. let tab_item = this.tab_list[this.current];
  324. if(tab_item.isPage){
  325. tab_item.page = tab_item.page + 1;
  326. this.getActivityList();
  327. }
  328. },
  329. getActivityList(){
  330. let tab_item1 = this.tab_list_father[this.current_father];
  331. let tab_item = this.tab_list[this.current];
  332. let sort_type = this.tab_list[this.current].type;
  333. console.log('页数',tab_item.id)
  334. if(this.$shared.isValueType(tab_item) == 'undefined') return;
  335. this.$http(this.API.API_ADVICELIST, {
  336. lat: this.self_latitude,
  337. lng: this.self_longitude,
  338. page: tab_item.page,
  339. category_id: tab_item1.id,
  340. type: sort_type,
  341. by: this.sort,
  342. }).then(res => {
  343. let isPage = res.data.next_page_url == null?false:true;
  344. tab_item.isPage = isPage;
  345. if(!isPage){
  346. tab_item.loadingClass = false;
  347. tab_item.loadingText = '没有更多数据啦~';
  348. }
  349. this.tab_list[this.current].isRefresher = false;
  350. if(tab_item.page == 1){
  351. tab_item.list = res.data.data;
  352. }else{
  353. tab_item.list.push(...res.data.data);
  354. }
  355. console.log("res", res);
  356. // let res_list = res.data.data || [];
  357. this.createMarkers(tab_item.list);
  358. }).catch(err => {
  359. })
  360. },
  361. // 将iconPath下载到本地,然后生成markers渲染出来
  362. createMarkers(res_list){
  363. let markers_self = [];
  364. let p_list = []; // 异步队列
  365. // let downloadImages = JSON.parse(JSON.stringify(this.downloadImages)); // PS: 已下载过的图片缓存,如果需要显示market图片时打开这行注释!!!!
  366. uni.showLoading({
  367. title: '加载地图信息中'
  368. })
  369. res_list.map(item => {
  370. let itemP = new Promise((resolve, reject) => {
  371. let tempFilePath = '../../static/market_icon.png';
  372. let obj = {
  373. id: item.id,
  374. name: item.title,
  375. address: item.address,
  376. latitude: Number(item.latitude),
  377. longitude: Number(item.longitude),
  378. iconPath: tempFilePath,
  379. width: 30,
  380. height: 30,
  381. callout: {
  382. content: item.title,
  383. fontSize: 14,
  384. textAlign: 'center',
  385. bgColor: "#fff",
  386. borderRadius: 14,
  387. padding: 4,
  388. display: "ALWAYS"
  389. }
  390. };
  391. /* PSmarket
  392. let image = downloadImages.filter(function(f_item, f_index, f_arr){
  393. return f_item.id == item.id;
  394. });
  395. if(image.length > 0){
  396. // 找到缓存匹配项
  397. tempFilePath = image[0].url;
  398. obj.iconPath = image[0].url;
  399. markers_self.push(obj);
  400. resolve();
  401. }else{
  402. // 未放入缓存,将执行download
  403. uni.downloadFile({
  404. url: item.picture,
  405. complete: result => {
  406. if (result.statusCode === 200) {
  407. tempFilePath = result.tempFilePath;
  408. }
  409. obj.iconPath = tempFilePath;
  410. markers_self.push(obj);
  411. downloadImages.push({
  412. id: item.id,
  413. url: tempFilePath
  414. });
  415. resolve();
  416. }
  417. })
  418. }
  419. */
  420. markers_self.push(obj);
  421. resolve(); // PS: 如果需要打开注释代码时,请将这两行代码删除!!!!
  422. });
  423. p_list.push(itemP);
  424. });
  425. Promise.all(p_list).then(res => {
  426. // this.downloadImages = JSON.parse(JSON.stringify(downloadImages)); // PS: 如果需要显示market图片时打开这行注释!!!!
  427. this.markers_list = markers_self;
  428. uni.hideLoading();
  429. })
  430. }
  431. }
  432. }
  433. </script>
  434. <style lang="scss" scoped>
  435. .com{
  436. width: 100%;
  437. height: 100%;
  438. box-sizing: border-box;
  439. // padding: 0rpx 28rpx;
  440. }
  441. .lf-map-height {
  442. width: 100%;
  443. height: 500rpx;
  444. }
  445. /deep/.special_tab .u-scroll-box {
  446. display: flex;
  447. justify-content: center;
  448. align-items: center;
  449. border-bottom: 1rpx solid rgba(0, 0, 0, 0.1);
  450. }
  451. /deep/.special_tab .u-scroll-box .u-tab-bar {
  452. background-color: #1998FE!important;
  453. width: 80rpx!important;
  454. position: absolute;
  455. left: 0;
  456. bottom: -12rpx;
  457. }
  458. /deep/.special_tab .u-tabs .u-scroll-box .u-tab-bar {
  459. background-color: #1998FE!important;
  460. width: 56rpx!important;
  461. position: absolute;
  462. height: 5rpx!important;
  463. left: 8rpx;
  464. bottom: -4rpx;
  465. }
  466. /deep/.special_tab .u-tab-item {
  467. font-size: 28rpx!important;
  468. }
  469. </style>