Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Hooke
/
map-demo
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
hookehuyr
2025-01-26 10:05:16 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
a238d6ff31a0e99893f029e254cfca22172fa95c
a238d6ff
1 parent
326d6f7d
把别院的详情做搬出来作为通用的详情页-Bob需求
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
586 additions
and
1 deletions
src/route.js
src/views/info.vue
src/route.js
View file @
a238d6f
/*
* @Date: 2023-05-29 11:10:19
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-01-2
3 16:22:10
* @LastEditTime: 2025-01-2
6 09:55:58
* @FilePath: /map-demo/src/route.js
* @Description: 文件描述
*/
...
...
@@ -70,6 +70,13 @@ export default [
},
},
{
path
:
'/info'
,
component
:
()
=>
import
(
'@/views/info.vue'
),
meta
:
{
title
:
'详情页'
,
},
},
{
path
:
'/map_cutter'
,
name
:
'瓦片切图工具'
,
component
:
()
=>
import
(
'@/views/mapCutter.vue'
),
...
...
src/views/info.vue
0 → 100644
View file @
a238d6f
<!--
* @Date: 2024-09-15 22:08:49
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-11-06 11:49:42
* @FilePath: /map-demo/src/views/bieyuan/info.vue
* @Description: 文件描述
-->
<template>
<div class="info-page">
<div class="info-header-wrapper">
<div v-if="showBack && page_details.banner?.length" style="position: absolute; top: 1rem; left: 0.5rem; z-index: 9;">
<van-icon name="arrow-left" color="white" size="1.75rem" @click="goBack()" />
</div>
<van-config-provider :theme-vars="themeVars">
<van-swipe class="my-swipe" indicator-color="#DD7850" lazy-render :autoplay="5000">
<van-swipe-item v-for="(image, index) in page_details.banner" :key="index" style="position: relative;">
<van-image fit="cover" width="100%" :height="img_height" :src="image" @click="onClickImg(index)" />
<img src="https://cdn.ipadbiz.cn/bieyuan/map/icon/pageShade@3x.png" style="width: 100%; height: 5rem; position: absolute; right: 0; left: 0; bottom: 0;" alt="">
</van-swipe-item>
</van-swipe>
</van-config-provider>
<div class="header-z"></div>
</div>
<div class="info-content-wrapper">
<div class="info-header">
<div style="display: flex; justify-content: space-between;">
<p class="info-title">{{ page_details.name }}</p>
<div style="display: flex;">
<div @click="onClickAudioList" style="margin-right: 0.75rem;">
<van-icon v-if="!audio_list_height" name="https://cdn.ipadbiz.cn/bieyuan/map/icon/%E8%AF%AD%E9%9F%B31@3x.png" size="1.65rem" />
<van-icon v-else name="https://cdn.ipadbiz.cn/bieyuan/map/icon/%E8%AF%AD%E9%9F%B32@3x.png" size="1.65rem" />
</div>
<div v-if="page_details.path?.length > 1" @click="goTo()" class="info-btn">前往</div>
</div>
</div>
<div class="info-sub-title">{{ page_details.note }}</div>
</div>
<div id="tab-wrapper" style="margin-top: 0.5rem;">
<van-config-provider :theme-vars="themeVars">
<van-tabs ref="tabsRef" v-model:active="active" @click-tab="clickTab" color="#DD7850" title-active-color="#DD7850" title-inactive-color="#DD7850" :shrink="show_shrink" sticky animated>
<van-tab title="介 绍" v-if="page_details.introduction">
<div class="info-content">
<div id="introduction" v-html="page_details.introduction" style="padding: 0 1rem;"></div>
</div>
</van-tab>
<van-tab title="故 事" v-if="page_details.story">
<div class="info-content">
<div id="story" v-html="page_details.story" style="padding: 0 1rem;"></div>
</div>
</van-tab>
<van-tab title="体 验" v-if="page_details.experience">
<div class="info-content">
<div id="experience" v-html="page_details.experience" style="padding: 0 1rem;"></div>
</div>
<div v-if="page_details.experience_audio.length" class="audio-wrapper">
<div @click="toggleHandleAudio(item, index)" :class="['audio-item', play_audio_index === index ? 'click' : '']" v-for="(item, index) in page_details.experience_audio" :key="index">
<div>{{ item.description }}</div>
<van-icon @click.stop="stopAudio(item, index)" v-if="item.play" size="2rem" name="stop-circle-o" color="#DD7850" />
<van-icon v-else @click="playAudio(item, index)" size="2rem" name="https://cdn.ipadbiz.cn/bieyuan/map/icon/audio_icon.png" />
</div>
</div>
</van-tab>
</van-tabs>
</van-config-provider>
</div>
</div>
<!-- <div class="info-logo" :style="{ marginBottom: audio_list_height ? `${audio_list_height * 1.5}px` : '3rem' }">
<van-image width="3rem" height="3rem" fit="contain" src="https://cdn.ipadbiz.cn/bieyuan/map/icon/scan_logo.png" />
</div> -->
<van-toast v-model:show="show_toast" style="padding: 0">
<template #message>
<p style="padding: 0.5rem 1rem;">{{ toast_text }}</p>
</template>
</van-toast>
<van-image-preview v-model:show="show_preview" :images="preview_images" @change="onChange" doubleScale>
<template v-slot:index>第{{ index + 1 }}张</template>
</van-image-preview>
<van-back-top />
<audio-play-list :height="audio_list_height" :status="audio_status" @close="onCloseAudioList" @status="onStatusAudioList"></audio-play-list>
</div>
</template>
<script setup>
import { ref, watch, watchEffect } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { showImagePreview } from 'vant';
import { storeToRefs } from 'pinia'
import audioPlayList from '@/components/audioList.vue'
import { mainStore, useTitle } from '@/utils/generatePackage'
import wx from 'weixin-js-sdk';
import $ from 'jquery';
import { mapAPI } from '@/api/map.js'
const store = mainStore();
const { audio_status, audio_entity, audio_list_status, audio_list_entity } = storeToRefs(store);
const $route = useRoute();
const $router = useRouter();
const themeVars = ref({
swipeIndicatorInactiveBackground: '#fff',
swipeIndicatorMargin: '1.5rem',
tabFontSize: '0.95rem',
});
const props = defineProps({
info: Object,
height: Number
});
const page_details = ref({});
watch(
() => props.info,
(v) => {
if (v.details.length) {
page_details.value = { ...v.details[0], position: v.position, path: v.path };
// 获取浏览器可视范围的高度
$('.info-page').height(props.height + 'px');
}
}
)
const images = ref([
'https://cdn.ipadbiz.cn/bieyuan/map/swiper_img.png',
'https://cdn.ipadbiz.cn/bieyuan/map/Mix_20230612_201951.png',
'https://cdn.ipadbiz.cn/bieyuan/map/Mix_20240815_211927.png',
]);
const active = ref(0);
const play_audio_index = ref(null);
// const audioList = ref([{
// text: '5分钟观呼吸',
// src: 'https://cdn.ipadbiz.cn/bieyuan/map/audio/%E6%AD%A3%E5%BF%B5%E5%91%BC%E5%90%B8%EF%BC%8810%E5%88%86%E9%92%9F%EF%BC%89.mp3',
// play: false,
// }, {
// text: '10分钟正念静坐',
// src: 'https://cdn.ipadbiz.cn/bieyuan/map/audio/%E5%8D%81%E5%88%86%E9%92%9F%E6%AD%A3%E5%BF%B5%E9%9D%99%E5%9D%9020210510.mp3',
// play: false,
// }, {
// text: '15分钟正念静坐',
// src: 'https://cdn.ipadbiz.cn/bieyuan/map/audio/%E5%8D%81%E5%88%86%E9%92%9F%E6%AD%A3%E5%BF%B5%E9%9D%99%E5%9D%9020210510.mp3',
// play: false,
// }])
const toggleHandleAudio = (item, index) => { // 切换播放或者暂停操作
if (item.play) {
stopAudio(item, index);
} else {
playAudio(item, index);
}
}
const playAudio = (item, index) => {
page_details.value.experience_audio.forEach(item => item.play = false);
audio.value.src = item.src;
// 后台有播放器运行时,先暂停
if (audio_list_status.value === 'play'){
audio_list_entity.value.pause();
}
play_audio_index.value = index;
let play_status = audio.value.play() // 播放
if (play_status) {
play_status.then(() => {
item.play = true;
// 存放到pinia里面控制
store.changeAudio(audio.value);
store.changeAudioSrc(audio.value.src);
store.changeAudioStatus('play');
}).catch((e) => {
// 失败
console.log('Operation is too fast, audio play fails')
})
}
}
const stopAudio = (item, index) => {
item.play = false;
audio.value.pause();
}
const audio = ref(new Audio());
const img_height = ref('15rem');
const scrollTop = ref(0);
onMounted(async () => {
// 通过ID查询到标记点详情
if (!props.info) {
let id = $route.query.id;
const { data } = await mapAPI({ i: id });
const raw_list = data.list[0].list; // 获取标记点列表
const marker_id = $route.query.marker_id;
const current_marker = raw_list.filter(item => item.id == marker_id)[0];
//
page_details.value = { ...current_marker.details[0], position: current_marker.position, path: current_marker.path };
// 富文本转义, 分割线样式转换
page_details.value.introduction = page_details.value.introduction?.replace(/\<hr\>/g, '<div class="van-hairline--bottom" style="margin: 1rem 0;"></div>')
page_details.value.story = page_details.value.story?.replace(/\<hr\>/g, '<div class="van-hairline--bottom" style="margin: 1rem 0;"></div>')
page_details.value.experience = page_details.value.experience?.replace(/\<hr\>/g, '<div class="van-hairline--bottom" style="margin: 1rem 0;"></div>')
}
// 介绍栏目,图片点击事件
var imgs = $('#introduction').find('img');
// 图片点击事件
imgs.each(function(index, img) {
$(img).on('click', function (e) {
showImagePreview({
images: [$(img).attr('src')],
startPosition: 0,
showIndex: false,
onClose: () => {
// console.log('close');
}
})
});
// 图片有2个像素的圆角
$(img).css('border-radius', '5px');
});
// 获取屏幕宽度,设置高度4:3
// 获取屏幕的宽度
var screenWidth = $(window).width();
// 计算4:3比例的高度
var screenHeight = screenWidth * 3 / 4;
// 设置容器的高度
img_height.value = screenHeight + 'px';
//
nextTick(() => {
$('.info-page').on('scroll', (evt) => {
scrollTop.value = $(evt.currentTarget).scrollTop(); // 获取滚动的垂直距离
})
})
// 如果是从浮动窗口点击进来音频播放,自动打开
if ($route.query.source === 'click_audio') {
setTimeout(() => {
audio_list_height.value = (0.2 * window.innerHeight);
// 修改当前路由参数,避免刷新再次播放
$router.push({
query: {
...$route.query,
source: ''
}
});
}, 500);
}
// 地图标题
document.title = page_details.value.name;
// 微信分享
const shareData = {
title: page_details.value.name, // 分享标题
desc: '别院详情', // 分享描述
link: location.origin + location.pathname + location.hash, // 分享链接,该链接域名或路径必须与当前页面对应的公众号 JS 安全域名一致
imgUrl: '', // 分享图标
success: function () {
console.warn('设置成功');
}
}
// 分享好友(微信好友或qq好友)
wx.updateAppMessageShareData(shareData);
// 分享到朋友圈或qq空间
wx.updateTimelineShareData(shareData);
// 分享到腾讯微博
wx.onMenuShareWeibo(shareData);
});
// watchEffect(
// () => useTitle(page_details.value.name) // 地图标题
// )
onUnmounted(() => { // 离开页面时关闭音频播放
audio.value.pause();
store.changeAudioStatus('pause');
})
const audio_play = (src, index) => {
audio.value.src = src;
}
const outerStopAudio = () => {
audio.value.pause();
}
const emit = defineEmits(["closeFloat", 'route']);
const show_toast = ref(false);
const toast_text = ref('');
const goTo = () => { // 打开标记地图显示
// 没有关联导航提示
if (page_details.value.path.length <= 1) {
show_toast.value = true;
toast_text.value = '该标记点没有关联导航';
return;
}
//
if ($router.currentRoute.value.path === '/bieyuan/info') { // 详情页
$router.push({
path: '/bieyuan/map',
query: {
id: $route.query.id,
marker_id: $route.query.marker_id
}
})
} else { // 地图页
//
emit("closeFloat", false);
//
emit("route", {name: '参观路径', path: page_details.value.path});
}
}
const goBack = () => { // 返回首页
$router.push({
path: '/bieyuan/map',
query: {
id: $route.query.id,
}
})
}
const showBack = computed(() => $router.currentRoute.value.path === '/bieyuan/info');
const voicePause = () => {
audio.value.pause();
store.changeAudioStatus('pause');
}
const tabsRef = ref(null);
const clickTab = (evt) => { // 标签切换
tabsRef.value.resize();
nextTick(() => {
if (evt.title === '介 绍') { // 介绍
var imgs = $('#introduction').find('img');
}
if (evt.title === '故 事') { // 故事
var imgs = $('#story').find('img');
}
if (evt.title === '体 验') { // 体验
var imgs = $('#experience').find('img');
}
// 图片点击事件
imgs.each(function(index, img) {
$(img).on('click', function (e) {
showImagePreview({
images: [$(img).attr('src')],
startPosition: 0,
showIndex: false,
onClose: () => {
// console.log('close');
}
})
})
// 图片有5个像素的圆角
$(img).css('border-radius', '5px');
});
// 滚动高度大于tabs高度后才滚动到指定高度
let offsetTop = $('#tab-wrapper')[0].offsetTop;
if (scrollTop.value >= offsetTop) {
$('.info-page').scrollTop(offsetTop);
}
});
}
watch(
() => audio_status.value,
(v) => {
if (v === 'pause') {
voicePause();
page_details.value.experience_audio?.forEach(item => item.play = false);
}
},
{ immediate: true }
);
defineExpose({
outerStopAudio
})
const show_preview = ref(false);
const index = ref(0);
const preview_images = [];
const onChange = (newIndex) => {
index.value = newIndex;
};
const onClickImg = (idx) => {
showImagePreview({
images: page_details.value.banner,
startPosition: idx,
showIndex: true,
onClose: () => {
// console.log('close');
}
})
};
const show_shrink = computed(() => {
// 统计非空字段的个数
let filledFields = 0;
if (page_details.value.introduction) filledFields++;
if (page_details.value.story) filledFields++;
if (page_details.value.experience) filledFields++;
// 判断是否只有一个字段有值
if (filledFields === 1) {
return true;
}
return false;
});
const audio_list_height = ref(0);
const onClickAudioList = () => {
if ($('.info-page').height() < $(window).height()) { // 在浮动模式下点击音频列表
// 打开页面
$router.push({
path: '/bieyuan/info',
query: {
id: $route.query.id,
marker_id: props.info.id,
source: 'click_audio'
}
});
} else { // 详情页内点击
audio_list_height.value = (0.2 * window.innerHeight);
}
}
const onCloseAudioList = () => {
audio_list_height.value = 0;
}
// const show_audio = ref(true);
const onStatusAudioList = (status) => { // 音频列表组件,状态改变
page_details.value.experience_audio?.forEach(item => item.play = false);
audio.value.pause();
play_audio_index.value = null;
store.changeAudioStatus('pause');
// // 反馈播放列表数量为空时,隐藏图标
// if (status === 'none') {
// show_audio.value = false;
// }
}
</script>
<style lang="less">
.info-page {
background-color: #EBEBEB;
height: 100vh;
overflow: scroll;
position: relative;
.info-header-wrapper {
position: relative;
min-height: 2rem;
.header-z {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 1rem;
// box-shadow: rgba(241, 242, 248, 0.6) 0px -3px 25px 15px;
// background-color: #f7f7f7;
background-color: #fff;
margin: 0 1rem;
border-top-left-radius: 0.5rem;
border-top-right-radius: 0.5rem;
}
}
.info-content-wrapper {
box-shadow: 0px -3px 6px 0 rgba(241, 242, 248, 0.8);
margin: 1rem;
margin-top: 0;
// padding: 1rem;
border-bottom-left-radius: 0.5rem;
border-bottom-right-radius: 0.5rem;
background-color: white;
.info-header {
padding: 1rem 2rem 0;
// display: flex;
// justify-content: space-between;
// align-items: center;
.info-title {
font-size: 1.25rem;
margin-bottom: 0.5rem;
}
.info-sub-title {
font-size: 0.85rem;
color: #A0A8B1;
line-height: 1.75;
}
.info-btn {
width: 3rem;
height: 1.5rem;
border: 1px solid #DD7850;
color: #DD7850;
border-radius: 0.8rem;
font-size: 0.85rem;
text-align: center;
line-height: 1.5rem;
}
}
.info-content {
color: #47525F;
padding: 1rem;
line-height: 1.75;
p {
line-height: 1.75;
// padding: 0 0.85rem;
text-align: justify;
img {
width: 100%;
}
}
}
.audio-wrapper {
padding: 1rem;
.audio-item {
color: #47525F;
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
background-color: #FFF;
border-radius: 0.25rem;
margin: 1rem;
box-shadow: 0 0 0.5rem rgba(0, 0, 0, 0.1);
&.click {
border: 1px solid #DD7850;
}
.audio-icon {
width: 2rem;
height: 2rem;
background-image: url('https://cdn.ipadbiz.cn/bieyuan/map/icon/audio_icon.png'); /* 使用上传的图标 */
background-size: cover;
&.click {
animation: pulse 1.5s infinite;
}
}
@keyframes pulse {
0% {
transform: scale(1);
}
50% {
transform: scale(1.2);
}
100% {
transform: scale(1);
}
}
}
}
}
.info-logo {
display: flex;
justify-content: center;
margin: 3rem;
}
.van-tabs__wrap {
border-bottom: 1px solid #F3F3F3;
}
.van-tabs__nav--line.van-tabs__nav--shrink {
padding-left: 2rem;
}
}
.van-back-top {
background-color: #DD7850;
}
</style>
Please
register
or
login
to post a comment