zhwl-miniapp/pages/tabbar/guide.vue
2025-06-26 12:38:35 +08:00

711 lines
21 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="waper">
<u-navbar left-icon-size="0" :placeholder="true" bgColor="#fff">
<view slot='center' class="navbar_title">导览</view>
</u-navbar>
<view class="tabs-box" v-if="!showSwiper">
<scroll-view scroll-x="true">
<view class="tab" :class="{active: activeType === item.id}" v-for="(item, index) in typeList" :key="index" @click="getMarkers(item.id)">{{item.potypeName}}</view>
</scroll-view>
</view>
<map id="map" :style="'height: calc(100% - ' + windowBottom + 'px)'"
:enable-building="enableBuilding" :show-location="showLocation" :latitude="latitude"
:longitude="longitude" :markers="markers" :scale="scale" :max-scale="14.5" @markertap="markertap" @labeltap="labeltap" :polyline="polyline"></map>
<view class="btn-box" :style="'bottom: ' + windowBottom2 + 'px'">
<view class="location" @click="changeLocation">
<image class="icon" src="https://common/location.png" mode=""></image>
</view>
<view class="location" @click="closeLine" v-if="showLine || showSwiper">
<image class="icon" src="https://common/out.png" mode=""></image>
</view>
</view>
<view class="line_btn" v-if="showBtn" @click="getGuideList" :style="'bottom: ' + windowBottom3 + 'px'">
<image class="img" src="https://common/lineBtn.png" mode=""></image>
<view>游览</view>
<view>线路</view>
</view>
<view class="line_swiper" v-if="showLine" :style="'bottom: ' + windowBottom1 + 'px'">
<swiper :interval="5000" :duration="1000" previous-margin="32rpx" next-margin="32rpx" :current="current1" @change="swiperChange1">
<swiper-item v-for="(i, index) in lineList" :key="index">
<view class="line_box">
<view class="line_waper">
<view class="title">{{i.name}}</view>
<view class="msg">预计游览{{i.duration}}小时</view>
<view class="tag">
<view>难度{{i.difficultyName}}</view>
</view>
<view class="btn" @click="startLine(i)">
<view>开始</view>
<view>游览</view>
</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
<!-- -->
<view class="detail_swiper" v-if="showSwiper" :style="'bottom: ' + windowBottom1 + 'px'">
<swiper :interval="5000" :duration="1000" previous-margin="32rpx" next-margin="32rpx" :current="current2" @change="swiperChange2">
<swiper-item v-for="(i, index) in lineInfo" :key="index" :class="[current2 == index ? 'activeClass' : 'defaultClass']" @click="goSpot(i)">
<view class="detail_box">
<view class="detail_waper">
<view class="num">{{index+1}}</view>
<view class="con-box">
<view class="title">
<view class="label">{{i.pointName}}</view>
<!-- <view class="voice">
<image class="icon" src="https://common/voice.png" mode=""></image>
<view class="time">2:30</view>
</view> -->
</view>
<view class="text">{{i.blurb}}</view>
</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
<view v-if="popup1" class="popup-box">
<view class="popup-content1">
<view class="head-box" v-if="data1.ticketId">
<view class="name">
<view class="h4">{{data1.ticketName}}</view>
<view class="price">
¥{{data1.salesRice}}
<text>起</text>
</view>
</view>
<view class="go" @click="buyTicket(data1.ticketId)">
去购买
<u-icon name="arrow-right" color="#666666" size="28rpx"></u-icon>
</view>
</view>
<view class="con">
<image class="con-img" :src="$utils.setImgUrl(data1.image)" mode=""></image>
<view class="con-right">
<view class="title">{{data1.pointName}}</view>
<view class="describe">{{data1.blurb}}</view>
</view>
</view>
<view class="btn">
<image class="btn-img" src="https://common/go.png" mode=""></image>
<view class="label" @click="goLocation(data1)">去这里</view>
</view>
</view>
</view>
<tabbar name="guide"></tabbar>
</view>
</template>
<script>
import tabbar from '@/components/tabbar/index.vue'
import _config from '../../common/http/config.js'
export default {
components: {
tabbar
},
data() {
return {
windowBottom: 0,
windowBottom1: 0,
windowBottom2: 0,
windowBottom3: 0,
popup1: false,
mapCtx: null,
showLine: false,
showSwiper: false,
showBtn: true,
current1: 0,
current2: 0,
// 路线集合
lineList: [],
// 路线点集合
lineInfo: null,
id: 0,
bgColor: 'transparent',
scale: null,
enableBuilding: false,
showLocation: true,
latitude: null,
longitude: null,
polyline: [],
markers: [],
// tab类型集合
typeList: [],
showPointList: [],
// 所有数据
allData: {},
// 选中tab类型id、数据点类型id
activeType: '',
markerId: '',
// 数据点id
spotId: '',
// 当前tab类型点图标
pathIcon: '',
// 弹窗数据
data1: {},
// 是否点击查看所有路线
isAllLine: false,
};
},
onLoad() {
this.windowBottom = this.$safeAreaBottom + 50 + this.$paddingTop + uni.upx2px(72);
this.windowBottom1 = this.$safeAreaBottom + uni.upx2px(134);
this.windowBottom2 = this.$safeAreaBottom + uni.upx2px(340);
this.windowBottom3 = this.$safeAreaBottom + uni.upx2px(140);
this.mapCtx = uni.createMapContext('map', this);
this.pointMapList()
},
onReady() {},
onShow() {},
methods: {
async pointMapList() {
let info = await this.$http.pointMapList({mapId: 1})
if (info.code === 200) {
this.allData = info.data
this.typeList = this.allData.pointTypeList
this.activeType = this.typeList[0].id
this.latitude = this.allData.centerLatitude
this.longitude = this.allData.centerLongitude
this.scale = this.allData.zoomLevel
this.addImageLayer(this.allData);
this.getMarkers(this.activeType)
} else {
uni.$u.toast(info.msg);
}
},
addImageLayer(data) {
const imageLayerOptions = {
id: data.id,
src: _config.url + data.image,
zIndex: 1,
bounds: {
southwest: {
longitude: data.leftLongitude,
latitude: data.leftLatitude
},
northeast: {
longitude: data.rightLongitude,
latitude: data.rightLatitude
}
}
};
this.mapCtx.addGroundOverlay(imageLayerOptions);
},
getMarkers(id) {
this.activeType = id
this.popup1 = false;
this.showLine = false;
this.showSwiper = false;
this.showBtn = true;
this.getMarkersList()
},
getMarkersList() {
this.polyline = [];
this.markers = []
let index = null
this.typeList.forEach((n, i) => {
if (n.id == this.activeType) {
index = i
this.showPointList = this.typeList[index]
this.pathIcon = this.showPointList.image
}
})
if (!this.showPointList.pointDataList) return;
this.showPointList.pointDataList.forEach((e, i) => {
this.markers.push({
id: e.id,
latitude: e.latitude,
longitude: e.longitude,
width: '90rpx',
height: '90rpx',
iconPath: _config.url + this.pathIcon,
label: {
padding: '10rpx',
content: e.pointName,
color: '#fff',
fontSize: '24rpx',
anchorX: '0',
anchorY: '0',
borderRadius: '4rpx',
bgColor: 'rgba(0,0,0,0.5)',
textAlign: 'center'
}
})
})
},
labeltap (e) {
this.markerId = e.markerId
this.showDetail(this.markerId)
},
markertap(e) {
this.markerId = e.markerId
this.showDetail(this.markerId)
},
showDetail(id) {
if (!this.showLine && !this.showSwiper) {
this.showBtn = false;
this.isAllLine = false;
this.current1 = 0;
this.getGuide(id)
let f = this.showPointList.pointDataList.find(m => m.id == id)
if (f) {
this.data1 = f
this.popup1 = true
}
}
},
buyTicket(id) {
uni.navigateTo({ url: '/pages/scenic/ticket?id=' + id })
},
goLocation(data) {
let latitude = data.latitude;
let longitude = data.longitude;
uni.openLocation({
latitude: Number(latitude),
longitude: Number(longitude),
name: data.pointName,
address: '',
})
},
getGuide(id) {
this.spotId = id;
this.guideList()
},
async guideList() {
let info = await this.$http.guideLineList({spotId: this.spotId})
if (info.code === 200) {
this.showLine = true
this.lineList = info.data
} else {
uni.$u.toast(info.msg);
}
},
async startLine (i) {
let info = await this.$http.guideDetail({id: i.id})
if (info.code === 200) {
this.windowBottom = this.$safeAreaBottom + 50 + this.$paddingTop;
this.showLine = false
this.showSwiper = true
this.popup1 = false
this.current2 = 0
this.lineInfo = info.data.spotGuideList;
if (!this.lineInfo) {
return false;
}
this.polyline = [];
this.getLine(info.data.coordinate);
let markers = [];
let numArr = ['①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩']
this.lineInfo.forEach((e, i) => {
markers.push({
id: e.id,
latitude: e.latitude,
longitude: e.longitude,
width: '90rpx',
height: '90rpx',
iconPath: _config.url + e.image,
title: i,
label: {
padding: '10rpx',
content: numArr[i] + ' ' + e.pointName,
color: '#fff',
fontSize: '24rpx',
anchorX: '0',
anchorY: '0',
borderRadius: '4rpx',
bgColor: 'rgba(0,0,0,0.5)',
textAlign: 'center'
},
callout: {
bgColor: 'transparent'
}
})
})
this.markers = markers;
} else {
uni.$u.toast(info.msg);
}
},
getLine (line) {
let array = JSON.parse(line);
if (!array) return false;
this.polyline = ([
{ points: array, color: '#EFE7A7', width: 8, dottedLine: false },
{ points: array, color: '#743F00', width: 2, dottedLine: true }
]);
},
async getGuideList () {
this.showBtn = false;
this.isAllLine = true;
this.current1 = 0;
this.getGuide('')
},
closeLine () {
this.popup1 = false;
if (this.showLine) {
this.showLine = false;
this.showBtn = true;
} else if (this.showSwiper) {
this.windowBottom = this.$safeAreaBottom + 50 + this.$paddingTop + uni.upx2px(72);
this.showLine = true;
this.showBtn = false;
this.guideList()
if (!this.isAllLine) this.popup1 = true;
}
this.showSwiper = false;
this.getMarkersList()
},
changeLocation() {
let mapObjs = uni.createMapContext('map', this)
mapObjs.moveToLocation({
complete: res => {
console.log('移动完成:', res)
}
})
},
swiperChange1(e) {
this.current1 = e.detail.current
},
swiperChange2(e) {
this.current2 = e.detail.current
},
goSpot(i) {
if (!i.spotId) return;
uni.navigateTo({ url: '/pages/scenic/spot?id=' + i.spotId })
}
}
}
</script>
<style lang="scss" scoped>
.line_btn{
width: 180rpx;
height: 180rpx;
position: relative;
color: #fff;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 32rpx;
line-height: 46rpx;
position: fixed;
left: 50%;
transform: translateX(-50%);
.img {
position: absolute;
left: 0;
top: 0;
z-index: -1;
}
}
.line_swiper{
width: 100%; height: 188rpx; position: fixed; left: 0;
swiper{ width: 100%; height: 100%; }
.line_box{ width: 100%; height: 100%; box-sizing: border-box; padding: 0 12rpx; }
.line_waper{
width: 100%; height: 100%; background: #fff; border-radius: 10rpx; box-sizing: border-box; padding: 24rpx 24rpx 0; position: relative; padding-right: 148rpx;
.title{ line-height: 46rpx; color: #333; font-size: 32rpx; font-weight: 500; }
.msg{ line-height: 34rpx; margin-top: 12rpx; color: #999; width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 24rpx; }
.tag{
width: 100%; margin-top: 12rpx; display: flex; align-items: center;
view{
height: 32rpx; box-sizing: border-box; border: 2rpx solid #03AE80; border-radius: 2rpx; padding: 0 8rpx; line-height: 28rpx; color: #03AE80; font-size: 20rpx;
}
}
.btn{ width: 120rpx; height: 120rpx; background: #03AE80; display: flex; flex-direction: column; justify-content: center; align-items: center; color: #FCFCFC; font-size: 24rpx; line-height: 30rpx; border-radius: 50%; position: absolute; right: 24rpx; top: 50%; transform: translateY(-50%); }
}
}
.detail_swiper {
width: 100%; height: 204rpx; position: fixed; left: 0;
swiper{ width: 100%; }
.activeClass {
height: 204rpx !important;
box-sizing: border-box;
.detail_waper {
padding: 24rpx 32rpx;
}
}
.defaultClass {
height: 188rpx !important;
margin-top: 16rpx;
box-sizing: border-box;
.detail_waper {
padding: 16rpx 32rpx;
}
}
.detail_box{ width: 100%; height: 100%; box-sizing: border-box; padding: 0 12rpx; }
.detail_waper{
width: 100%; height: 100%; background: #fff; border-radius: 10rpx; box-sizing: border-box;
display: flex;
flex-direction: row;
justify-content: space-between;
.num {
width: 34rpx;
height: 34rpx;
background: #03AE80;
border-radius: 50%;
border: 2rpx solid #FFFFFF;
font-weight: 500;
font-size: 20rpx;
color: #FFFFFF;
line-height: 34rpx;
text-align: center;
margin-right: 12rpx;
}
.con-box {
flex: 1;
.title {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
.label {
font-weight: 500;
font-size: 32rpx;
color: #333333;
}
.voice {
display: flex;
align-items: center;
.icon {
width: 32rpx;
height: 32rpx;
margin-right: 10rpx;
}
.time {
font-size: 24rpx;
color: #333333;
}
}
}
.text {
margin-top: 8rpx;
font-weight: 400;
font-size: 24rpx;
color: #999999;
line-height: 36rpx;
width: 528rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
}
}
}
.waper {
width: 100%;
height: 100vh;
background: #F4F6FA;
#map{ width: 100%; }
.tabs-box {
padding: 5rpx 0 11rpx;
background: #FFFFFF;
scroll-view{ width: 100%; white-space: nowrap; font-size: 0;}
.tab {
display: inline-block;
vertical-align: top;
height: 56rpx;
line-height: 56rpx;
padding: 0 38rpx;
background: #FFFFFF;
border-radius: 42rpx 42rpx 42rpx 42rpx;
font-size: 28rpx;
color: #000000;
&:first-child {
margin-left: 32rpx;
}
&:last-child {
margin-right: 32rpx;
}
}
.active {
background: #03AE80;
font-weight: 500;
font-size: 28rpx;
color: #FFFFFF;
}
}
// .map-box {
// width: 100%;
// height: 100%;
// position: fixed;
// left: 0;
// top: 0;
// .customCallout {
// display: flex;
// justify-content: center;
// align-items: center;
// box-sizing: border-box;
// padding: 8rpx 46rpx;
// background: #00BE69;
// border-radius: 30rpx;
// .txt {
// font-weight: 500;
// font-size: 28rpx;
// color: #FFFFFF;
// }
// .triangle {
// width: 0;
// height: 0;
// border-left: 10rpx solid transparent;
// /* 左边的透明部分 */
// border-right: 10rpx solid transparent;
// /* 右边的透明部分 */
// border-top: 14rpx solid #00BE69;
// /* 底部红色线条 */
// position: absolute;
// bottom: -13rpx;
// }
// }
// }
.btn-box {
position: fixed;
right: 18rpx;
z-index: 1;
.location {
width: 80rpx;
height: 80rpx;
border-radius: 10rpx;
background-color: #fff;
position: relative;
margin-top: 40rpx;
.icon {
width: 50rpx;
height: 50rpx;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
}
.head-box {
display: flex;
align-items: center;
flex-direction: row;
justify-content: space-between;
padding-bottom: 24rpx;
border-bottom: 1rpx solid #E8E8E8;
.name {
display: flex;
align-items: center;
flex-direction: row;
.h4 {
font-size: 32rpx;
color: #333333;
}
.price {
margin-left: 24rpx;
font-size: 32rpx;
color: #FF3333;
text {
font-size: 24rpx;
color: #333333;
}
}
}
.go {
display: flex;
align-items: center;
flex-direction: row;
font-size: 26rpx;
color: #666666;
}
}
.popup-box {
width: 638rpx;
height: 300rpx;
position: fixed;
left: 50%;
top: 400rpx;
transform: translateX(-50%);
}
.popup-content1 {
background: #FFFFFF;
border-radius: 10rpx;
padding: 32rpx;
width: 638rpx;
box-sizing: border-box;
.con {
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 24rpx 0;
margin-bottom: 24rpx;
border-bottom: 1rpx solid #E8E8E8;
.con-img {
width: 169rpx;
height: 169rpx;
margin-right: 22rpx;
}
.con-right {
.title {
font-weight: 500;
font-size: 32rpx;
color: #333333;
}
.describe {
margin-top: 14rpx;
width: 385rpx;
font-size: 24rpx;
color: #333333;
line-height: 32rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
}
}
.btn {
width: 266rpx;
height: 70rpx;
border-radius: 70rpx;
background-color: #03AE80;
text-align: center;
line-height: 70rpx;
display: flex;
align-items: center;
flex-direction: row;
justify-content: center;
margin: 0 auto;
.btn-img {
width: 30rpx;
height: 30rpx;
margin-right: 12rpx;
}
.label {
font-weight: 500;
font-size: 28rpx;
color: #fff;
}
}
}
}
</style>