feat(路由): 新增签到模块相关页面和路由配置
添加签到模块的首页、扫码页和信息详情页 配置签到模块的路由路径 实现音频播放、图片预览等功能
Showing
6 changed files
with
2430 additions
and
1 deletions
| 1 | /* | 1 | /* |
| 2 | * @Date: 2023-05-29 11:10:19 | 2 | * @Date: 2023-05-29 11:10:19 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-02-10 16:19:29 | 4 | + * @LastEditTime: 2025-08-26 15:46:05 |
| 5 | * @FilePath: /map-demo/src/route.js | 5 | * @FilePath: /map-demo/src/route.js |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | */ | 7 | */ |
| ... | @@ -112,4 +112,18 @@ export default [ | ... | @@ -112,4 +112,18 @@ export default [ |
| 112 | title: '详情页', | 112 | title: '详情页', |
| 113 | }, | 113 | }, |
| 114 | }, | 114 | }, |
| 115 | + { | ||
| 116 | + path: '/checkin', | ||
| 117 | + component: () => import('@/views/checkin/map.vue'), | ||
| 118 | + meta: { | ||
| 119 | + title: '地图', | ||
| 120 | + }, | ||
| 121 | + }, | ||
| 122 | + { | ||
| 123 | + path: '/checkin/info', | ||
| 124 | + component: () => import('@/views/checkin/info.vue'), | ||
| 125 | + meta: { | ||
| 126 | + title: '详情页', | ||
| 127 | + }, | ||
| 128 | + }, | ||
| 115 | ]; | 129 | ]; | ... | ... |
src/views/checkin/index.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2024-09-14 17:48:55 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2024-09-21 23:04:40 | ||
| 5 | + * @FilePath: /map-demo/src/views/bieyuan/index.vue | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <div class="index-page"> | ||
| 10 | + <div style="display: flex; flex-direction: column; align-items: center;"> | ||
| 11 | + <van-image | ||
| 12 | + width="12rem" | ||
| 13 | + height="12rem" | ||
| 14 | + fit="contain" | ||
| 15 | + src="https://cdn.ipadbiz.cn/bieyuan/map/icon/index_logo@3x.png" | ||
| 16 | + /> | ||
| 17 | + <div style="margin-top: 2rem; font-size: 0.95rem; letter-spacing: 5px; color: #47525F;">山水逢甘露,静心遇桃源</div> | ||
| 18 | + </div> | ||
| 19 | + <div @click="goTo" style="border: 1px solid #DD7850; padding: 0.8rem 5.5rem; border-radius: 5px; font-size: 1.15rem; color: #DD7850; background-color: white;">进 入</div> | ||
| 20 | + </div> | ||
| 21 | +</template> | ||
| 22 | + | ||
| 23 | +<script setup> | ||
| 24 | +import { ref } from 'vue' | ||
| 25 | +import { useRoute, useRouter } from 'vue-router' | ||
| 26 | + | ||
| 27 | +//import { } from '@/utils/generateModules.js' | ||
| 28 | +//import { } from '@/utils/generateIcons.js' | ||
| 29 | +//import { } from '@/composables' | ||
| 30 | +const $route = useRoute(); | ||
| 31 | +const $router = useRouter(); | ||
| 32 | + | ||
| 33 | +const goTo = () => { | ||
| 34 | + $router.push({ | ||
| 35 | + path: './map', | ||
| 36 | + query: { | ||
| 37 | + id: $route.query.id | ||
| 38 | + } | ||
| 39 | + }); | ||
| 40 | + // 进入标记 | ||
| 41 | + localStorage.setItem('first_in_bieyuan', 1); | ||
| 42 | +} | ||
| 43 | + | ||
| 44 | +onMounted(() => { | ||
| 45 | + // 记录第一次进入页面,之后判断是否第一次进入,直接跳转到MAP页面 | ||
| 46 | + if (localStorage.getItem('first_in_bieyuan') === '1') { | ||
| 47 | + $router.push({ | ||
| 48 | + path: './map', | ||
| 49 | + query: { | ||
| 50 | + id: $route.query.id | ||
| 51 | + } | ||
| 52 | + }); | ||
| 53 | + } | ||
| 54 | +}); | ||
| 55 | +</script> | ||
| 56 | + | ||
| 57 | +<style lang="less" scoped> | ||
| 58 | + .index-page { | ||
| 59 | + height: 100vh; | ||
| 60 | + display: flex; | ||
| 61 | + flex-direction: column; | ||
| 62 | + justify-content: space-evenly; | ||
| 63 | + align-items: center; | ||
| 64 | + background: linear-gradient(rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.5)), | ||
| 65 | + url('https://cdn.ipadbiz.cn/bieyuan/map/MAP@3x.png'); | ||
| 66 | + background-size: contain; | ||
| 67 | + } | ||
| 68 | +</style> |
src/views/checkin/info.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2024-09-15 22:08:49 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-03-22 21:33:41 | ||
| 5 | + * @FilePath: /map-demo/src/views/by/info.vue | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <div class="info-page"> | ||
| 10 | + <div class="info-header-wrapper"> | ||
| 11 | + <div v-if="showBack && page_details.banner?.length" style="position: absolute; top: 1rem; left: 0.5rem; z-index: 9;"> | ||
| 12 | + <van-icon name="arrow-left" color="white" size="1.75rem" @click="goBack()" /> | ||
| 13 | + </div> | ||
| 14 | + <van-config-provider :theme-vars="themeVars"> | ||
| 15 | + <van-swipe class="my-swipe" indicator-color="#DD7850" lazy-render :autoplay="5000"> | ||
| 16 | + <van-swipe-item v-for="(image, index) in page_details.banner" :key="index" style="position: relative;"> | ||
| 17 | + <van-image fit="cover" width="100%" :height="img_height" :src="image" @click="onClickImg(index)" /> | ||
| 18 | + <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=""> | ||
| 19 | + </van-swipe-item> | ||
| 20 | + </van-swipe> | ||
| 21 | + </van-config-provider> | ||
| 22 | + <div class="header-z"></div> | ||
| 23 | + </div> | ||
| 24 | + <div class="info-content-wrapper"> | ||
| 25 | + <div class="info-header"> | ||
| 26 | + <div style="display: flex; justify-content: space-between;"> | ||
| 27 | + <p class="info-title">{{ page_details.name }}</p> | ||
| 28 | + <div style="display: flex;"> | ||
| 29 | + <div v-if="page_details.show_audio" @click="onClickAudioList" style="margin-right: 0.75rem;"> | ||
| 30 | + <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" /> | ||
| 31 | + <van-icon v-else name="https://cdn.ipadbiz.cn/bieyuan/map/icon/%E8%AF%AD%E9%9F%B32@3x.png" size="1.65rem" /> | ||
| 32 | + </div> | ||
| 33 | + <div v-if="page_details.path?.length > 1" @click="goTo()" class="info-btn">前往</div> | ||
| 34 | + <div @click="goToWalk()" class="info-btn">前往</div> | ||
| 35 | + </div> | ||
| 36 | + </div> | ||
| 37 | + <div class="info-sub-title">{{ page_details.note }}</div> | ||
| 38 | + </div> | ||
| 39 | + <div id="tab-wrapper" style="margin-top: 0.5rem;"> | ||
| 40 | + <van-config-provider :theme-vars="themeVars"> | ||
| 41 | + <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> | ||
| 42 | + <van-tab title="介 绍" v-if="page_details.introduction"> | ||
| 43 | + <div class="info-content"> | ||
| 44 | + <div id="introduction" v-html="page_details.introduction" style="padding: 0 1rem;"></div> | ||
| 45 | + </div> | ||
| 46 | + </van-tab> | ||
| 47 | + <van-tab title="故 事" v-if="page_details.story"> | ||
| 48 | + <div class="info-content"> | ||
| 49 | + <div id="story" v-html="page_details.story" style="padding: 0 1rem;"></div> | ||
| 50 | + </div> | ||
| 51 | + </van-tab> | ||
| 52 | + <van-tab title="体 验" v-if="page_details.experience"> | ||
| 53 | + <div class="info-content"> | ||
| 54 | + <div id="experience" v-html="page_details.experience" style="padding: 0 1rem;"></div> | ||
| 55 | + </div> | ||
| 56 | + <div v-if="page_details.experience_audio.length" class="audio-wrapper"> | ||
| 57 | + <div @click="toggleHandleAudio(item, index)" :class="['audio-item', play_audio_index === index ? 'click' : '']" v-for="(item, index) in page_details.experience_audio" :key="index"> | ||
| 58 | + <div>{{ item.description }}</div> | ||
| 59 | + <van-icon @click.stop="stopAudio(item, index)" v-if="item.play" size="2rem" name="stop-circle-o" color="#DD7850" /> | ||
| 60 | + <van-icon v-else @click="playAudio(item, index)" size="2rem" name="https://cdn.ipadbiz.cn/bieyuan/map/icon/audio_icon.png" /> | ||
| 61 | + </div> | ||
| 62 | + </div> | ||
| 63 | + </van-tab> | ||
| 64 | + </van-tabs> | ||
| 65 | + </van-config-provider> | ||
| 66 | + </div> | ||
| 67 | + </div> | ||
| 68 | + <!-- <div class="info-logo" :style="{ marginBottom: audio_list_height ? `${audio_list_height * 1.5}px` : '3rem' }"> | ||
| 69 | + <van-image width="3rem" height="3rem" fit="contain" src="https://cdn.ipadbiz.cn/bieyuan/map/icon/scan_logo.png" /> | ||
| 70 | + </div> --> | ||
| 71 | + | ||
| 72 | + <van-toast v-model:show="show_toast" style="padding: 0"> | ||
| 73 | + <template #message> | ||
| 74 | + <p style="padding: 0.5rem 1rem;">{{ toast_text }}</p> | ||
| 75 | + </template> | ||
| 76 | + </van-toast> | ||
| 77 | + | ||
| 78 | + <van-image-preview v-model:show="show_preview" :images="preview_images" @change="onChange" doubleScale> | ||
| 79 | + <template v-slot:index>第{{ index + 1 }}张</template> | ||
| 80 | + </van-image-preview> | ||
| 81 | + | ||
| 82 | + <van-back-top /> | ||
| 83 | + | ||
| 84 | + <audio-play-list :height="audio_list_height" :status="audio_status" @close="onCloseAudioList" @status="onStatusAudioList"></audio-play-list> | ||
| 85 | + </div> | ||
| 86 | +</template> | ||
| 87 | + | ||
| 88 | +<script setup> | ||
| 89 | +import { ref, watch, watchEffect } from 'vue' | ||
| 90 | +import { useRoute, useRouter } from 'vue-router' | ||
| 91 | +import { showImagePreview } from 'vant'; | ||
| 92 | +import { storeToRefs } from 'pinia' | ||
| 93 | +import audioPlayList from '@/components/audioList.vue' | ||
| 94 | +import { mainStore, useTitle } from '@/utils/generatePackage' | ||
| 95 | +import wx from 'weixin-js-sdk'; | ||
| 96 | +import $ from 'jquery'; | ||
| 97 | + | ||
| 98 | +import { mapAPI, mapAudioAPI } from '@/api/map.js' | ||
| 99 | + | ||
| 100 | +const store = mainStore(); | ||
| 101 | +const { audio_status, audio_entity, audio_list_status, audio_list_entity } = storeToRefs(store); | ||
| 102 | + | ||
| 103 | +const $route = useRoute(); | ||
| 104 | +const $router = useRouter(); | ||
| 105 | + | ||
| 106 | +const themeVars = ref({ | ||
| 107 | + swipeIndicatorInactiveBackground: '#fff', | ||
| 108 | + swipeIndicatorMargin: '1.5rem', | ||
| 109 | + tabFontSize: '0.95rem', | ||
| 110 | +}); | ||
| 111 | + | ||
| 112 | +const props = defineProps({ | ||
| 113 | + info: Object, | ||
| 114 | + height: Number | ||
| 115 | +}); | ||
| 116 | + | ||
| 117 | +const page_details = ref({}); | ||
| 118 | + | ||
| 119 | +watch( | ||
| 120 | + () => props.info, | ||
| 121 | + (v) => { | ||
| 122 | + if (v.details.length) { | ||
| 123 | + page_details.value = { ...v.details[0], position: v.position, path: v.path }; | ||
| 124 | + // 获取浏览器可视范围的高度 | ||
| 125 | + $('.info-page').height(props.height + 'px'); | ||
| 126 | + } | ||
| 127 | + } | ||
| 128 | +) | ||
| 129 | + | ||
| 130 | +const images = ref([ | ||
| 131 | + 'https://cdn.ipadbiz.cn/bieyuan/map/swiper_img.png', | ||
| 132 | + 'https://cdn.ipadbiz.cn/bieyuan/map/Mix_20230612_201951.png', | ||
| 133 | + 'https://cdn.ipadbiz.cn/bieyuan/map/Mix_20240815_211927.png', | ||
| 134 | +]); | ||
| 135 | + | ||
| 136 | +const active = ref(0); | ||
| 137 | +const play_audio_index = ref(null); | ||
| 138 | + | ||
| 139 | +// const audioList = ref([{ | ||
| 140 | +// text: '5分钟观呼吸', | ||
| 141 | +// 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', | ||
| 142 | +// play: false, | ||
| 143 | +// }, { | ||
| 144 | +// text: '10分钟正念静坐', | ||
| 145 | +// 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', | ||
| 146 | +// play: false, | ||
| 147 | +// }, { | ||
| 148 | +// text: '15分钟正念静坐', | ||
| 149 | +// 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', | ||
| 150 | +// play: false, | ||
| 151 | +// }]) | ||
| 152 | +const toggleHandleAudio = (item, index) => { // 切换播放或者暂停操作 | ||
| 153 | + if (item.play) { | ||
| 154 | + stopAudio(item, index); | ||
| 155 | + } else { | ||
| 156 | + playAudio(item, index); | ||
| 157 | + } | ||
| 158 | +} | ||
| 159 | + | ||
| 160 | +const playAudio = (item, index) => { | ||
| 161 | + page_details.value.experience_audio.forEach(item => item.play = false); | ||
| 162 | + audio.value.src = item.src; | ||
| 163 | + // 后台有播放器运行时,先暂停 | ||
| 164 | + if (audio_list_status.value === 'play'){ | ||
| 165 | + audio_list_entity.value.pause(); | ||
| 166 | + } | ||
| 167 | + play_audio_index.value = index; | ||
| 168 | + let play_status = audio.value.play() // 播放 | ||
| 169 | + if (play_status) { | ||
| 170 | + play_status.then(() => { | ||
| 171 | + item.play = true; | ||
| 172 | + // 存放到pinia里面控制 | ||
| 173 | + store.changeAudio(audio.value); | ||
| 174 | + store.changeAudioSrc(audio.value.src); | ||
| 175 | + store.changeAudioStatus('play'); | ||
| 176 | + }).catch((e) => { | ||
| 177 | + // 失败 | ||
| 178 | + console.log('Operation is too fast, audio play fails') | ||
| 179 | + }) | ||
| 180 | + } | ||
| 181 | +} | ||
| 182 | + | ||
| 183 | +const stopAudio = (item, index) => { | ||
| 184 | + item.play = false; | ||
| 185 | + audio.value.pause(); | ||
| 186 | +} | ||
| 187 | + | ||
| 188 | +const audio = ref(new Audio()); | ||
| 189 | +const img_height = ref('15rem'); | ||
| 190 | +const scrollTop = ref(0); | ||
| 191 | + | ||
| 192 | +onMounted(async () => { | ||
| 193 | + // 通过ID查询到标记点详情 | ||
| 194 | + if (!props.info) { | ||
| 195 | + let id = $route.query.id; | ||
| 196 | + const { data } = await mapAPI({ i: id }); | ||
| 197 | + const raw_list = data.list[0].list; // 获取标记点列表 | ||
| 198 | + const marker_id = $route.query.marker_id; | ||
| 199 | + const current_marker = raw_list.filter(item => item.id == marker_id)[0]; | ||
| 200 | + // | ||
| 201 | + page_details.value = { ...current_marker.details[0], position: current_marker.position, path: current_marker.path }; | ||
| 202 | + // 富文本转义, 分割线样式转换 | ||
| 203 | + page_details.value.introduction = page_details.value.introduction?.replace(/\<hr\>/g, '<div class="van-hairline--bottom" style="margin: 1rem 0;"></div>') | ||
| 204 | + page_details.value.story = page_details.value.story?.replace(/\<hr\>/g, '<div class="van-hairline--bottom" style="margin: 1rem 0;"></div>') | ||
| 205 | + page_details.value.experience = page_details.value.experience?.replace(/\<hr\>/g, '<div class="van-hairline--bottom" style="margin: 1rem 0;"></div>') | ||
| 206 | + // 查询是否有音频列表,打标记点是否有音频 | ||
| 207 | + const getAudioList = await mapAudioAPI({ mid: $route.query.id, bid: marker_id }); | ||
| 208 | + if (getAudioList.data && getAudioList.data.length) { | ||
| 209 | + page_details.value.show_audio = true; | ||
| 210 | + } | ||
| 211 | + } | ||
| 212 | + // 介绍栏目,图片点击事件 | ||
| 213 | + var imgs = $('#introduction').find('img'); | ||
| 214 | + // 图片点击事件 | ||
| 215 | + imgs.each(function(index, img) { | ||
| 216 | + $(img).on('click', function (e) { | ||
| 217 | + showImagePreview({ | ||
| 218 | + images: [$(img).attr('src')], | ||
| 219 | + startPosition: 0, | ||
| 220 | + showIndex: false, | ||
| 221 | + onClose: () => { | ||
| 222 | + // console.log('close'); | ||
| 223 | + } | ||
| 224 | + }) | ||
| 225 | + }); | ||
| 226 | + // 图片有2个像素的圆角 | ||
| 227 | + $(img).css('border-radius', '5px'); | ||
| 228 | + }); | ||
| 229 | + // 获取屏幕宽度,设置高度4:3 | ||
| 230 | + // 获取屏幕的宽度 | ||
| 231 | + var screenWidth = $(window).width(); | ||
| 232 | + // 计算4:3比例的高度 | ||
| 233 | + var screenHeight = screenWidth * 3 / 4; | ||
| 234 | + // 设置容器的高度 | ||
| 235 | + img_height.value = screenHeight + 'px'; | ||
| 236 | + // | ||
| 237 | + nextTick(() => { | ||
| 238 | + $('.info-page').on('scroll', (evt) => { | ||
| 239 | + scrollTop.value = $(evt.currentTarget).scrollTop(); // 获取滚动的垂直距离 | ||
| 240 | + }) | ||
| 241 | + }) | ||
| 242 | + // 如果是从浮动窗口点击进来音频播放,自动打开 | ||
| 243 | + if ($route.query.source === 'click_audio') { | ||
| 244 | + setTimeout(() => { | ||
| 245 | + audio_list_height.value = (0.2 * window.innerHeight); | ||
| 246 | + // 修改当前路由参数,避免刷新再次播放 | ||
| 247 | + $router.push({ | ||
| 248 | + query: { | ||
| 249 | + ...$route.query, | ||
| 250 | + source: '' | ||
| 251 | + } | ||
| 252 | + }); | ||
| 253 | + }, 500); | ||
| 254 | + } | ||
| 255 | + // 地图标题 | ||
| 256 | + document.title = page_details.value.name; | ||
| 257 | + // 微信分享 | ||
| 258 | + const shareData = { | ||
| 259 | + title: page_details.value.name, // 分享标题 | ||
| 260 | + desc: '别院详情', // 分享描述 | ||
| 261 | + link: location.origin + location.pathname + location.hash, // 分享链接,该链接域名或路径必须与当前页面对应的公众号 JS 安全域名一致 | ||
| 262 | + imgUrl: '', // 分享图标 | ||
| 263 | + success: function () { | ||
| 264 | + // console.warn('设置成功'); | ||
| 265 | + } | ||
| 266 | + } | ||
| 267 | + // 分享好友(微信好友或qq好友) | ||
| 268 | + wx.updateAppMessageShareData(shareData); | ||
| 269 | + // 分享到朋友圈或qq空间 | ||
| 270 | + wx.updateTimelineShareData(shareData); | ||
| 271 | + // 分享到腾讯微博 | ||
| 272 | + wx.onMenuShareWeibo(shareData); | ||
| 273 | +}); | ||
| 274 | + | ||
| 275 | +// watchEffect( | ||
| 276 | +// () => useTitle(page_details.value.name) // 地图标题 | ||
| 277 | +// ) | ||
| 278 | + | ||
| 279 | +onUnmounted(() => { // 离开页面时关闭音频播放 | ||
| 280 | + audio.value.pause(); | ||
| 281 | + store.changeAudioStatus('pause'); | ||
| 282 | +}) | ||
| 283 | + | ||
| 284 | +const audio_play = (src, index) => { | ||
| 285 | + audio.value.src = src; | ||
| 286 | +} | ||
| 287 | + | ||
| 288 | +const outerStopAudio = () => { | ||
| 289 | + audio.value.pause(); | ||
| 290 | +} | ||
| 291 | + | ||
| 292 | +const emit = defineEmits(["closeFloat", 'route', 'walkRoute']); | ||
| 293 | + | ||
| 294 | +const show_toast = ref(false); | ||
| 295 | +const toast_text = ref(''); | ||
| 296 | + | ||
| 297 | +const goTo = () => { // 打开标记地图显示 | ||
| 298 | + // 没有关联导航提示 | ||
| 299 | + if (page_details.value.path.length <= 1) { | ||
| 300 | + show_toast.value = true; | ||
| 301 | + toast_text.value = '该标记点没有关联导航'; | ||
| 302 | + return; | ||
| 303 | + } | ||
| 304 | + // | ||
| 305 | + if ($router.currentRoute.value.path === '/by/info') { // 详情页 | ||
| 306 | + $router.push({ | ||
| 307 | + path: '/by', | ||
| 308 | + query: { | ||
| 309 | + id: $route.query.id, | ||
| 310 | + marker_id: $route.query.marker_id | ||
| 311 | + } | ||
| 312 | + }) | ||
| 313 | + } else { // 地图页 | ||
| 314 | + // | ||
| 315 | + emit("closeFloat", false); | ||
| 316 | + // | ||
| 317 | + emit("route", {name: '参观路径', path: page_details.value.path}); | ||
| 318 | + } | ||
| 319 | +} | ||
| 320 | + | ||
| 321 | +const goToWalk = async () => { // 打开步行导航地图显示 | ||
| 322 | + // | ||
| 323 | + if ($router.currentRoute.value.path === '/by/info') { // 详情页 | ||
| 324 | + $router.push({ | ||
| 325 | + path: '/by', | ||
| 326 | + query: { | ||
| 327 | + id: $route.query.id, | ||
| 328 | + marker_id: $route.query.marker_id | ||
| 329 | + } | ||
| 330 | + }) | ||
| 331 | + } else { // 地图页 | ||
| 332 | + // | ||
| 333 | + emit("closeFloat", false); | ||
| 334 | + // | ||
| 335 | + if (page_details.value?.position.length) { | ||
| 336 | + emit("walkRoute", {name: '步行导航', point: [+page_details.value?.position[0], +page_details.value?.position[1]]}); | ||
| 337 | + } else { | ||
| 338 | + show_toast.value = true; | ||
| 339 | + toast_text.value = '该标记点没有关联导航'; | ||
| 340 | + } | ||
| 341 | + } | ||
| 342 | +} | ||
| 343 | + | ||
| 344 | +const goBack = () => { // 返回首页 | ||
| 345 | + $router.push({ | ||
| 346 | + path: '/by', | ||
| 347 | + query: { | ||
| 348 | + id: $route.query.id, | ||
| 349 | + } | ||
| 350 | + }) | ||
| 351 | +} | ||
| 352 | + | ||
| 353 | +const showBack = computed(() => $router.currentRoute.value.path === '/by/info'); | ||
| 354 | + | ||
| 355 | +const voicePause = () => { | ||
| 356 | + audio.value.pause(); | ||
| 357 | + store.changeAudioStatus('pause'); | ||
| 358 | +} | ||
| 359 | + | ||
| 360 | +const tabsRef = ref(null); | ||
| 361 | +const clickTab = (evt) => { // 标签切换 | ||
| 362 | + tabsRef.value.resize(); | ||
| 363 | + nextTick(() => { | ||
| 364 | + if (evt.title === '介 绍') { // 介绍 | ||
| 365 | + var imgs = $('#introduction').find('img'); | ||
| 366 | + } | ||
| 367 | + if (evt.title === '故 事') { // 故事 | ||
| 368 | + var imgs = $('#story').find('img'); | ||
| 369 | + } | ||
| 370 | + if (evt.title === '体 验') { // 体验 | ||
| 371 | + var imgs = $('#experience').find('img'); | ||
| 372 | + } | ||
| 373 | + // 图片点击事件 | ||
| 374 | + imgs.each(function(index, img) { | ||
| 375 | + $(img).on('click', function (e) { | ||
| 376 | + showImagePreview({ | ||
| 377 | + images: [$(img).attr('src')], | ||
| 378 | + startPosition: 0, | ||
| 379 | + showIndex: false, | ||
| 380 | + onClose: () => { | ||
| 381 | + // console.log('close'); | ||
| 382 | + } | ||
| 383 | + }) | ||
| 384 | + }) | ||
| 385 | + // 图片有5个像素的圆角 | ||
| 386 | + $(img).css('border-radius', '5px'); | ||
| 387 | + }); | ||
| 388 | + // 滚动高度大于tabs高度后才滚动到指定高度 | ||
| 389 | + let offsetTop = $('#tab-wrapper')[0].offsetTop; | ||
| 390 | + if (scrollTop.value >= offsetTop) { | ||
| 391 | + $('.info-page').scrollTop(offsetTop); | ||
| 392 | + } | ||
| 393 | + }); | ||
| 394 | +} | ||
| 395 | + | ||
| 396 | +watch( | ||
| 397 | + () => audio_status.value, | ||
| 398 | + (v) => { | ||
| 399 | + if (v === 'pause') { | ||
| 400 | + voicePause(); | ||
| 401 | + page_details.value.experience_audio?.forEach(item => item.play = false); | ||
| 402 | + } | ||
| 403 | + }, | ||
| 404 | + { immediate: true } | ||
| 405 | +); | ||
| 406 | + | ||
| 407 | +defineExpose({ | ||
| 408 | + outerStopAudio | ||
| 409 | +}) | ||
| 410 | + | ||
| 411 | + | ||
| 412 | +const show_preview = ref(false); | ||
| 413 | +const index = ref(0); | ||
| 414 | +const preview_images = []; | ||
| 415 | +const onChange = (newIndex) => { | ||
| 416 | + index.value = newIndex; | ||
| 417 | +}; | ||
| 418 | + | ||
| 419 | +const onClickImg = (idx) => { | ||
| 420 | + if ($('.info-page').height() >= $(window).height()) { | ||
| 421 | + showImagePreview({ | ||
| 422 | + images: page_details.value.banner, | ||
| 423 | + startPosition: idx, | ||
| 424 | + showIndex: true, | ||
| 425 | + onClose: () => { | ||
| 426 | + // console.log('close'); | ||
| 427 | + } | ||
| 428 | + }) | ||
| 429 | + } | ||
| 430 | +}; | ||
| 431 | + | ||
| 432 | +const show_shrink = computed(() => { | ||
| 433 | + // 统计非空字段的个数 | ||
| 434 | + let filledFields = 0; | ||
| 435 | + | ||
| 436 | + if (page_details.value.introduction) filledFields++; | ||
| 437 | + if (page_details.value.story) filledFields++; | ||
| 438 | + if (page_details.value.experience) filledFields++; | ||
| 439 | + | ||
| 440 | + // 判断是否只有一个字段有值 | ||
| 441 | + if (filledFields === 1) { | ||
| 442 | + return true; | ||
| 443 | + } | ||
| 444 | + return false; | ||
| 445 | +}); | ||
| 446 | + | ||
| 447 | +const audio_list_height = ref(0); | ||
| 448 | + | ||
| 449 | +const onClickAudioList = () => { | ||
| 450 | + if ($('.info-page').height() < $(window).height()) { // 在浮动模式下点击音频列表 | ||
| 451 | + // 打开页面 | ||
| 452 | + $router.push({ | ||
| 453 | + path: '/by/info', | ||
| 454 | + query: { | ||
| 455 | + id: $route.query.id, | ||
| 456 | + marker_id: props.info.id, | ||
| 457 | + source: 'click_audio' | ||
| 458 | + } | ||
| 459 | + }); | ||
| 460 | + } else { // 详情页内点击 | ||
| 461 | + audio_list_height.value = (0.2 * window.innerHeight); | ||
| 462 | + } | ||
| 463 | +} | ||
| 464 | + | ||
| 465 | +const onCloseAudioList = () => { | ||
| 466 | + audio_list_height.value = 0; | ||
| 467 | +} | ||
| 468 | + | ||
| 469 | +// const show_audio = ref(true); | ||
| 470 | + | ||
| 471 | +const onStatusAudioList = (status) => { // 音频列表组件,状态改变 | ||
| 472 | + page_details.value.experience_audio?.forEach(item => item.play = false); | ||
| 473 | + audio.value.pause(); | ||
| 474 | + play_audio_index.value = null; | ||
| 475 | + store.changeAudioStatus('pause'); | ||
| 476 | + // // 反馈播放列表数量为空时,隐藏图标 | ||
| 477 | + // if (status === 'none') { | ||
| 478 | + // show_audio.value = false; | ||
| 479 | + // } | ||
| 480 | +} | ||
| 481 | +</script> | ||
| 482 | + | ||
| 483 | +<style lang="less"> | ||
| 484 | +.info-page { | ||
| 485 | + background-color: #EBEBEB; | ||
| 486 | + height: 100vh; | ||
| 487 | + overflow: scroll; | ||
| 488 | + position: relative; | ||
| 489 | + .info-header-wrapper { | ||
| 490 | + position: relative; | ||
| 491 | + min-height: 2rem; | ||
| 492 | + .header-z { | ||
| 493 | + position: absolute; | ||
| 494 | + bottom: 0; | ||
| 495 | + left: 0; | ||
| 496 | + right: 0; | ||
| 497 | + height: 1rem; | ||
| 498 | + // box-shadow: rgba(241, 242, 248, 0.6) 0px -3px 25px 15px; | ||
| 499 | + // background-color: #f7f7f7; | ||
| 500 | + background-color: #fff; | ||
| 501 | + margin: 0 1rem; | ||
| 502 | + border-top-left-radius: 0.5rem; | ||
| 503 | + border-top-right-radius: 0.5rem; | ||
| 504 | + } | ||
| 505 | + } | ||
| 506 | + .info-content-wrapper { | ||
| 507 | + box-shadow: 0px -3px 6px 0 rgba(241, 242, 248, 0.8); | ||
| 508 | + margin: 1rem; | ||
| 509 | + margin-top: 0; | ||
| 510 | + // padding: 1rem; | ||
| 511 | + border-bottom-left-radius: 0.5rem; | ||
| 512 | + border-bottom-right-radius: 0.5rem; | ||
| 513 | + background-color: white; | ||
| 514 | + .info-header { | ||
| 515 | + padding: 1rem 2rem 0; | ||
| 516 | + // display: flex; | ||
| 517 | + // justify-content: space-between; | ||
| 518 | + // align-items: center; | ||
| 519 | + .info-title { | ||
| 520 | + font-size: 1.25rem; | ||
| 521 | + margin-bottom: 0.5rem; | ||
| 522 | + } | ||
| 523 | + .info-sub-title { | ||
| 524 | + font-size: 0.85rem; | ||
| 525 | + color: #A0A8B1; | ||
| 526 | + line-height: 1.75; | ||
| 527 | + } | ||
| 528 | + .info-btn { | ||
| 529 | + width: 3rem; | ||
| 530 | + height: 1.5rem; | ||
| 531 | + border: 1px solid #DD7850; | ||
| 532 | + color: #DD7850; | ||
| 533 | + border-radius: 0.8rem; | ||
| 534 | + font-size: 0.85rem; | ||
| 535 | + text-align: center; | ||
| 536 | + line-height: 1.5rem; | ||
| 537 | + } | ||
| 538 | + } | ||
| 539 | + .info-content { | ||
| 540 | + color: #47525F; | ||
| 541 | + padding: 1rem; | ||
| 542 | + line-height: 1.75; | ||
| 543 | + p { | ||
| 544 | + line-height: 1.75; | ||
| 545 | + // padding: 0 0.85rem; | ||
| 546 | + text-align: justify; | ||
| 547 | + img { | ||
| 548 | + width: 100%; | ||
| 549 | + } | ||
| 550 | + } | ||
| 551 | + } | ||
| 552 | + .audio-wrapper { | ||
| 553 | + padding: 1rem; | ||
| 554 | + .audio-item { | ||
| 555 | + color: #47525F; | ||
| 556 | + display: flex; | ||
| 557 | + justify-content: space-between; | ||
| 558 | + align-items: center; | ||
| 559 | + padding: 1rem; | ||
| 560 | + background-color: #FFF; | ||
| 561 | + border-radius: 0.25rem; | ||
| 562 | + margin: 1rem; | ||
| 563 | + box-shadow: 0 0 0.5rem rgba(0, 0, 0, 0.1); | ||
| 564 | + &.click { | ||
| 565 | + border: 1px solid #DD7850; | ||
| 566 | + } | ||
| 567 | + .audio-icon { | ||
| 568 | + width: 2rem; | ||
| 569 | + height: 2rem; | ||
| 570 | + background-image: url('https://cdn.ipadbiz.cn/bieyuan/map/icon/audio_icon.png'); /* 使用上传的图标 */ | ||
| 571 | + background-size: cover; | ||
| 572 | + &.click { | ||
| 573 | + animation: pulse 1.5s infinite; | ||
| 574 | + } | ||
| 575 | + } | ||
| 576 | + | ||
| 577 | + @keyframes pulse { | ||
| 578 | + 0% { | ||
| 579 | + transform: scale(1); | ||
| 580 | + } | ||
| 581 | + 50% { | ||
| 582 | + transform: scale(1.2); | ||
| 583 | + } | ||
| 584 | + 100% { | ||
| 585 | + transform: scale(1); | ||
| 586 | + } | ||
| 587 | + } | ||
| 588 | + } | ||
| 589 | + } | ||
| 590 | + } | ||
| 591 | + .info-logo { | ||
| 592 | + display: flex; | ||
| 593 | + justify-content: center; | ||
| 594 | + margin: 3rem; | ||
| 595 | + } | ||
| 596 | + | ||
| 597 | + .van-tabs__wrap { | ||
| 598 | + border-bottom: 1px solid #F3F3F3; | ||
| 599 | + } | ||
| 600 | + | ||
| 601 | + .van-tabs__nav--line.van-tabs__nav--shrink { | ||
| 602 | + padding-left: 2rem; | ||
| 603 | + } | ||
| 604 | +} | ||
| 605 | + | ||
| 606 | +.van-back-top { | ||
| 607 | + background-color: #DD7850; | ||
| 608 | +} | ||
| 609 | +</style> |
src/views/checkin/info_w.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2024-09-15 22:08:49 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-02-10 16:11:41 | ||
| 5 | + * @FilePath: /map-demo/src/views/by/info_w.vue | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <div class="info-page"> | ||
| 10 | + <div> | ||
| 11 | + <van-config-provider :theme-vars="themeVars"> | ||
| 12 | + <van-swipe class="my-swipe" indicator-color="#DD7850" lazy-render :autoplay="5000"> | ||
| 13 | + <van-swipe-item v-for="image in images" :key="image"> | ||
| 14 | + <van-image fit="cover" width="100%" height="13rem" :src="image" /> | ||
| 15 | + </van-swipe-item> | ||
| 16 | + </van-swipe> | ||
| 17 | + </van-config-provider> | ||
| 18 | + </div> | ||
| 19 | + <div class="info-content-wrapper"> | ||
| 20 | + <div class="info-header"> | ||
| 21 | + <div> | ||
| 22 | + <p class="info-title">选佛场</p> | ||
| 23 | + <p class="info-sub-title">南楼2层</p> | ||
| 24 | + </div> | ||
| 25 | + <div @click="goTo()" class="info-btn">前往</div> | ||
| 26 | + </div> | ||
| 27 | + <div class="van-hairline--bottom"> | ||
| 28 | + <van-tabs v-model:active="active" color="#DD7850" title-active-color="#DD7850" sticky> | ||
| 29 | + <van-tab title="介 绍"> | ||
| 30 | + <div class="info-content"> | ||
| 31 | + <p style="line-height: 1.75; padding: 0 0.85rem; color: #47525F;">选佛场是一个宗教活动场所,集禅堂与讲堂功能于一体。其设计仿制古代石窟样式,把古代人修行的场所“石窟”搬进室内。禅堂内的释迦牟尼佛像,仿麦积山石窟第44号特窟“东方的微笑”的造型。禅堂设计自然古朴,匠心独运,星光、烛光、月光三光辉映,营造出“一个人不孤单,一千人不喧闹”的宁静祥和的氛围。禅堂可容纳千人,开展讲经、禅修、法会等多种活动,提供礼佛、供灯、静坐等体验。</p> | ||
| 32 | + <div class="van-hairline--bottom" style="margin: 1rem 0;"></div> | ||
| 33 | + <div style="padding: 1rem;"> | ||
| 34 | + <div style="color: #DD7850;">• 五方塔</div> | ||
| 35 | + <div style="color: #47525F; margin-top: 1rem; line-height: 1.75;">禅堂外的草坪,安立着大小不一五座佛塔。信众可绕塔或悬挂风铃祝愿祈福,在肃静庄严的氛围中得到佛力加持,自净其意,心想事成。</div> | ||
| 36 | + </div> | ||
| 37 | + </div> | ||
| 38 | + </van-tab> | ||
| 39 | + <van-tab title="故 事"> | ||
| 40 | + <div style="padding: 0 1rem;"> | ||
| 41 | + <div style="padding: 1rem;"> | ||
| 42 | + <div style="color: #DD7850;">• 选官何如选佛</div> | ||
| 43 | + </div> | ||
| 44 | + <div style="padding: 0 1rem;"> | ||
| 45 | + <van-image width="100%" height="11rem" fit="cover" src="https://cdn.ipadbiz.cn/bieyuan/map/Mix_20230612_201951.png" /> | ||
| 46 | + </div> | ||
| 47 | + <div style="padding: 1rem;"> | ||
| 48 | + <p style="color: #47525F; line-height: 1.75;">过去把禅堂叫作选佛场,意思是选择作佛的场所。这个典故与丹霞禅师有关。 <br />他原本是一个秀才,赴京赶考的途中遇到一位禅师,这位禅师跟他讲,选官何如选佛?考官还不如成佛利益更大。世间功名如过眼云烟,即便追求得到也是暂时利益,执著于此就会烦恼重重,甚至不断造业。而学佛修行,考佛就是要成佛,成就生命永恒的福祉。这是永久的利益,尽未来际的利益。每个生命原本具备觉悟的潜质,具有无尽的功德宝藏,取之不尽用之不竭。成佛,可以断除一切迷惑烦恼,可以彻底地开发我们生命的潜质,全然觉醒,这个利益无量无边。丹霞禅师深具慧根,一经点拨,马上出家。</p> | ||
| 49 | + </div> | ||
| 50 | + <div class="van-hairline--bottom" style="margin: 0 1rem;"></div> | ||
| 51 | + </div> | ||
| 52 | + <div style="padding: 0 1rem;"> | ||
| 53 | + <div style="padding: 1rem;"> | ||
| 54 | + <div style="color: #DD7850;">• 把洞窟搬进讲堂</div> | ||
| 55 | + </div> | ||
| 56 | + <div style="padding: 0 1rem;"> | ||
| 57 | + <van-image width="100%" height="11rem" fit="cover" src="https://cdn.ipadbiz.cn/bieyuan/map/Mix_20240815_211927.png" /> | ||
| 58 | + </div> | ||
| 59 | + <div style="padding: 1rem;"> | ||
| 60 | + <p style="color: #47525F; line-height: 1.75;">洞窟,是传统的佛教建筑形式,最早在印度盛行,古代僧人喜欢在崇山峻岭的幽僻处开凿洞窟,遁世修行。选佛场集禅堂与讲堂的功能于一体,把洞窟搬进讲堂,既有回归佛教本怀的宁静温暖,又体现出融入泰宁岩穴文化的祥和之气。</p> | ||
| 61 | + </div> | ||
| 62 | + <div class="van-hairline--bottom" style="margin: 0 1rem;"></div> | ||
| 63 | + </div> | ||
| 64 | + </van-tab> | ||
| 65 | + <van-tab title="体 验"> | ||
| 66 | + <div style="padding: 0 1rem;"> | ||
| 67 | + <div style="padding: 1rem;"> | ||
| 68 | + <div style="color: #DD7850;">• 供灯</div> | ||
| 69 | + <div style="color: #47525F; margin-top: 1rem; line-height: 1.75;">禅堂内自助供灯。</div> | ||
| 70 | + </div> | ||
| 71 | + <div style="padding: 0 1rem;"> | ||
| 72 | + <van-image width="100%" height="11rem" fit="cover" src="https://cdn.ipadbiz.cn/bieyuan/map/Mix_20240815_211927.png" /> | ||
| 73 | + </div> | ||
| 74 | + <div class="van-hairline--bottom" style="margin: 0 1rem;"></div> | ||
| 75 | + </div> | ||
| 76 | + <div class="audio-wrapper"> | ||
| 77 | + <div :class="['audio-item', play_audio_index === index ? 'click' : '']" v-for="(item, index) in audioList" :key="index"> | ||
| 78 | + <div>{{ item.text }}</div> | ||
| 79 | + <!-- <div :class="['audio-icon', play_audio_index === index ? 'click' : '']"></div> --> | ||
| 80 | + <van-icon @click="stopAudio(item, index)" v-if="item.play" size="2rem" name="stop-circle-o" color="#DD7850" /> | ||
| 81 | + <van-icon v-else @click="playAudio(item, index)" size="2rem" name="https://cdn.ipadbiz.cn/bieyuan/map/icon/audio_icon.png" /> | ||
| 82 | + </div> | ||
| 83 | + </div> | ||
| 84 | + <div style="padding: 0 1rem;"> | ||
| 85 | + <img src="https://cdn.ipadbiz.cn/bieyuan/map/xcx.png" style="width: 100%;"> | ||
| 86 | + </div> | ||
| 87 | + </van-tab> | ||
| 88 | + </van-tabs> | ||
| 89 | + </div> | ||
| 90 | + </div> | ||
| 91 | + <!-- <div style="display: flex; justify-content: center; margin: 3rem;"> | ||
| 92 | + <van-image | ||
| 93 | + width="3rem" | ||
| 94 | + height="3rem" | ||
| 95 | + fit="contain" | ||
| 96 | + src="https://cdn.ipadbiz.cn/bieyuan/map/icon/scan_logo.png" | ||
| 97 | + /> | ||
| 98 | + </div> --> | ||
| 99 | + </div> | ||
| 100 | +</template> | ||
| 101 | + | ||
| 102 | +<script setup> | ||
| 103 | +import { ref, watch } from 'vue' | ||
| 104 | +import { useRoute, useRouter } from 'vue-router' | ||
| 105 | + | ||
| 106 | +import { storeToRefs } from 'pinia' | ||
| 107 | +import { mainStore } from '@/store'; | ||
| 108 | + | ||
| 109 | +const store = mainStore(); | ||
| 110 | +const { audio_status, audio_entity } = storeToRefs(store); | ||
| 111 | + | ||
| 112 | +const $route = useRoute(); | ||
| 113 | +const $router = useRouter(); | ||
| 114 | + | ||
| 115 | +const themeVars = ref({ | ||
| 116 | + swipeIndicatorInactiveBackground: '#fff', | ||
| 117 | +}); | ||
| 118 | + | ||
| 119 | +const images = ref([ | ||
| 120 | + 'https://cdn.ipadbiz.cn/bieyuan/map/swiper_img.png', | ||
| 121 | + 'https://cdn.ipadbiz.cn/bieyuan/map/Mix_20230612_201951.png', | ||
| 122 | + 'https://cdn.ipadbiz.cn/bieyuan/map/Mix_20240815_211927.png', | ||
| 123 | +]); | ||
| 124 | + | ||
| 125 | +const active = ref(0); | ||
| 126 | +const play_audio_index = ref(null); | ||
| 127 | + | ||
| 128 | +const audioList = ref([{ | ||
| 129 | + text: '5分钟观呼吸', | ||
| 130 | + 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', | ||
| 131 | + play: false, | ||
| 132 | +}, { | ||
| 133 | + text: '10分钟正念静坐', | ||
| 134 | + 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', | ||
| 135 | + play: false, | ||
| 136 | +}, { | ||
| 137 | + text: '15分钟正念静坐', | ||
| 138 | + 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', | ||
| 139 | + play: false, | ||
| 140 | +}]) | ||
| 141 | + | ||
| 142 | +const playAudio = (item, index) => { | ||
| 143 | + audioList.value.forEach(item => item.play = false); | ||
| 144 | + audio.value.src = item.src; | ||
| 145 | + play_audio_index.value = index; | ||
| 146 | + let play_status = audio.value.play() // 播放 | ||
| 147 | + if (play_status) { | ||
| 148 | + console.warn('start'); | ||
| 149 | + // if (audio_status.value === 'play') { | ||
| 150 | + // audio_entity.value.pause(); | ||
| 151 | + // } | ||
| 152 | + play_status.then(() => { | ||
| 153 | + console.warn('success'); | ||
| 154 | + item.play = true; | ||
| 155 | + // 存放到pinia里面控制 | ||
| 156 | + // store.changeAudioSrc(audio.value.src); | ||
| 157 | + // store.changeAudioStatus('play'); | ||
| 158 | + }).catch((e) => { | ||
| 159 | + // 失败 | ||
| 160 | + console.log('Operation is too fast, audio play fails') | ||
| 161 | + }) | ||
| 162 | + } | ||
| 163 | +} | ||
| 164 | + | ||
| 165 | +const stopAudio = (item, index) => { | ||
| 166 | + item.play = false; | ||
| 167 | + audio.value.pause(); | ||
| 168 | +} | ||
| 169 | + | ||
| 170 | +const audio = ref(new Audio()); | ||
| 171 | + | ||
| 172 | +onMounted(() => { | ||
| 173 | + // 存放到pinia里面控制 | ||
| 174 | + store.changeAudio(audio.value); | ||
| 175 | + // store.changeAudioStatus('pause'); | ||
| 176 | +}) | ||
| 177 | + | ||
| 178 | +onUnmounted(() => { | ||
| 179 | + audio.value.pause(); | ||
| 180 | + store.changeAudioStatus('pause'); | ||
| 181 | +}) | ||
| 182 | + | ||
| 183 | +const audio_play = (src, index) => { | ||
| 184 | + audio.value.src = src; | ||
| 185 | +} | ||
| 186 | + | ||
| 187 | +const outerStopAudio = () => { | ||
| 188 | + audio.value.pause(); | ||
| 189 | +} | ||
| 190 | + | ||
| 191 | +const emit = defineEmits(["closeFloat", 'route']); | ||
| 192 | +const goTo = () => { // 打开标记地图显示 | ||
| 193 | + if ($router.currentRoute.value.path === '/by/info') { // 详情页 | ||
| 194 | + $router.push({ | ||
| 195 | + path: '/by', | ||
| 196 | + query: { | ||
| 197 | + id: $route.query.id, | ||
| 198 | + marker_id: '12345' | ||
| 199 | + } | ||
| 200 | + }) | ||
| 201 | + } else { // 地图页 | ||
| 202 | + // | ||
| 203 | + emit("closeFloat", false); | ||
| 204 | + // | ||
| 205 | + emit("route", 'marker_id'); | ||
| 206 | + } | ||
| 207 | +} | ||
| 208 | + | ||
| 209 | +const voicePause = () => { | ||
| 210 | + audio.value.pause(); | ||
| 211 | + store.changeAudioStatus('pause'); | ||
| 212 | +} | ||
| 213 | + | ||
| 214 | +watch( | ||
| 215 | + () => audio_status.value, | ||
| 216 | + (v) => { | ||
| 217 | + if (v === 'pause') { | ||
| 218 | + voicePause(); | ||
| 219 | + audioList.value.forEach(item => item.play = false); | ||
| 220 | + } | ||
| 221 | + }, | ||
| 222 | + { immediate: true } | ||
| 223 | +); | ||
| 224 | + | ||
| 225 | +defineExpose({ | ||
| 226 | + outerStopAudio | ||
| 227 | +}) | ||
| 228 | +</script> | ||
| 229 | + | ||
| 230 | +<style lang="less"> | ||
| 231 | +.info-page { | ||
| 232 | + background-color: #EBEBEB; | ||
| 233 | + height: 100vh; | ||
| 234 | + overflow: scroll; | ||
| 235 | + position: relative; | ||
| 236 | + .info-content-wrapper { | ||
| 237 | + // position: absolute; | ||
| 238 | + // top: 14.9rem; | ||
| 239 | + margin: 1rem; | ||
| 240 | + margin-top: 0; | ||
| 241 | + // padding: 1rem; | ||
| 242 | + border-radius: 0.5rem; | ||
| 243 | + background-color: white; | ||
| 244 | + .info-header { | ||
| 245 | + padding: 1rem 2rem 0; | ||
| 246 | + display: flex; | ||
| 247 | + justify-content: space-between; | ||
| 248 | + // align-items: center; | ||
| 249 | + .info-title { | ||
| 250 | + font-size: 1.25rem; | ||
| 251 | + margin-bottom: 0.5rem; | ||
| 252 | + } | ||
| 253 | + .info-sub-title { | ||
| 254 | + font-size: 0.85rem; | ||
| 255 | + color: #A0A8B1; | ||
| 256 | + } | ||
| 257 | + .info-btn { | ||
| 258 | + width: 3rem; | ||
| 259 | + height: 1.5rem; | ||
| 260 | + border: 1px solid #DD7850; | ||
| 261 | + color: #DD7850; | ||
| 262 | + border-radius: 0.8rem; | ||
| 263 | + font-size: 0.85rem; | ||
| 264 | + text-align: center; | ||
| 265 | + line-height: 1.5rem; | ||
| 266 | + } | ||
| 267 | + } | ||
| 268 | + .info-content { | ||
| 269 | + padding: 1rem; | ||
| 270 | + } | ||
| 271 | + .audio-wrapper { | ||
| 272 | + padding: 1rem; | ||
| 273 | + .audio-item { | ||
| 274 | + color: #47525F; | ||
| 275 | + display: flex; | ||
| 276 | + justify-content: space-between; | ||
| 277 | + align-items: center; | ||
| 278 | + padding: 1rem; | ||
| 279 | + background-color: #FFF; | ||
| 280 | + border-radius: 0.25rem; | ||
| 281 | + margin: 1rem; | ||
| 282 | + box-shadow: 0 0 0.5rem rgba(0, 0, 0, 0.1); | ||
| 283 | + &.click { | ||
| 284 | + border: 1px solid #DD7850; | ||
| 285 | + } | ||
| 286 | + .audio-icon { | ||
| 287 | + width: 2rem; | ||
| 288 | + height: 2rem; | ||
| 289 | + background-image: url('https://cdn.ipadbiz.cn/bieyuan/map/icon/audio_icon.png'); /* 使用上传的图标 */ | ||
| 290 | + background-size: cover; | ||
| 291 | + &.click { | ||
| 292 | + animation: pulse 1.5s infinite; | ||
| 293 | + } | ||
| 294 | + } | ||
| 295 | + | ||
| 296 | + @keyframes pulse { | ||
| 297 | + 0% { | ||
| 298 | + transform: scale(1); | ||
| 299 | + } | ||
| 300 | + 50% { | ||
| 301 | + transform: scale(1.2); | ||
| 302 | + } | ||
| 303 | + 100% { | ||
| 304 | + transform: scale(1); | ||
| 305 | + } | ||
| 306 | + } | ||
| 307 | + } | ||
| 308 | + } | ||
| 309 | + } | ||
| 310 | +} | ||
| 311 | +</style> |
src/views/checkin/map.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2023-05-19 14:54:27 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-08-08 14:51:23 | ||
| 5 | + * @FilePath: /map-demo/src/views/by/map.vue | ||
| 6 | + * @Description: 公众地图主体页面 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <div ref="root" style="height: 100vh; position: relative; overflow: hidden;"> | ||
| 10 | + <div id="container"></div> | ||
| 11 | + <!-- 添加导航面板容器 --> | ||
| 12 | + <div id="walking-panel" style="position: absolute; bottom: 1rem; left: 1rem; padding: 1rem;"></div> | ||
| 13 | + <div style="position: absolute; top: 2rem; right: 1rem; display: flex; flex-direction: column;"> | ||
| 14 | + <!-- <van-icon size="2rem" name="search" color="#DD7850" style="margin-bottom: 1rem;" /> --> | ||
| 15 | + <van-image | ||
| 16 | + width="2rem" | ||
| 17 | + height="2rem" | ||
| 18 | + fit="contain" | ||
| 19 | + src="https://cdn.ipadbiz.cn/bieyuan/map/icon/NAV@3x.png" | ||
| 20 | + /> | ||
| 21 | + </div> | ||
| 22 | + <div v-if="data_logo" style="position: absolute; top: 2rem; left: calc(50% - 1.5rem); opacity: 0.5;"> | ||
| 23 | + <van-image | ||
| 24 | + width="3rem" | ||
| 25 | + height="3rem" | ||
| 26 | + fit="contain" | ||
| 27 | + :src="data_logo" | ||
| 28 | + /> | ||
| 29 | + </div> | ||
| 30 | + <div @click="scanQrcode" style="position: absolute; bottom: 1rem; left: calc(50% - 2.5rem);"> | ||
| 31 | + <van-image | ||
| 32 | + width="5rem" | ||
| 33 | + height="5rem" | ||
| 34 | + fit="contain" | ||
| 35 | + src="https://cdn.ipadbiz.cn/bieyuan/map/icon/scan@3x.png" | ||
| 36 | + /> | ||
| 37 | + </div> | ||
| 38 | + | ||
| 39 | + <van-config-provider :theme-vars="themeVars"> | ||
| 40 | + <van-floating-panel v-model:height="info_height" :anchors="anchors" @height-change="onHeightChange"> | ||
| 41 | + <!-- <template #header> | ||
| 42 | + <div class="custom-header"> | ||
| 43 | + <h3>自定义标题</h3> | ||
| 44 | + <button @click="show = false">关闭</button> | ||
| 45 | + </div> | ||
| 46 | + </template> --> | ||
| 47 | + <page-info ref="pageInfo" :info="itemInfo" :height="info_height" @close-float="onCloseFloat" @route="onRoute" @walk-route="onWalkRoute"></page-info> | ||
| 48 | + <!-- <div v-if="showClose" @click="closeFloatPanel" class="close-float-panel"> | ||
| 49 | + <van-icon name="arrow-left" color="#FFF" size="1.5rem" /> | ||
| 50 | + </div> --> | ||
| 51 | + </van-floating-panel> | ||
| 52 | + </van-config-provider> | ||
| 53 | + | ||
| 54 | + <div v-if="!show_walk_route" @click="removeSafeRoute({ name: '参观路径' })" class="walk-nav-text"> | ||
| 55 | + 关闭步行导航 | ||
| 56 | + </div> | ||
| 57 | + | ||
| 58 | + | ||
| 59 | + <!-- 新增关闭导航按钮 --> | ||
| 60 | + <div v-if="walking && !show_walk_route" class="walk-nav-text" @click="closeWalkingRoute"> | ||
| 61 | + 关闭步行导航 | ||
| 62 | + </div> | ||
| 63 | + | ||
| 64 | + <van-dialog v-model:show="dialog_show" title="温馨提示"> | ||
| 65 | + <div style="padding: 1rem; text-align: center;">{{ dialog_text }}</div> | ||
| 66 | + </van-dialog> | ||
| 67 | + | ||
| 68 | + <!-- 背景音乐控制 --> | ||
| 69 | + <!-- <audioBackground1></audioBackground1> --> | ||
| 70 | + | ||
| 71 | + <div class="operate-bar-wrapper"> | ||
| 72 | + <div class="box-wrapper"> | ||
| 73 | + <div v-if="open_current_location" class="item" @click="handleLocation(true)"> | ||
| 74 | + <van-icon name="https://cdn.ipadbiz.cn/xys/map/%E5%AE%9A%E4%BD%8Dloc@2x.png" size="1.5rem" | ||
| 75 | + style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);;" /> | ||
| 76 | + </div> | ||
| 77 | + <div v-else class="item" @click="handleLocation(false)"> | ||
| 78 | + <van-icon name="https://cdn.ipadbiz.cn/xys/map/%E5%AE%9A%E4%BD%8Dloc@2x.png" size="1.5rem" | ||
| 79 | + style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);" /> | ||
| 80 | + </div> | ||
| 81 | + </div> | ||
| 82 | + </div> | ||
| 83 | + | ||
| 84 | + <van-toast v-model:show="show_toast" style="padding: 0"> | ||
| 85 | + <template #message> | ||
| 86 | + <p style="padding: 0.5rem 1rem;">{{ toast_text }}</p> | ||
| 87 | + </template> | ||
| 88 | + </van-toast> | ||
| 89 | + </div> | ||
| 90 | +</template> | ||
| 91 | + | ||
| 92 | +<script> | ||
| 93 | +import "@vant/touch-emulator"; | ||
| 94 | +// import { mapState } from 'vuex' | ||
| 95 | +import coord from '@/common/map_data' | ||
| 96 | +import my_router from '@/common/my_router' | ||
| 97 | +import _ from 'lodash'; | ||
| 98 | +import $ from 'jquery'; | ||
| 99 | +import { useRect } from '@vant/use'; | ||
| 100 | +import { mapAPI } from '@/api/map.js' | ||
| 101 | +import wx from 'weixin-js-sdk' | ||
| 102 | +import pageInfo from '@/views/by/info.vue' | ||
| 103 | +import audioBackground1 from '@/components/audioBackground1.vue' | ||
| 104 | +import { mapState, mapActions } from 'pinia' | ||
| 105 | +import { mainStore } from '@/store' | ||
| 106 | +import { parseQueryString } from '@/utils/tools' | ||
| 107 | +import AMapLoader from '@amap/amap-jsapi-loader' | ||
| 108 | +import { mapAudioAPI } from '@/api/map.js' | ||
| 109 | + | ||
| 110 | +const GPS = { | ||
| 111 | + PI: 3.14159265358979324, | ||
| 112 | + x_pi: 3.14159265358979324 * 3000.0 / 180.0, | ||
| 113 | + delta: function (lat, lon) { | ||
| 114 | + var a = 6378245.0; // a: 卫星椭球坐标投影到平面地图坐标系的投影因子。 | ||
| 115 | + var ee = 0.00669342162296594323; // ee: 椭球的偏心率。 | ||
| 116 | + var dLat = this.transformLat(lon - 105.0, lat - 35.0); | ||
| 117 | + var dLon = this.transformLon(lon - 105.0, lat - 35.0); | ||
| 118 | + var radLat = lat / 180.0 * this.PI; | ||
| 119 | + var magic = Math.sin(radLat); | ||
| 120 | + magic = 1 - ee * magic * magic; | ||
| 121 | + var sqrtMagic = Math.sqrt(magic); | ||
| 122 | + dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * this.PI); | ||
| 123 | + dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * this.PI); | ||
| 124 | + return { | ||
| 125 | + 'lat': dLat, | ||
| 126 | + 'lon': dLon | ||
| 127 | + }; | ||
| 128 | + }, | ||
| 129 | + //WGS-84 to GCJ-02 | ||
| 130 | + gcj_encrypt: function (wgsLat, wgsLon) { | ||
| 131 | + if (this.outOfChina(wgsLat, wgsLon)) | ||
| 132 | + return { | ||
| 133 | + 'lat': wgsLat, | ||
| 134 | + 'lon': wgsLon | ||
| 135 | + }; | ||
| 136 | + | ||
| 137 | + var d = this.delta(wgsLat, wgsLon); | ||
| 138 | + return { | ||
| 139 | + 'lat': wgsLat + d.lat, | ||
| 140 | + 'lon': wgsLon + d.lon | ||
| 141 | + }; | ||
| 142 | + }, | ||
| 143 | + outOfChina: function (lat, lon) { | ||
| 144 | + if (lon < 72.004 || lon > 137.8347) | ||
| 145 | + return true; | ||
| 146 | + if (lat < 0.8293 || lat > 55.8271) | ||
| 147 | + return true; | ||
| 148 | + return false; | ||
| 149 | + }, | ||
| 150 | + transformLat: function (x, y) { | ||
| 151 | + var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x)); | ||
| 152 | + ret += (20.0 * Math.sin(6.0 * x * this.PI) + 20.0 * Math.sin(2.0 * x * this.PI)) * 2.0 / 3.0; | ||
| 153 | + ret += (20.0 * Math.sin(y * this.PI) + 40.0 * Math.sin(y / 3.0 * this.PI)) * 2.0 / 3.0; | ||
| 154 | + ret += (160.0 * Math.sin(y / 12.0 * this.PI) + 320 * Math.sin(y * this.PI / 30.0)) * 2.0 / 3.0; | ||
| 155 | + return ret; | ||
| 156 | + }, | ||
| 157 | + transformLon: function (x, y) { | ||
| 158 | + var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x)); | ||
| 159 | + ret += (20.0 * Math.sin(6.0 * x * this.PI) + 20.0 * Math.sin(2.0 * x * this.PI)) * 2.0 / 3.0; | ||
| 160 | + ret += (20.0 * Math.sin(x * this.PI) + 40.0 * Math.sin(x / 3.0 * this.PI)) * 2.0 / 3.0; | ||
| 161 | + ret += (150.0 * Math.sin(x / 12.0 * this.PI) + 300.0 * Math.sin(x / 30.0 * this.PI)) * 2.0 / 3.0; | ||
| 162 | + return ret; | ||
| 163 | + } | ||
| 164 | +}; | ||
| 165 | + | ||
| 166 | +// 关键安全配置 | ||
| 167 | +window._AMapSecurityConfig = { | ||
| 168 | + securityJsCode: 'ac1a3a5858d74b7d6c50b6858100aa12', // 替换为你的密钥 | ||
| 169 | +} | ||
| 170 | + | ||
| 171 | +export default { | ||
| 172 | + components: { pageInfo, audioBackground1 }, | ||
| 173 | + data() { | ||
| 174 | + return { | ||
| 175 | + map: '', | ||
| 176 | + geolocation: '', | ||
| 177 | + current_lng: '', | ||
| 178 | + current_lat: '', | ||
| 179 | + dialog_show: false, | ||
| 180 | + dialog_text: '', | ||
| 181 | + location_marker: '', | ||
| 182 | + itemInfo: {}, | ||
| 183 | + navBarList: [], | ||
| 184 | + navList: [], | ||
| 185 | + navKey: '', | ||
| 186 | + markerSum: [], // marker合集 | ||
| 187 | + mapTiles: [], | ||
| 188 | + data_center: [], // 接口获取-地图中心点 | ||
| 189 | + data_zoom: '', // 接口获取-地图默认缩放 | ||
| 190 | + data_zooms: '', // 接口获取-地图默认缩放范围 | ||
| 191 | + data_rotation: 0, // 接口获取-地图旋转角度 | ||
| 192 | + data_paths: {}, // 接口获取-地图导航路径 | ||
| 193 | + data_path_list: [], // 接口获取-地图导航路径 | ||
| 194 | + info_height: 0, | ||
| 195 | + anchors: [0, (0.65 * window.innerHeight), (1 * window.innerHeight)], | ||
| 196 | + themeVars: { | ||
| 197 | + floatingPanelHeaderHeight: 0, | ||
| 198 | + floatingPanelBorderRadius: '1.25rem' | ||
| 199 | + }, | ||
| 200 | + showClose: false, | ||
| 201 | + markerStyle2: { // 选中 | ||
| 202 | + //设置文本样式,Object 同 css 样式表 | ||
| 203 | + "padding": ".5rem .2rem .5rem .2rem", | ||
| 204 | + // "margin-bottom": "1rem", | ||
| 205 | + "border-color": "#DD7850", | ||
| 206 | + "border-radius": ".25rem", | ||
| 207 | + "background-color": "#FFF", | ||
| 208 | + // "width": "1rem", | ||
| 209 | + // "border-width": 0, | ||
| 210 | + // "box-shadow": "0 2px 6px 0 rgba(114, 124, 245, .5)", | ||
| 211 | + // "text-align": "center", | ||
| 212 | + "font-size": "0.8rem", | ||
| 213 | + "color": "#DD7850", | ||
| 214 | + "writing-mode": "vertical-rl", | ||
| 215 | + "text-orientation": "mixed", | ||
| 216 | + "display": "flex", | ||
| 217 | + "justify-content": "center", | ||
| 218 | + "align-items": "center", | ||
| 219 | + }, | ||
| 220 | + markerStyle1: { // 未选中 | ||
| 221 | + //设置文本样式,Object 同 css 样式表 | ||
| 222 | + "padding": ".5rem .2rem .5rem .2rem", | ||
| 223 | + // "margin-bottom": "1rem", | ||
| 224 | + "border-color": "#fcfbfa", | ||
| 225 | + "border-radius": ".25rem", | ||
| 226 | + "background-color": "#DD7850", | ||
| 227 | + // "width": "1rem", | ||
| 228 | + // "border-width": 0, | ||
| 229 | + // "box-shadow": "0 2px 6px 0 rgba(114, 124, 245, .5)", | ||
| 230 | + // "text-align": "center", | ||
| 231 | + "font-size": "0.8rem", | ||
| 232 | + "color": "white", | ||
| 233 | + "writing-mode": "vertical-rl", | ||
| 234 | + "text-orientation": "mixed", | ||
| 235 | + "display": "flex", | ||
| 236 | + "justify-content": "center", | ||
| 237 | + "align-items": "center", | ||
| 238 | + }, | ||
| 239 | + markerStyle2_horizontal: { // 选中 | ||
| 240 | + //设置文本样式,Object 同 css 样式表 | ||
| 241 | + "padding": ".2rem .5rem .2rem .5rem", | ||
| 242 | + // "margin-bottom": "1rem", | ||
| 243 | + "border-color": "#DD7850", | ||
| 244 | + "border-radius": ".25rem", | ||
| 245 | + "background-color": "#FFF", | ||
| 246 | + // "width": "1rem", | ||
| 247 | + // "border-width": 0, | ||
| 248 | + // "box-shadow": "0 2px 6px 0 rgba(114, 124, 245, .5)", | ||
| 249 | + // "text-align": "center", | ||
| 250 | + "font-size": "0.8rem", | ||
| 251 | + "color": "#DD7850", | ||
| 252 | + "writing-mode": "horizontal", | ||
| 253 | + "text-orientation": "mixed", | ||
| 254 | + "display": "flex", | ||
| 255 | + "justify-content": "center", | ||
| 256 | + "align-items": "center", | ||
| 257 | + }, | ||
| 258 | + markerStyle1_horizontal: { // 未选中 | ||
| 259 | + //设置文本样式,Object 同 css 样式表 | ||
| 260 | + "padding": ".2rem .5rem .2rem .5rem", | ||
| 261 | + // "margin-bottom": "1rem", | ||
| 262 | + "border-color": "#fcfbfa", | ||
| 263 | + "border-radius": ".25rem", | ||
| 264 | + "background-color": "#DD7850", | ||
| 265 | + // "width": "1rem", | ||
| 266 | + // "border-width": 0, | ||
| 267 | + // "box-shadow": "0 2px 6px 0 rgba(114, 124, 245, .5)", | ||
| 268 | + // "text-align": "center", | ||
| 269 | + "font-size": "0.8rem", | ||
| 270 | + "color": "white", | ||
| 271 | + "writing-mode": "horizontal", | ||
| 272 | + "text-orientation": "mixed", | ||
| 273 | + "display": "flex", | ||
| 274 | + "justify-content": "center", | ||
| 275 | + "align-items": "center", | ||
| 276 | + }, | ||
| 277 | + current_safe_route: [], | ||
| 278 | + route_safe_marker: [], | ||
| 279 | + show_walk_route: true, | ||
| 280 | + open_current_location: true, | ||
| 281 | + show_toast: false, | ||
| 282 | + toast_text: '', | ||
| 283 | + data_logo: '', | ||
| 284 | + data_layers: [], | ||
| 285 | + point_range: [ | ||
| 286 | + [117.044223,26.835105], [117.044227,26.842448], [117.0552,26.842452], [117.055195,26.8351] | ||
| 287 | + ], | ||
| 288 | + walking: '', | ||
| 289 | + } | ||
| 290 | + }, | ||
| 291 | + async mounted() { | ||
| 292 | + const AMap = await AMapLoader.load({ | ||
| 293 | + key: '17b8fc386104b89db88b60b049a6dbce', // 控制台获取 | ||
| 294 | + version: '2.0', // 指定API版本 | ||
| 295 | + plugins: ['AMap.ElasticMarker','AMap.ImageLayer','AMap.ToolBar','AMap.IndoorMap','AMap.Walking','AMap.Geolocation'] // 必须加载步行导航插件 | ||
| 296 | + }) | ||
| 297 | + const code = this.$route.query.id; | ||
| 298 | + const { data } = await mapAPI({ i: code }); | ||
| 299 | + this.navBarList = data.list; // 底部导航条 | ||
| 300 | + this.mapTiles = data.level; // 获取图层 | ||
| 301 | + this.navKey = data.list.length ? data.list[0]['id'] : 0; // 默认选中 第一个 id | ||
| 302 | + this.navList = data.list.length ? data.list.filter(item => item.id === this.navKey)[0]['list'] : []; // 返回默认选中项的实体信息 | ||
| 303 | + this.data_center = data.map.center.map(item => Number(item)); // 地图中心点 | ||
| 304 | + this.data_zoom = data.map.zoom; // 地图默认缩放 | ||
| 305 | + this.data_rotation = data.map.rotation; // 地图旋转角度 | ||
| 306 | + this.data_zooms = data.map.zooms.map(item => Number(item)); // 地图默认缩放范围 | ||
| 307 | + this.data_paths = data.map.path ? data.map.path : {}; // 地图默认导航路径 | ||
| 308 | + this.data_logo = data.map.map_logo ? data.map.map_logo : ''; // 地图logo | ||
| 309 | + this.point_range = data.map.map_range ? data.map.map_range : []; // 地图定位范围 | ||
| 310 | + if (data.map.map_layers) { // 地图默认图层 | ||
| 311 | + if (data.map.map_layers === 'satellite') { // 卫星和路网 | ||
| 312 | + this.data_layers = [new AMap.TileLayer.Satellite(), new AMap.TileLayer.RoadNet()] | ||
| 313 | + } else { // 平面图 | ||
| 314 | + this.data_layers = []; | ||
| 315 | + } | ||
| 316 | + } | ||
| 317 | + if (data.map.path) { | ||
| 318 | + for (const key in data.map.path) { | ||
| 319 | + const element = data.map.path[key]; | ||
| 320 | + this.data_path_list.push({ | ||
| 321 | + name: key, | ||
| 322 | + path: element, | ||
| 323 | + status: true | ||
| 324 | + }) | ||
| 325 | + } | ||
| 326 | + } | ||
| 327 | + // 地图标题 | ||
| 328 | + document.title = data.map.map_title; | ||
| 329 | + // 微信分享 | ||
| 330 | + const shareData = { | ||
| 331 | + title: data.map.map_title, // 分享标题 | ||
| 332 | + desc: '别院地图', // 分享描述 | ||
| 333 | + link: location.origin + location.pathname + location.hash, // 分享链接,该链接域名或路径必须与当前页面对应的公众号 JS 安全域名一致 | ||
| 334 | + imgUrl: '', // 分享图标 | ||
| 335 | + success: function () { | ||
| 336 | + // console.warn('设置成功'); | ||
| 337 | + } | ||
| 338 | + } | ||
| 339 | + // 分享好友(微信好友或qq好友) | ||
| 340 | + wx.updateAppMessageShareData(shareData); | ||
| 341 | + // 分享到朋友圈或qq空间 | ||
| 342 | + wx.updateTimelineShareData(shareData); | ||
| 343 | + // 分享到腾讯微博 | ||
| 344 | + wx.onMenuShareWeibo(shareData); | ||
| 345 | + // 初始化地图 | ||
| 346 | + this.initMap(); | ||
| 347 | + // this.setMapBoundary(); | ||
| 348 | + // 使用之前获取当前地址,判断当前是否能够获取经纬度 | ||
| 349 | + // wx.getLocation({ | ||
| 350 | + // type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02' | ||
| 351 | + // success: (res) => { | ||
| 352 | + // var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90 | ||
| 353 | + // var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。 | ||
| 354 | + // var speed = res.speed; // 速度,以米/每秒计 | ||
| 355 | + // var accuracy = res.accuracy; // 位置精度 | ||
| 356 | + // this.current_lng = GPS.gcj_encrypt(latitude, longitude).lon; | ||
| 357 | + // this.current_lat = GPS.gcj_encrypt(latitude, longitude).lat; | ||
| 358 | + // }, | ||
| 359 | + // }); | ||
| 360 | + // 设置贴片地图 | ||
| 361 | + this.setTitleLayer(); | ||
| 362 | + // 地图标题 | ||
| 363 | + document.title = data.map.map_title; | ||
| 364 | + // | ||
| 365 | + // setTimeout(() => { | ||
| 366 | + // this.info_height = (0.5 * window.innerHeight); | ||
| 367 | + // // 浮动面板样式 | ||
| 368 | + // $('.van-floating-panel__content').css('borderRadius', '1.5rem'); | ||
| 369 | + // }, 2000); | ||
| 370 | + // 初始化步行导航插件时指定面板容器 | ||
| 371 | + this.walking = new AMap.Walking({ | ||
| 372 | + map: this.map, | ||
| 373 | + // panel: 'walking-panel', // 必须指定存在的DOM元素ID | ||
| 374 | + hideMarkers: false, // 设置隐藏路径规划的起始点图标 | ||
| 375 | + isOutline: true, // 使用map属性时,绘制的规划线路是否显示描边 | ||
| 376 | + autoFitView: true, // 是否自动调整地图视野到显示的路线 | ||
| 377 | + }); | ||
| 378 | + }, | ||
| 379 | + watch: { | ||
| 380 | + // // 监听 $route 对象的 query 属性 | ||
| 381 | + // '$route.query': { | ||
| 382 | + // handler(newQuery, oldQuery) { | ||
| 383 | + // if (newQuery.marker_id) { | ||
| 384 | + | ||
| 385 | + // } | ||
| 386 | + // }, | ||
| 387 | + // immediate: true, // 设置为 true,确保在初始化时也执行一次 handler | ||
| 388 | + // deep: true // 如果 query 是嵌套对象,可以设置 deep 监听深层变化 | ||
| 389 | + // } | ||
| 390 | + }, | ||
| 391 | + computed: { | ||
| 392 | + ...mapState(mainStore, ['audio_entity', 'audio_src', 'audio_status']) | ||
| 393 | + }, | ||
| 394 | + methods: { | ||
| 395 | + ...mapActions(mainStore, ['changeAudio', 'changeAudioSrc', 'changeAudioStatus']), | ||
| 396 | + initMap() { | ||
| 397 | + // 初始化地图 | ||
| 398 | + this.map = new AMap.Map('container', { | ||
| 399 | + viewMode: '2D', // 设置地图模式 | ||
| 400 | + turboMode: false, | ||
| 401 | + showIndoorMap: false, | ||
| 402 | + defaultCursor: 'pointer', // 地图默认鼠标样式 | ||
| 403 | + showBuildingBlock: false, // 是否展示地图 3D 楼块 | ||
| 404 | + zooms: this.data_zooms, // 地图显示的缩放级别范围, 默认为 [2, 20] ,取值范围 [2 ~ 30] | ||
| 405 | + showLabel: true, // 是否展示地图文字和 POI 信息 | ||
| 406 | + zoom: this.data_zoom, // 设置地图显示的缩放级别 | ||
| 407 | + pitch: 0, // 俯仰角度,默认 0,最大值根据地图当前 zoom 级别不断增大,2D地图下无效 。 | ||
| 408 | + rotation: this.data_rotation, // 地图顺时针旋转角度,取值范围 [0-360] ,默认值:0 | ||
| 409 | + center: this.data_center, // 设置地图中心点坐标 | ||
| 410 | + forceVector: false, | ||
| 411 | + // rotateEnable: true, | ||
| 412 | + layers: this.data_layers, | ||
| 413 | + features: ['bg', 'road'], // 设置地图上显示的元素种类 | ||
| 414 | + animateEnable: false, // 地图平移过程中是否使用动画 | ||
| 415 | + resizeEnable: true, | ||
| 416 | + WebGLParams: { // 新增WebGL优化参数 | ||
| 417 | + preserveDrawingBuffer: true, | ||
| 418 | + antialias: true, | ||
| 419 | + stencil: true, | ||
| 420 | + alpha: true | ||
| 421 | + }, | ||
| 422 | + optimizeTileStrategy: true, // 开启瓦片优化 | ||
| 423 | + autoRendering: false // 关闭自动渲染 | ||
| 424 | + }); | ||
| 425 | + // 添加地图点击事件 | ||
| 426 | + this.map.on("click", this.showInfoClick); | ||
| 427 | + // 加载景点图层 | ||
| 428 | + this.navKey && this.loadMaker(this.navKey); | ||
| 429 | + // | ||
| 430 | + this.map.setRotation(this.data_rotation, true); | ||
| 431 | + }, | ||
| 432 | + loadMaker(id) { | ||
| 433 | + var zoomStyleMapping = { 14: 0, 15: 0, 16: 0, 17: 0, 18: 0, 19: 0, 20: 0 }; | ||
| 434 | + const entity_info = this.navBarList.filter(item => item.id === id)[0]['list']; | ||
| 435 | + this.markerSum = []; | ||
| 436 | + _.each(entity_info, (x, i) => { | ||
| 437 | + let marker_icon = ''; | ||
| 438 | + if (entity_info[i].window_type === 'warn' && entity_info[i].details.length === 1) { // 如果是预警类型并且内部预警项目只有一个取details第一个icon | ||
| 439 | + marker_icon = entity_info[i].details[0]['icon']; | ||
| 440 | + } else { | ||
| 441 | + marker_icon = entity_info[i].icon; | ||
| 442 | + } | ||
| 443 | + let text_direction = entity_info[i]?.writing_mode === 'vertical' ? 'vertical' : 'horizontal'; | ||
| 444 | + let textMarker = new AMap.Text({ | ||
| 445 | + zooms: [18, 20], // 点标记显示的层级范围,超过范围不显示。 | ||
| 446 | + text: entity_info[i].name, //标记显示的文本内容 | ||
| 447 | + anchor: "center", //设置文本标记锚点位置 | ||
| 448 | + // draggable: true, //是否可拖拽 | ||
| 449 | + // cursor: "pointer", //指定鼠标悬停时的鼠标样式。 | ||
| 450 | + // angle: 10, //点标记的旋转角度 | ||
| 451 | + style: text_direction === 'vertical' ? this.markerStyle1 : this.markerStyle1_horizontal, | ||
| 452 | + position: entity_info[i].position, //点标记在地图上显示的位置 | ||
| 453 | + }); | ||
| 454 | + textMarker.setMap(this.map); //将文本标记设置到地图上 | ||
| 455 | + this.markerSum.push(textMarker); | ||
| 456 | + if (clickListener1) { | ||
| 457 | + textMarker.off('click', clickListener) | ||
| 458 | + } | ||
| 459 | + // 绑定景点的点击事件 - 文字出现才能触发 | ||
| 460 | + var clickListener1 = textMarker.on('click', async (e) => { | ||
| 461 | + // 还原样式 | ||
| 462 | + this.markerSum.forEach(item => { | ||
| 463 | + if (e.target.hS !== item.hS) { | ||
| 464 | + // 修改文本的样式 | ||
| 465 | + item.setStyle(item._x['writing-mode'] === 'vertical-rl' ? this.markerStyle2 : this.markerStyle2_horizontal); | ||
| 466 | + } | ||
| 467 | + }) | ||
| 468 | + // 修改文本的样式 | ||
| 469 | + e.target.setStyle(text_direction === 'vertical' ? this.markerStyle1 : this.markerStyle1_horizontal); | ||
| 470 | + | ||
| 471 | + // 修改文本内容 | ||
| 472 | + // textMarker.setText('样式已修改'); | ||
| 473 | + // | ||
| 474 | + | ||
| 475 | + // 先获取音频信息 | ||
| 476 | + const { data, code } = await mapAudioAPI({ mid: this.$route.query.id, bid: entity_info[i].id }); | ||
| 477 | + | ||
| 478 | + // 创建新的对象并设置音频状态 | ||
| 479 | + const updatedInfo = JSON.parse(JSON.stringify(entity_info[i])); | ||
| 480 | + if (data.length && updatedInfo.details && updatedInfo.details[0]) { | ||
| 481 | + updatedInfo.details[0].show_audio = true; | ||
| 482 | + } | ||
| 483 | + | ||
| 484 | + // 使用 nextTick 确保视图更新 | ||
| 485 | + await this.$nextTick(); | ||
| 486 | + this.itemInfo = updatedInfo; | ||
| 487 | + | ||
| 488 | + // 详情为空提示 | ||
| 489 | + if (!this.itemInfo.details.length) { | ||
| 490 | + this.show_toast = true; | ||
| 491 | + this.toast_text = '该景点暂无详情' | ||
| 492 | + return; | ||
| 493 | + } | ||
| 494 | + | ||
| 495 | + // 打开浮动面板 | ||
| 496 | + this.info_height = (0.65 * window.innerHeight); | ||
| 497 | + // 浮动面板样式 | ||
| 498 | + $('.van-floating-panel__content').css('borderRadius', '1.25rem'); | ||
| 499 | + $('.van-floating-panel').css('boxShadow', '0 0 15px black'); | ||
| 500 | + | ||
| 501 | + // 定位到当前位置中心 | ||
| 502 | + this.map.setZoomAndCenter(this.zoom, this.itemInfo.position); | ||
| 503 | + // 获取地图容器的高度 | ||
| 504 | + const mapHeight = this.map.getSize().height; | ||
| 505 | + | ||
| 506 | + // 计算需要向上移动的像素值,比如向上移动地图高度的一半左右 | ||
| 507 | + const offsetY = -mapHeight / 3.5; | ||
| 508 | + | ||
| 509 | + // 使用 panBy 方法进行视图偏移 | ||
| 510 | + this.map.panBy(0, offsetY); | ||
| 511 | + }) | ||
| 512 | + // if (entity_info[i]?.writing_mode === 'vertical') { // 标题文字垂直 | ||
| 513 | + // let textMarker = new AMap.Text({ | ||
| 514 | + // zooms: [18, 20], // 点标记显示的层级范围,超过范围不显示。 | ||
| 515 | + // text: entity_info[i].name, //标记显示的文本内容 | ||
| 516 | + // anchor: "center", //设置文本标记锚点位置 | ||
| 517 | + // // draggable: true, //是否可拖拽 | ||
| 518 | + // // cursor: "pointer", //指定鼠标悬停时的鼠标样式。 | ||
| 519 | + // // angle: 10, //点标记的旋转角度 | ||
| 520 | + // style: this.markerStyle1, | ||
| 521 | + // position: entity_info[i].position, //点标记在地图上显示的位置 | ||
| 522 | + // }); | ||
| 523 | + // textMarker.setMap(this.map); //将文本标记设置到地图上 | ||
| 524 | + // this.markerSum.push(textMarker); | ||
| 525 | + // if (clickListener1) { | ||
| 526 | + // textMarker.off('click', clickListener) | ||
| 527 | + // } | ||
| 528 | + // // 绑定景点的点击事件 - 文字出现才能触发 | ||
| 529 | + // var clickListener1 = textMarker.on('click', (e) => { | ||
| 530 | + // // 还原样式 | ||
| 531 | + // this.markerSum.forEach(item => { | ||
| 532 | + // if (e.target.hS !== item.hS) { | ||
| 533 | + // // 修改文本的样式 | ||
| 534 | + // item.setStyle(this.markerStyle2); | ||
| 535 | + // } | ||
| 536 | + // }) | ||
| 537 | + // // 修改文本的样式 | ||
| 538 | + // e.target.setStyle(this.markerStyle1); | ||
| 539 | + | ||
| 540 | + // // 修改文本内容 | ||
| 541 | + // // textMarker.setText('样式已修改'); | ||
| 542 | + // // | ||
| 543 | + | ||
| 544 | + // // console.warn(e); | ||
| 545 | + // this.itemInfo = entity_info[i]; | ||
| 546 | + | ||
| 547 | + // // 详情为空提示 | ||
| 548 | + // if (!this.itemInfo.details.length) { | ||
| 549 | + // this.show_toast = true; | ||
| 550 | + // this.toast_text = '该景点暂无详情' | ||
| 551 | + // return; | ||
| 552 | + // } | ||
| 553 | + | ||
| 554 | + | ||
| 555 | + // // 打开浮动面板 | ||
| 556 | + // this.info_height = (0.65 * window.innerHeight); | ||
| 557 | + // // 浮动面板样式 | ||
| 558 | + // $('.van-floating-panel__content').css('borderRadius', '1.25rem'); | ||
| 559 | + // $('.van-floating-panel').css('boxShadow', '0 0 15px black'); | ||
| 560 | + | ||
| 561 | + // // 定位到当前位置中心 | ||
| 562 | + // this.map.setZoomAndCenter(this.zoom, this.itemInfo.position); | ||
| 563 | + // // 获取地图容器的高度 | ||
| 564 | + // const mapHeight = this.map.getSize().height; | ||
| 565 | + | ||
| 566 | + // // 计算需要向上移动的像素值,比如向上移动地图高度的一半左右 | ||
| 567 | + // const offsetY = -mapHeight / 3.5; | ||
| 568 | + | ||
| 569 | + // // 使用 panBy 方法进行视图偏移 | ||
| 570 | + // this.map.panBy(0, offsetY); | ||
| 571 | + // }) | ||
| 572 | + // } | ||
| 573 | + // TODO: 获取详情定位信息用来导航 | ||
| 574 | + // 导航路径 | ||
| 575 | + let marker_id = this.$route.query.marker_id; | ||
| 576 | + if (marker_id) { | ||
| 577 | + this.$nextTick(() => { | ||
| 578 | + let marker = this.navBarList[0]['list'].filter(item => item.id == marker_id) | ||
| 579 | + // let path = marker[0].path; | ||
| 580 | + // this.addSafeRoute({name: '参观路径', path}); | ||
| 581 | + // TAG: 新增步行导航 | ||
| 582 | + let position = marker[0].position; | ||
| 583 | + wx.getLocation({ | ||
| 584 | + type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02' | ||
| 585 | + success: (res) => { | ||
| 586 | + var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90 | ||
| 587 | + var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。 | ||
| 588 | + var speed = res.speed; // 速度,以米/每秒计 | ||
| 589 | + var accuracy = res.accuracy; // 位置精度 | ||
| 590 | + this.current_lng = GPS.gcj_encrypt(latitude, longitude).lon; | ||
| 591 | + this.current_lat = GPS.gcj_encrypt(latitude, longitude).lat; | ||
| 592 | + this.onWalkRoute({point: position}); | ||
| 593 | + }, | ||
| 594 | + }); | ||
| 595 | + | ||
| 596 | + // 获取当前 URL 的查询参数 | ||
| 597 | + let query = { ...this.$route.query }; | ||
| 598 | + | ||
| 599 | + // 删除 marker_id 参数 | ||
| 600 | + delete query.marker_id; | ||
| 601 | + | ||
| 602 | + // 使用 Vue Router 更新 URL,并且不刷新页面 | ||
| 603 | + this.$router.replace({ query }); | ||
| 604 | + }); | ||
| 605 | + } | ||
| 606 | + }); | ||
| 607 | + this.map.add(this.markerSum); | ||
| 608 | + // | ||
| 609 | + // setTimeout(() => { | ||
| 610 | + // // 获取定位打标记 | ||
| 611 | + // this.setLocation(); | ||
| 612 | + // }, 1000); | ||
| 613 | + }, | ||
| 614 | + isPointInRing() { // 是否在景区范围 | ||
| 615 | + let isPointInRing = AMap.GeometryUtil.isPointInRing([this.current_lng, this.current_lat], this.point_range); | ||
| 616 | + return isPointInRing | ||
| 617 | + }, | ||
| 618 | + setLocation() { // 开启定位服务 | ||
| 619 | + // 获取失败 | ||
| 620 | + // if (!this.current_lng || !this.current_lat) { | ||
| 621 | + // this.dialog_show = true; | ||
| 622 | + // this.dialog_text = '获取经纬度失败'; | ||
| 623 | + // } | ||
| 624 | + this.getLocation(); | ||
| 625 | + }, | ||
| 626 | + getLocation() { // 获取经纬度 | ||
| 627 | + // PC端无法获取定位 | ||
| 628 | + // 微信获取地址 | ||
| 629 | + wx.getLocation({ | ||
| 630 | + type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02' | ||
| 631 | + success: (res) => { | ||
| 632 | + var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90 | ||
| 633 | + var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。 | ||
| 634 | + var speed = res.speed; // 速度,以米/每秒计 | ||
| 635 | + var accuracy = res.accuracy; // 位置精度 | ||
| 636 | + this.current_lng = GPS.gcj_encrypt(latitude, longitude).lon; | ||
| 637 | + this.current_lat = GPS.gcj_encrypt(latitude, longitude).lat; | ||
| 638 | + // 判断是否在范围内 | ||
| 639 | + // if (!this.isPointInRing()) { | ||
| 640 | + // this.dialog_show = true; | ||
| 641 | + // this.dialog_text = '您不在景区范围内'; | ||
| 642 | + // } else { | ||
| 643 | + // 使用纠正偏移后的地址,打一个定位标记 | ||
| 644 | + this.location_marker = new AMap.LabelMarker({ | ||
| 645 | + icon: { | ||
| 646 | + image: 'https://cdn.ipadbiz.cn/bieyuan/map/icon/Group%2034@3x.png', | ||
| 647 | + anchor: 'bottom-center', | ||
| 648 | + size: [65, 65], | ||
| 649 | + }, | ||
| 650 | + position: new AMap.LngLat(this.current_lng, this.current_lat), // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9] | ||
| 651 | + }); | ||
| 652 | + this.map.add(this.location_marker); | ||
| 653 | + // 定位到当前位置中心 | ||
| 654 | + this.map.setZoomAndCenter(this.zoom, [this.current_lng, this.current_lat]); | ||
| 655 | + // } | ||
| 656 | + }, | ||
| 657 | + complete: () => { | ||
| 658 | + // 获取失败 | ||
| 659 | + if (!this.current_lng || !this.current_lat) { | ||
| 660 | + this.dialog_show = true; | ||
| 661 | + this.dialog_text = '获取经纬度失败'; | ||
| 662 | + } | ||
| 663 | + }, | ||
| 664 | + }); | ||
| 665 | + }, | ||
| 666 | + setZoom(type) { // 设置放大缩小地图 | ||
| 667 | + const zoom = this.map.getZoom(); | ||
| 668 | + if (type === 'plus') { | ||
| 669 | + this.map.setZoom(zoom + 1) | ||
| 670 | + } | ||
| 671 | + if (type === 'minus') { | ||
| 672 | + this.map.setZoom(zoom - 1) | ||
| 673 | + } | ||
| 674 | + }, | ||
| 675 | + computedMapSource(x, y, z) { // 根据图层信息生成图层实际地址 | ||
| 676 | + for (const id in this.mapTiles) { | ||
| 677 | + if (z == id) { | ||
| 678 | + const scope = this.mapTiles[id]; | ||
| 679 | + return scope[`${x}-${y}`] | ||
| 680 | + } | ||
| 681 | + } | ||
| 682 | + }, | ||
| 683 | + setTitleLayer() { // 生成瓦片图 | ||
| 684 | + // 获取瓦片图渲染范围 | ||
| 685 | + function getFirstProperty(obj) { | ||
| 686 | + for (var prop in obj) { | ||
| 687 | + return prop; | ||
| 688 | + } | ||
| 689 | + } | ||
| 690 | + function getLastProperty(obj) { | ||
| 691 | + var props = []; | ||
| 692 | + for (var prop in obj) { | ||
| 693 | + props.push(prop); | ||
| 694 | + } | ||
| 695 | + return props[props.length - 1]; | ||
| 696 | + } | ||
| 697 | + let obj_scope = {}; | ||
| 698 | + for (const key in this.mapTiles) { | ||
| 699 | + const element = this.mapTiles[key]; | ||
| 700 | + let first = getFirstProperty(element).split('-'); | ||
| 701 | + let last = getLastProperty(element).split('-'); | ||
| 702 | + obj_scope[key] = { | ||
| 703 | + x: [first[0], last[0]], | ||
| 704 | + y: [first[1], last[1]] | ||
| 705 | + } | ||
| 706 | + } | ||
| 707 | + const _this = this; | ||
| 708 | + var layer = new AMap.TileLayer.Flexible({ | ||
| 709 | + cacheSize: 50, | ||
| 710 | + opacity: 1, | ||
| 711 | + zIndex: 100, | ||
| 712 | + createTile: function (x, y, z, success, fail) { | ||
| 713 | + // 控制地图等级显示图片范围-过滤不显示的图层渲染 | ||
| 714 | + for (const id in obj_scope) { | ||
| 715 | + if (z == id) { | ||
| 716 | + const scope = obj_scope[id]; | ||
| 717 | + if (x < scope.x[0] || x > scope.x[1]) { | ||
| 718 | + fail() | ||
| 719 | + return; | ||
| 720 | + } | ||
| 721 | + if (y < scope.y[0] || y > scope.y[1]) { | ||
| 722 | + fail() | ||
| 723 | + return; | ||
| 724 | + } | ||
| 725 | + } | ||
| 726 | + } | ||
| 727 | + | ||
| 728 | + var img = document.createElement('img'); | ||
| 729 | + img.onload = function () { | ||
| 730 | + success(img) | ||
| 731 | + }; | ||
| 732 | + img.crossOrigin = "anonymous";// 必须添加,同时图片要有跨域头 | ||
| 733 | + img.onerror = function () { | ||
| 734 | + fail() | ||
| 735 | + }; | ||
| 736 | + | ||
| 737 | + // img.src = `images/tiles/${z}/${x}_${y}.png`; | ||
| 738 | + img.src = _this.computedMapSource(x, y, z); | ||
| 739 | + }, | ||
| 740 | + }); | ||
| 741 | + | ||
| 742 | + this.map.addLayer(layer); | ||
| 743 | + | ||
| 744 | + // Canvas作为切片 | ||
| 745 | + var layer1 = new AMap.TileLayer.Flexible({ | ||
| 746 | + // tileSize: 128, | ||
| 747 | + cacheSize: 300, | ||
| 748 | + zIndex: 200, | ||
| 749 | + createTile: function (x, y, z, success, fail) { | ||
| 750 | + var c = document.createElement('canvas'); | ||
| 751 | + c.width = c.height = 256; | ||
| 752 | + | ||
| 753 | + var cxt = c.getContext("2d"); | ||
| 754 | + cxt.font = "15px Verdana"; | ||
| 755 | + cxt.fillStyle = "#ff0000"; | ||
| 756 | + cxt.strokeStyle = "#FF0000"; | ||
| 757 | + cxt.strokeRect(0, 0, 256, 256); | ||
| 758 | + cxt.fillText('(' + [x, y, z].join(',') + ')', 10, 30); | ||
| 759 | + | ||
| 760 | + // 通知API切片创建完成 | ||
| 761 | + success(c); | ||
| 762 | + } | ||
| 763 | + }); | ||
| 764 | + | ||
| 765 | + // layer1.setMap(this.map); | ||
| 766 | + | ||
| 767 | + // 只显示相应区域,移动会回到选定范围 | ||
| 768 | + // this.lockMapBounds() | ||
| 769 | + }, | ||
| 770 | + // 限制地图范围 | ||
| 771 | + lockMapBounds() { | ||
| 772 | + // var bounds = this.map.getBounds(); | ||
| 773 | + var myBounds = new AMap.Bounds( // 移动范围,对角线 | ||
| 774 | + [117.04384,26.833629], | ||
| 775 | + [117.055975,26.843652] | ||
| 776 | + ); | ||
| 777 | + | ||
| 778 | + this.map.setLimitBounds(myBounds); | ||
| 779 | + | ||
| 780 | + let list =[ // 四个角,覆盖填充范围 | ||
| 781 | + [117.04421,26.833875], | ||
| 782 | + [117.045012,26.842089], | ||
| 783 | + [117.054749,26.84219], | ||
| 784 | + [117.056013,26.83387] | ||
| 785 | + ] | ||
| 786 | + | ||
| 787 | + // 隐藏边界以外的区域 | ||
| 788 | + let outer = [ | ||
| 789 | + new AMap.LngLat(-360, 90, true), | ||
| 790 | + new AMap.LngLat(-360, -90, true), | ||
| 791 | + new AMap.LngLat(360, -90, true), | ||
| 792 | + new AMap.LngLat(360, 90, true), | ||
| 793 | + ] // 遮盖填充反向 | ||
| 794 | + | ||
| 795 | + let pathArray = [ | ||
| 796 | + outer, | ||
| 797 | + list | ||
| 798 | + ] | ||
| 799 | + | ||
| 800 | + var polygon = new AMap.Polygon({ | ||
| 801 | + pathL: pathArray, | ||
| 802 | + strokeColor: "#fcfbf9", | ||
| 803 | + strokeWeight: 2, | ||
| 804 | + fillColor: "#fcfbf9", | ||
| 805 | + fillOpacity: 1, | ||
| 806 | + }) | ||
| 807 | + | ||
| 808 | + polygon.setPath(pathArray) | ||
| 809 | + this.map.add(polygon) | ||
| 810 | + | ||
| 811 | + }, | ||
| 812 | + showInfoClick(e) { | ||
| 813 | + // console.log(e); | ||
| 814 | + var zoom = this.map.getZoom(); //获取当前地图级别 | ||
| 815 | + // var text = | ||
| 816 | + // "您在 [" + | ||
| 817 | + // e.lnglat.getLng() + | ||
| 818 | + // "," + | ||
| 819 | + // e.lnglat.getLat() + | ||
| 820 | + // "] 的位置单击了地图!当前层级" + | ||
| 821 | + // zoom; | ||
| 822 | + var text = | ||
| 823 | + "[" + | ||
| 824 | + e.lnglat.getLng() + | ||
| 825 | + "," + | ||
| 826 | + e.lnglat.getLat() + | ||
| 827 | + "]," | ||
| 828 | + console.log(text); | ||
| 829 | + // 点击空白处,关闭弹框 | ||
| 830 | + if (this.info_height) { | ||
| 831 | + // 关闭浮动面板 | ||
| 832 | + this.info_height = 0; | ||
| 833 | + $('.van-floating-panel').css('boxShadow', 'none'); | ||
| 834 | + // 还原样式 | ||
| 835 | + this.resetMarkStyle(); | ||
| 836 | + } | ||
| 837 | + }, | ||
| 838 | + scanQrcode() { // 扫码跳转详情页 | ||
| 839 | + wx.scanQRCode({ | ||
| 840 | + needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果, | ||
| 841 | + scanType: ["qrCode","barCode"], // 可以指定扫二维码还是一维码,默认二者都有 | ||
| 842 | + success: (res) => { | ||
| 843 | + var result = res.resultStr; // 当needResult 为 1 时,扫码返回的结果 | ||
| 844 | + let id = parseQueryString(result).id; | ||
| 845 | + let marker_id = parseQueryString(result).marker_id; | ||
| 846 | + // 跳转详情页 | ||
| 847 | + this.$router.push({ | ||
| 848 | + path: '/by/info', | ||
| 849 | + query: { | ||
| 850 | + id, | ||
| 851 | + marker_id | ||
| 852 | + } | ||
| 853 | + }) | ||
| 854 | + } | ||
| 855 | + }); | ||
| 856 | + // 识别率太低 | ||
| 857 | + // this.$router.push({ | ||
| 858 | + // path: '/by/scan' | ||
| 859 | + // }) | ||
| 860 | + }, | ||
| 861 | + onHeightChange ({ height }) { // 监听浮动面板高度变化 | ||
| 862 | + if (height > window.innerHeight * 0.6) { | ||
| 863 | + // // 浮动面板样式 | ||
| 864 | + // $('.van-floating-panel__content').css('borderRadius', '0'); | ||
| 865 | + // this.showClose = true; | ||
| 866 | + // 清空设置 | ||
| 867 | + // this.changeAudio(''); | ||
| 868 | + // this.changeAudioStatus('pause'); | ||
| 869 | + // | ||
| 870 | + this.$router.push({ | ||
| 871 | + path: '/by/info', | ||
| 872 | + query: { | ||
| 873 | + id: this.$route.query.id, | ||
| 874 | + marker_id: this.itemInfo.id | ||
| 875 | + } | ||
| 876 | + }) | ||
| 877 | + } else { | ||
| 878 | + $('.van-floating-panel__content').css('borderRadius', '1.25rem'); | ||
| 879 | + $('.van-floating-panel').css('boxShadow', 'none'); | ||
| 880 | + this.showClose = false; | ||
| 881 | + } | ||
| 882 | + }, | ||
| 883 | + closeFloatPanel () { | ||
| 884 | + this.info_height = (0.65 * window.innerHeight); | ||
| 885 | + $('.van-floating-panel__content').css('borderRadius', '1.25rem'); | ||
| 886 | + this.showClose = false; | ||
| 887 | + // 关闭音频 | ||
| 888 | + this.$refs.pageInfo.outerStopAudio(); | ||
| 889 | + }, | ||
| 890 | + resetMarkStyle () { | ||
| 891 | + this.markerSum.forEach(item => { | ||
| 892 | + item.setStyle(item._x['writing-mode'] === 'vertical-rl' ? this.markerStyle1 : this.markerStyle1_horizontal); | ||
| 893 | + }) | ||
| 894 | + }, | ||
| 895 | + onCloseFloat () { | ||
| 896 | + this.info_height = 0; | ||
| 897 | + $('.van-floating-panel__content').css('borderRadius', '1.25rem'); | ||
| 898 | + $('.van-floating-panel').css('boxShadow', 'none'); | ||
| 899 | + this.resetMarkStyle(); | ||
| 900 | + }, | ||
| 901 | + addSafeRoute({name, path}) { // 新增路径 | ||
| 902 | + // 获取对象的第一个键和值 | ||
| 903 | + // let firstKey = Object.keys(this.data_paths)[0]; | ||
| 904 | + // let firstValue = this.data_paths[firstKey]; | ||
| 905 | + // 行动路线 | ||
| 906 | + // var path = [ | ||
| 907 | + // [120.587645, 31.314833], | ||
| 908 | + // [120.587709, 31.314338], | ||
| 909 | + // [120.588211, 31.314377], | ||
| 910 | + // ]; | ||
| 911 | + // console.warn(firstValue); | ||
| 912 | + // var path = firstValue; | ||
| 913 | + // 生成折线地图路径 | ||
| 914 | + let current_safe_route = new AMap.Polyline({ | ||
| 915 | + path, | ||
| 916 | + isOutline: true, | ||
| 917 | + outlineColor: '#179FB1', | ||
| 918 | + borderWeight: 1, | ||
| 919 | + strokeColor: '#179FB1', | ||
| 920 | + strokeOpacity: 1, | ||
| 921 | + strokeWeight: 3, | ||
| 922 | + // 折线样式还支持 'dashed' | ||
| 923 | + strokeStyle: 'solid', | ||
| 924 | + // strokeStyle是dashed时有效 | ||
| 925 | + strokeDasharray: [10, 5], | ||
| 926 | + lineJoin: 'round', | ||
| 927 | + lineCap: 'round', | ||
| 928 | + zIndex: 50 | ||
| 929 | + }) | ||
| 930 | + this.map.add([current_safe_route]); | ||
| 931 | + this.current_safe_route.push({ | ||
| 932 | + key: name, | ||
| 933 | + path: current_safe_route | ||
| 934 | + }) | ||
| 935 | + // 设置起始点标记 | ||
| 936 | + var marker1 = new AMap.Marker({ | ||
| 937 | + icon: new AMap.Icon({ | ||
| 938 | + image: 'https://cdn.ipadbiz.cn/bieyuan/map/icon/Ellipse%2013@3x.png', | ||
| 939 | + size: new AMap.Size(15, 15), | ||
| 940 | + // 图标所用图片大小 | ||
| 941 | + imageSize: new AMap.Size(15, 15), | ||
| 942 | + // 图标取图偏移量 | ||
| 943 | + imageOffset: new AMap.Pixel(0, 0) | ||
| 944 | + }), | ||
| 945 | + position: new AMap.LngLat(path[0][0], path[0][1]), // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9] | ||
| 946 | + anchor: 'bottom-center', | ||
| 947 | + offset: new AMap.Pixel(0, 0) | ||
| 948 | + }); | ||
| 949 | + // marker1.setLabel({ | ||
| 950 | + // direction: 'right', | ||
| 951 | + // offset: new AMap.Pixel(0, -10), //设置文本标注偏移量 | ||
| 952 | + // content: "<div class='info'>起点</div>", //设置文本标注内容 | ||
| 953 | + // }); | ||
| 954 | + var marker2 = new AMap.Marker({ | ||
| 955 | + icon: new AMap.Icon({ | ||
| 956 | + image: 'https://cdn.ipadbiz.cn/bieyuan/map/icon/Ellipse%2013@3x.png', | ||
| 957 | + size: new AMap.Size(15, 15), | ||
| 958 | + // 图标所用图片大小 | ||
| 959 | + imageSize: new AMap.Size(15, 15), | ||
| 960 | + // 图标取图偏移量 | ||
| 961 | + imageOffset: new AMap.Pixel(0, 0) | ||
| 962 | + }), | ||
| 963 | + position: new AMap.LngLat(path[path.length - 1][0], path[path.length - 1][1]), // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9] | ||
| 964 | + anchor: 'bottom-center', | ||
| 965 | + offset: new AMap.Pixel(0, 0) | ||
| 966 | + }); | ||
| 967 | + // marker2.setLabel({ | ||
| 968 | + // direction: 'right', | ||
| 969 | + // offset: new AMap.Pixel(0, -10), //设置文本标注偏移量 | ||
| 970 | + // content: "<div class='info'>终点</div>", //设置文本标注内容 | ||
| 971 | + // }); | ||
| 972 | + // 新增逃生路线标记 | ||
| 973 | + // this.route_safe_marker = [marker1, marker2] | ||
| 974 | + // this.map.add(this.route_safe_marker); | ||
| 975 | + // 新增逃生路线标记 | ||
| 976 | + let route_safe_marker = [marker1, marker2] | ||
| 977 | + this.map.add(route_safe_marker); | ||
| 978 | + this.route_safe_marker.push({ | ||
| 979 | + key: name, | ||
| 980 | + path: route_safe_marker | ||
| 981 | + }); | ||
| 982 | + // 关闭导航提示 | ||
| 983 | + this.show_walk_route = false; | ||
| 984 | + }, | ||
| 985 | + removeSafeRoute({name}) { // 移除地图路线 | ||
| 986 | + this.current_safe_route.forEach(item => { | ||
| 987 | + if (item.key === name) { | ||
| 988 | + this.map.remove([item.path]); // 删除地图折线 | ||
| 989 | + } | ||
| 990 | + }); | ||
| 991 | + // this.map.remove(this.route_safe_marker); // 删除起始点标记 | ||
| 992 | + this.route_safe_marker.forEach(item => { | ||
| 993 | + if (item.key === name) { | ||
| 994 | + this.map.remove(item.path); // 删除起始点标记 | ||
| 995 | + } | ||
| 996 | + }); | ||
| 997 | + // 关闭导航提示 | ||
| 998 | + this.show_walk_route = true; | ||
| 999 | + }, | ||
| 1000 | + onRoute (path) { | ||
| 1001 | + console.warn(path); | ||
| 1002 | + // 模拟新增路线 | ||
| 1003 | + this.addSafeRoute(path); | ||
| 1004 | + // 定位到当前位置中心 | ||
| 1005 | + this.map.setZoomAndCenter(this.zoom, this.data_center); | ||
| 1006 | + }, | ||
| 1007 | + async onWalkRoute (position) { | ||
| 1008 | + await this.$nextTick(); // 等待DOM更新 | ||
| 1009 | + // 步行导航 | ||
| 1010 | + // let walking = new AMap.Walking({ | ||
| 1011 | + // map: this.map, | ||
| 1012 | + // panel: "panel" | ||
| 1013 | + // }); | ||
| 1014 | + | ||
| 1015 | + wx.getLocation({ | ||
| 1016 | + type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02' | ||
| 1017 | + success: (res) => { | ||
| 1018 | + var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90 | ||
| 1019 | + var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。 | ||
| 1020 | + var speed = res.speed; // 速度,以米/每秒计 | ||
| 1021 | + var accuracy = res.accuracy; // 位置精度 | ||
| 1022 | + this.current_lng = GPS.gcj_encrypt(latitude, longitude).lon; | ||
| 1023 | + this.current_lat = GPS.gcj_encrypt(latitude, longitude).lat; | ||
| 1024 | + | ||
| 1025 | + // 确保参数格式正确 | ||
| 1026 | + const startPoint = [this.current_lng, this.current_lat]; // 起点 | ||
| 1027 | + const endPoint = position.point; // 终点 | ||
| 1028 | + | ||
| 1029 | + // 参数检查 | ||
| 1030 | + if (!startPoint[0] || !startPoint[1]) { | ||
| 1031 | + this.show_toast = true; | ||
| 1032 | + this.toast_text = '无法获取当前位置,请确保已开启定位功能'; | ||
| 1033 | + return; | ||
| 1034 | + } | ||
| 1035 | + | ||
| 1036 | + if (!endPoint[0] || !endPoint[1]) { | ||
| 1037 | + this.show_toast = true; | ||
| 1038 | + this.toast_text = '目的地坐标不完整'; | ||
| 1039 | + return; | ||
| 1040 | + } | ||
| 1041 | + | ||
| 1042 | + // 转换为 LngLat 对象 | ||
| 1043 | + const start = new AMap.LngLat(startPoint[0], startPoint[1]); | ||
| 1044 | + const end = new AMap.LngLat(endPoint[0], endPoint[1]); | ||
| 1045 | + | ||
| 1046 | + // 规划步行路线 | ||
| 1047 | + this.walking.search(start, end, (status, result) => { | ||
| 1048 | + if (status === 'complete') { | ||
| 1049 | + console.log('步行路线规划成功'); | ||
| 1050 | + setTimeout(() =>{ | ||
| 1051 | + // 定位到当前位置中心 | ||
| 1052 | + this.getLocation(); | ||
| 1053 | + this.show_walk_route = false; | ||
| 1054 | + },500) | ||
| 1055 | + } else { | ||
| 1056 | + console.error('步行路线规划失败:', status, result); | ||
| 1057 | + ElMessage.error('步行路线规划失败,请稍后重试'); | ||
| 1058 | + } | ||
| 1059 | + }); | ||
| 1060 | + }, | ||
| 1061 | + }); | ||
| 1062 | + }, | ||
| 1063 | + handleLocation(status) { // 打开/关闭 当前定位 | ||
| 1064 | + if (status) { | ||
| 1065 | + this.setLocation() | ||
| 1066 | + this.open_current_location = false; | ||
| 1067 | + } else { | ||
| 1068 | + this.removeLocation() | ||
| 1069 | + this.open_current_location = true; | ||
| 1070 | + } | ||
| 1071 | + }, | ||
| 1072 | + removeLocation() { // 移除定位标记 | ||
| 1073 | + this.current_lng = ''; | ||
| 1074 | + this.current_lat = ''; | ||
| 1075 | + this.map.remove(this.location_marker); // 删除当前定位标记 | ||
| 1076 | + }, | ||
| 1077 | + closeWalkingRoute() { | ||
| 1078 | + if (this.walking) { | ||
| 1079 | + this.walking.clear(); // 清除路线 | ||
| 1080 | + this.show_walk_route = true; // 恢复状态 | ||
| 1081 | + // 可选:移除面板内容 | ||
| 1082 | + document.getElementById('walking-panel').innerHTML = ''; | ||
| 1083 | + | ||
| 1084 | + // 显示提示 | ||
| 1085 | + this.show_toast = true; | ||
| 1086 | + this.toast_text = '已关闭步行导航'; | ||
| 1087 | + } | ||
| 1088 | + }, | ||
| 1089 | + } | ||
| 1090 | +} | ||
| 1091 | +</script> | ||
| 1092 | + | ||
| 1093 | +<style lang="less"> | ||
| 1094 | +#container { | ||
| 1095 | + position: absolute; | ||
| 1096 | + top: 0; | ||
| 1097 | + left: 0; | ||
| 1098 | + right: 0; | ||
| 1099 | + bottom: 0; | ||
| 1100 | + width: 100%; | ||
| 1101 | + height: 100%; | ||
| 1102 | +} | ||
| 1103 | + | ||
| 1104 | +// 遮挡地图logo | ||
| 1105 | +.amap-logo { | ||
| 1106 | + display: none!important; | ||
| 1107 | + visibility: hidden!important; | ||
| 1108 | +} | ||
| 1109 | + | ||
| 1110 | +.amap-copyright { | ||
| 1111 | + display: none!important; | ||
| 1112 | + visibility: hidden!important; | ||
| 1113 | +} | ||
| 1114 | + | ||
| 1115 | +/* 标记文字样式 */ | ||
| 1116 | +.amap-marker-label { | ||
| 1117 | + padding: 0.25rem 0.5rem; | ||
| 1118 | + width: auto; | ||
| 1119 | + border: none; | ||
| 1120 | + border-radius: 2px; | ||
| 1121 | + background: rgba(86, 65, 23, 0.8); | ||
| 1122 | + color: white; | ||
| 1123 | +} | ||
| 1124 | + | ||
| 1125 | +.amap-marker { | ||
| 1126 | + .amap-icon { | ||
| 1127 | + margin-top: 0.25rem; | ||
| 1128 | + } | ||
| 1129 | +} | ||
| 1130 | + | ||
| 1131 | +.input-card { | ||
| 1132 | + display: flex; | ||
| 1133 | + flex-direction: column; | ||
| 1134 | + min-width: 0; | ||
| 1135 | + word-wrap: break-word; | ||
| 1136 | + background-color: #fff; | ||
| 1137 | + background-clip: border-box; | ||
| 1138 | + border-radius: .25rem; | ||
| 1139 | + width: 20rem; | ||
| 1140 | + border-width: 0; | ||
| 1141 | + border-radius: 0.4rem; | ||
| 1142 | + box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5); | ||
| 1143 | + position: fixed; | ||
| 1144 | + top: 4rem; | ||
| 1145 | + right: 1rem; | ||
| 1146 | + -ms-flex: 1 1 auto; | ||
| 1147 | + flex: 1 1 auto; | ||
| 1148 | + padding: 0.75rem 1.25rem; | ||
| 1149 | +} | ||
| 1150 | + | ||
| 1151 | +.tool-bar-wrapper { | ||
| 1152 | + position: absolute; | ||
| 1153 | + left: 20px; | ||
| 1154 | + bottom: 8rem; | ||
| 1155 | + width: 20px; | ||
| 1156 | +} | ||
| 1157 | + | ||
| 1158 | +.nav-bar-wrapper { | ||
| 1159 | + position: fixed; | ||
| 1160 | + bottom: 0; | ||
| 1161 | + left: 0; | ||
| 1162 | + height: 5.5rem; | ||
| 1163 | + width: 100%; | ||
| 1164 | + background-color: white; | ||
| 1165 | + text-align: center; | ||
| 1166 | + box-shadow: 0 -1px 0 rgba(80, 80, 80, 0.1); | ||
| 1167 | + z-index: 999; | ||
| 1168 | + // padding: 0.5rem 0; | ||
| 1169 | + padding-bottom: 0.5rem; | ||
| 1170 | + | ||
| 1171 | + .nav-bar-content { | ||
| 1172 | + display: flex; | ||
| 1173 | + overflow-x: scroll; | ||
| 1174 | + overflow-y: hidden; | ||
| 1175 | + -webkit-overflow-scrolling: touch; | ||
| 1176 | + position: relative; | ||
| 1177 | + } | ||
| 1178 | + | ||
| 1179 | + .item { | ||
| 1180 | + padding-top: 0.5rem; | ||
| 1181 | + color: #888; | ||
| 1182 | + width: 21.5%; | ||
| 1183 | + flex-shrink: 0; | ||
| 1184 | + padding-top: 1rem; | ||
| 1185 | + } | ||
| 1186 | + | ||
| 1187 | + .checked { | ||
| 1188 | + color: #965f13; | ||
| 1189 | + } | ||
| 1190 | +} | ||
| 1191 | + | ||
| 1192 | +.safe-route-wrapper { | ||
| 1193 | + position: absolute; | ||
| 1194 | + bottom: 2rem; | ||
| 1195 | + right: 1rem; | ||
| 1196 | + background-color: white; | ||
| 1197 | +} | ||
| 1198 | + | ||
| 1199 | +.operate-bar-wrapper { | ||
| 1200 | + position: fixed; | ||
| 1201 | + left: 20px; | ||
| 1202 | + bottom: 6rem; | ||
| 1203 | + width: 20px; | ||
| 1204 | + height: auto; | ||
| 1205 | + z-index: 100; | ||
| 1206 | + | ||
| 1207 | + .box-wrapper { | ||
| 1208 | + display: flex; | ||
| 1209 | + flex-direction: column; | ||
| 1210 | + align-items: center; | ||
| 1211 | + justify-content: center; | ||
| 1212 | + | ||
| 1213 | + .item { | ||
| 1214 | + position: relative; | ||
| 1215 | + text-align: center; | ||
| 1216 | + font-size: 0.85rem; | ||
| 1217 | + width: 2rem; | ||
| 1218 | + height: 2rem; | ||
| 1219 | + background-color: white; | ||
| 1220 | + margin-bottom: 1rem; | ||
| 1221 | + border-radius: 50%; | ||
| 1222 | + padding: 2.5px; | ||
| 1223 | + line-height: 2rem; | ||
| 1224 | + } | ||
| 1225 | + } | ||
| 1226 | +} | ||
| 1227 | + | ||
| 1228 | +.popup-wrapper { | ||
| 1229 | + margin-top: 1rem; | ||
| 1230 | + | ||
| 1231 | + .title { | ||
| 1232 | + font-size: 1.25rem; | ||
| 1233 | + margin-bottom: 0.85rem; | ||
| 1234 | + } | ||
| 1235 | + | ||
| 1236 | + .content { | ||
| 1237 | + line-height: 1.75; | ||
| 1238 | + font-size: 0.95rem; | ||
| 1239 | + } | ||
| 1240 | +} | ||
| 1241 | + | ||
| 1242 | + | ||
| 1243 | +.hideScrollBar::-webkit-scrollbar { | ||
| 1244 | + display: none; | ||
| 1245 | +} | ||
| 1246 | + | ||
| 1247 | +.hideScrollBar { | ||
| 1248 | + -ms-overflow-style: none; | ||
| 1249 | + overflow: -moz-scrollbars-none; | ||
| 1250 | +} | ||
| 1251 | + | ||
| 1252 | +.van-dialog__confirm, | ||
| 1253 | +.van-dialog__confirm:active { | ||
| 1254 | + color: #AB8F57; | ||
| 1255 | +} | ||
| 1256 | + | ||
| 1257 | +.walk-nav-text { | ||
| 1258 | + position: fixed; | ||
| 1259 | + bottom: 6rem; | ||
| 1260 | + left: 50%; | ||
| 1261 | + transform: translate(-50%, -50%); | ||
| 1262 | + z-index: 9; | ||
| 1263 | + background: rgba(86, 65, 23, 0.8); | ||
| 1264 | + color: white; | ||
| 1265 | + border-radius: 10px; | ||
| 1266 | + padding: 5px 12px; | ||
| 1267 | + font-size: 0.8rem; | ||
| 1268 | +} | ||
| 1269 | + | ||
| 1270 | +.close-float-panel { | ||
| 1271 | + position: absolute; | ||
| 1272 | + top: 1rem; | ||
| 1273 | + left: 1rem; | ||
| 1274 | +} | ||
| 1275 | + | ||
| 1276 | +.custom-header { | ||
| 1277 | + display: flex; | ||
| 1278 | + justify-content: space-between; | ||
| 1279 | + align-items: center; | ||
| 1280 | + padding: 10px; | ||
| 1281 | + background-color: #f7f8fa; | ||
| 1282 | +} | ||
| 1283 | + | ||
| 1284 | +.van-floating-panel__header-bar { | ||
| 1285 | + background: none; | ||
| 1286 | +} | ||
| 1287 | +</style> |
src/views/checkin/scan.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2024-09-15 11:45:13 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2024-09-18 11:15:56 | ||
| 5 | + * @FilePath: /map-demo/src/views/bieyuan/scan.vue | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <div class="scan-page"> | ||
| 10 | + <!--<div class="scan_wrapper"> | ||
| 11 | + <div class="scan_box"> | ||
| 12 | + <!~~ 镜头区域 ~~> | ||
| 13 | + <video ref="video" id="video" class="scan-video" autoplay></video> | ||
| 14 | + </div> | ||
| 15 | + <div @click="openScan" class="scan_text">点击扫描二维码查看详情</div> | ||
| 16 | + </div> | ||
| 17 | + <div class="sys_logo"> | ||
| 18 | + <van-image | ||
| 19 | + width="3rem" | ||
| 20 | + height="3rem" | ||
| 21 | + fit="contain" | ||
| 22 | + src="https://cdn.ipadbiz.cn/bieyuan/map/icon/scan_logo.png" | ||
| 23 | + /> | ||
| 24 | + </div>--> | ||
| 25 | + | ||
| 26 | + <video ref="video" id="video" class="video vjs-fluid" autoplay></video> | ||
| 27 | + <div v-show="tipShow" class="tip">{{tipMsg}}</div> | ||
| 28 | + </div> | ||
| 29 | +</template> | ||
| 30 | + | ||
| 31 | +<script setup> | ||
| 32 | +import { ref } from "vue"; | ||
| 33 | +import { useRoute, useRouter } from "vue-router"; | ||
| 34 | + | ||
| 35 | +const $route = useRoute(); | ||
| 36 | +const $router = useRouter(); | ||
| 37 | + | ||
| 38 | +import { BrowserMultiFormatReader } from "@zxing/library"; | ||
| 39 | +// import axios from 'axios' | ||
| 40 | +const codeReader = ref(null); | ||
| 41 | + | ||
| 42 | +const scanText = ref(""); | ||
| 43 | +// 初始化相机 | ||
| 44 | +const openScan = () => { | ||
| 45 | + codeReader.value = new BrowserMultiFormatReader(); | ||
| 46 | + codeReader.value | ||
| 47 | + .getVideoInputDevices() | ||
| 48 | + .then((videoDevices) => { | ||
| 49 | + let firstDeviceId = videoDevices[videoDevices.length - 1].deviceId; | ||
| 50 | + if (videoDevices.length > 1) { | ||
| 51 | + // 一般通过判断摄像头列表项里的 label 字段,'camera2 0, facing back' 字符串含有 'back' 和 '0',大部分机型是这样,如果有些机型没有,那就还是默认获取最后一个 | ||
| 52 | + firstDeviceId = videoDevices.find((el) => { | ||
| 53 | + return el.label.indexOf("back") > -1 && el.label.indexOf("0") > -1; | ||
| 54 | + }) | ||
| 55 | + ? videoDevices.find((el) => { | ||
| 56 | + return el.label.indexOf("back") > -1 && el.label.indexOf("0") > -1; | ||
| 57 | + }).deviceId | ||
| 58 | + : videoDevices[videoDevices.length - 1].deviceId; | ||
| 59 | + } | ||
| 60 | + decodeFromInputVideoFunc(firstDeviceId); | ||
| 61 | + }) | ||
| 62 | + .catch((err) => { | ||
| 63 | + console.log(err); | ||
| 64 | + }); | ||
| 65 | +}; | ||
| 66 | + | ||
| 67 | +// 扫码 | ||
| 68 | +const decodeFromInputVideoFunc = (firstDeviceId) => { | ||
| 69 | + // 使用摄像头扫描 | ||
| 70 | + codeReader.value.reset(); // 重置 | ||
| 71 | + codeReader.value.decodeFromInputVideoDeviceContinuously( | ||
| 72 | + firstDeviceId, | ||
| 73 | + "video", | ||
| 74 | + (result, err) => { | ||
| 75 | + if (result) { | ||
| 76 | + alert(result.text); | ||
| 77 | + console.log("扫码结果", result); | ||
| 78 | + scanText.value = result.text; | ||
| 79 | + if (scanText.value) { | ||
| 80 | + // 识别成功关闭摄像头 | ||
| 81 | + codeReader.value.reset(); | ||
| 82 | + codeReader.value.stopContinuousDecodeFromInputVideoDevice(); | ||
| 83 | + } | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | + ); | ||
| 87 | +}; | ||
| 88 | + | ||
| 89 | +onMounted(() => {}); | ||
| 90 | +</script> | ||
| 91 | + | ||
| 92 | + | ||
| 93 | +<style lang="less" scoped> | ||
| 94 | +.scan-page { | ||
| 95 | + position: relative; | ||
| 96 | + height: 100vh; | ||
| 97 | + .scan_wrapper { | ||
| 98 | + display: flex; | ||
| 99 | + padding: 1rem; | ||
| 100 | + flex-direction: column; | ||
| 101 | + align-items: center; | ||
| 102 | + padding-top: 5rem; | ||
| 103 | + .scan_box { | ||
| 104 | + padding: 1rem; | ||
| 105 | + background-image: url('https://cdn.ipadbiz.cn/bieyuan/map/icon/scan_bg.png'); | ||
| 106 | + background-size: contain; | ||
| 107 | + background-repeat: no-repeat; | ||
| 108 | + background-position: center center; | ||
| 109 | + height: 20rem; | ||
| 110 | + width: 90%; | ||
| 111 | + position: relative; | ||
| 112 | + overflow: hidden; /* 确保溢出内容被隐藏 */ | ||
| 113 | + box-sizing: border-box; /* 包括 padding 在内的尺寸计算 */ | ||
| 114 | + .scan-video { | ||
| 115 | + object-fit: cover; /* 保持视频内容的比例,同时填满容器 */ | ||
| 116 | + position: absolute; /* 确保视频覆盖整个容器 */ | ||
| 117 | + top: -1rem; | ||
| 118 | + left: -1rem; | ||
| 119 | + width: calc(100% - 2rem); /* 视频宽度减去左右1rem的padding */ | ||
| 120 | + height: calc(100% - 2rem); /* 视频高度减去上下1rem的padding */ | ||
| 121 | + padding: 2rem; | ||
| 122 | + object-fit: cover; /* 保持视频比例,同时填充容器 */ | ||
| 123 | + } | ||
| 124 | + } | ||
| 125 | + .scan_text { | ||
| 126 | + font-size: 0.9rem; | ||
| 127 | + color: #DD7850; | ||
| 128 | + padding: 0.5rem 1rem; | ||
| 129 | + margin: 1rem; | ||
| 130 | + border: 1px solid #DD7850; | ||
| 131 | + border-radius: 5px; | ||
| 132 | + } | ||
| 133 | + } | ||
| 134 | + .sys_logo { | ||
| 135 | + position: absolute; | ||
| 136 | + bottom: 3rem; | ||
| 137 | + left: calc(50% - 1.5rem); | ||
| 138 | + } | ||
| 139 | +} | ||
| 140 | +</style> |
-
Please register or login to post a comment