Files
zhwl-miniapp/pages/tabbar/guide.vue

711 lines
21 KiB
Vue
Raw Normal View History

2025-06-26 12:38:35 +08:00
<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>