1、调整王府井背景图
2、调整福印收集逻辑,必须是发生互动后才能进行收集
3、王府井增加热区点击,点击后展示图片浏览功能
4、图片浏览组件增加两种浏览模式,有标题和没有标题
This commit is contained in:
Wenzhe 2026-02-03 22:55:40 +08:00
parent ecb0bcda46
commit ab75f0056c
12 changed files with 164 additions and 127 deletions

View File

@ -1,6 +1,5 @@
<script setup>
import { ref, onMounted, computed } from 'vue'
import FuClickArea from './FuClickArea.vue'
//
const props = defineProps({
@ -23,7 +22,6 @@ const emit = defineEmits(['collect-seal'])
const sealCollected = ref(false)
//
const fuClickAreaVisible = ref(true)
const sq2ImageVisible = ref(false)
//
@ -32,15 +30,15 @@ const parallaxOffset = computed(() => {
return props.scrollPosition * 0.1
})
//
const handleFuClick = () => {
fuClickAreaVisible.value = false
// webview
const openWebview = () => {
//
if (!sealCollected.value) {
sealCollected.value = true
sq2ImageVisible.value = true
emit('collect-seal')
}
// webview
const openWebview = () => {
uni.navigateTo({
url: '/pages/webview/webview',
success: () => {
@ -75,16 +73,7 @@ onMounted(() => {
<img src="/static/bg/bg2.jpg" alt="崇文门商圈" class="background-image" />
</div>
<!-- 福字点击区域 -->
<FuClickArea
:visible="fuClickAreaVisible"
:x-range="630"
:y-range="300"
:y-start="150"
:fu-width="100"
:fu-height="100"
@click="handleFuClick"
/>
<!-- sq2图片 -->
<img

View File

@ -5,14 +5,14 @@
<div class="modal-body">
<div class="couplet-display">
<!-- 显示海报图片后端直接返回 -->
<div class="poster-image" v-if="couplet.image_url">
<div class="poster-image" v-if="couplet?.image_url">
<!-- 加载提示 -->
<div class="image-loading" v-if="isLoading">
<div class="loading-spinner"></div>
<div class="loading-text">海报加载中...</div>
</div>
<img
:src="couplet.image_url"
:src="couplet?.image_url"
alt="春联海报"
style="width: 100%; max-width: 300px; height: auto;"
@load="isLoading = false"
@ -58,7 +58,7 @@ const emit = defineEmits(['close'])
const isLoading = ref(true)
// couplet
watch(() => props.couplet.image_url, (newImageUrl) => {
watch(() => props.couplet?.image_url, (newImageUrl) => {
if (newImageUrl) {
isLoading.value = true
}
@ -66,7 +66,7 @@ watch(() => props.couplet.image_url, (newImageUrl) => {
// visible
watch(() => props.visible, (newVisible) => {
if (newVisible && props.couplet.image_url) {
if (newVisible && props.couplet?.image_url) {
isLoading.value = true
}
})

View File

@ -1,6 +1,5 @@
<script setup>
import { ref, onMounted, onUnmounted, computed, getCurrentInstance as vueGetCurrentInstance, watch } from 'vue'
import FuClickArea from './FuClickArea.vue'
import ImagePreloader from '@/utils/preload'
// Vue
@ -20,22 +19,16 @@ const props = defineProps({
const emit = defineEmits(['collect-seal'])
//
const fuClickAreaVisible = ref(true)
// sq3
const sq3ImageVisible = ref(false)
//
const sealCollected = ref(false)
//
const parallaxOffset = computed(() => {
return props.scrollPosition * 0.1
})
//
const handleFuClick = () => {
fuClickAreaVisible.value = false
sq3ImageVisible.value = true
emit('collect-seal')
}
//
const getDzmImageUrl = (name) => {
return new URL(`/static/dzm/${name}`, import.meta.url).href
@ -449,6 +442,13 @@ const handleTouchEnd = () => {
// Canvas
canvasDisabled.value = true
console.log('Canvas 触摸事件已禁用')
// sq3
if (!sealCollected.value) {
sq3ImageVisible.value = true
sealCollected.value = true
emit('collect-seal')
}
} else {
//
console.log('未放入目标区域,回归原始位置')
@ -553,17 +553,6 @@ onUnmounted(() => {
<image src="/static/bg/bg5.jpg" alt="东直门商圈" class="background-image" mode="widthFix" />
</view>
<!-- 福字点击区域 -->
<FuClickArea
:visible="fuClickAreaVisible"
:x-range="630"
:y-range="400"
:y-start="150"
:fu-width="100"
:fu-height="100"
@click="handleFuClick"
/>
<!-- sq3图片 -->
<image
v-if="sq3ImageVisible"

View File

@ -17,6 +17,11 @@ const props = defineProps({
currentIndex: {
type: Number,
default: 0
},
// 'with-title' 'without-title'
mode: {
type: String,
default: 'with-title'
}
})
@ -63,14 +68,22 @@ const handleOverlayClick = () => {
<div class="modal-overlay" @click="handleOverlayClick"></div>
<!-- 弹窗内容 -->
<div class="modal-content">
<div class="modal-content" :class="{ 'without-title': mode === 'without-title' }">
<!-- 图片区域 -->
<div class="gallery-image-wrapper">
<!-- 无标题模式下的导航按钮 -->
<div v-if="mode === 'without-title'" class="nav-btn prev-btn side-btn" @click="prevImage">
<img src="/static/images/btn_prev.png" alt="上一张" class="nav-icon" />
</div>
<img :src="images[currentImageIndex]?.src" :alt="images[currentImageIndex]?.title" class="gallery-image" />
<!-- 无标题模式下的导航按钮 -->
<div v-if="mode === 'without-title'" class="nav-btn next-btn side-btn" @click="nextImage">
<img src="/static/images/btn_next.png" alt="下一张" class="nav-icon" />
</div>
</div>
<!-- 控制区域 -->
<div class="gallery-controls">
<!-- 有标题模式下的控制区域 -->
<div v-if="mode === 'with-title'" class="gallery-controls">
<div class="nav-btn prev-btn" @click="prevImage">
<img src="/static/images/btn_prev.png" alt="上一张" class="nav-icon" />
</div>
@ -125,6 +138,36 @@ const handleOverlayClick = () => {
animation: modalIn 0.3s ease;
}
/* 无标题模式下的弹窗内容 */
.modal-content.without-title {
padding-bottom: 30rpx;
}
/* 图片区域 */
.gallery-image-wrapper {
position: relative;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
/* 无标题模式下的侧边导航按钮 */
.side-btn {
position: absolute;
top: 50%;
transform: translateY(-50%);
z-index: 10;
}
.side-btn.prev-btn {
left: -40rpx;
}
.side-btn.next-btn {
right: -40rpx;
}
@keyframes modalIn {
from {
opacity: 0;

View File

@ -1,6 +1,5 @@
<script setup>
import { ref, onMounted, computed, watch } from 'vue'
import FuClickArea from './FuClickArea.vue'
import ImageGalleryModal from './ImageGalleryModal.vue'
import ImagePreloader from '@/utils/preload';
@ -21,9 +20,10 @@ const props = defineProps({
//
const emit = defineEmits(['collect-seal'])
//
const fuClickAreaVisible = ref(true)
// sq3
const sq3ImageVisible = ref(false)
//
const sealCollected = ref(false)
//
const imagesLoaded = ref(false)
@ -60,12 +60,7 @@ watch(() => props.active, async (newActive) => {
}
})
//
const handleFuClick = () => {
fuClickAreaVisible.value = false
sq3ImageVisible.value = true
emit('collect-seal')
}
//
const getImageUrl = (name) => {
@ -87,6 +82,13 @@ const currentGalleryIndex = ref(0)
const openGallery = (index) => {
currentGalleryIndex.value = index
galleryVisible.value = true
// sq3
if (!sealCollected.value) {
sq3ImageVisible.value = true
sealCollected.value = true
emit('collect-seal')
}
}
//
@ -117,17 +119,6 @@ onMounted(() => {
<img src="/static/bg/bg4.jpg" alt="隆福寺商圈" class="background-image" />
</div>
<!-- 福字点击区域 -->
<FuClickArea
:visible="fuClickAreaVisible"
:x-range="630"
:y-range="400"
:y-start="150"
:fu-width="100"
:fu-height="100"
@click="handleFuClick"
/>
<!-- sq3图片 -->
<img
v-if="sq3ImageVisible"
@ -161,7 +152,8 @@ onMounted(() => {
<ImageGalleryModal
:visible="galleryVisible"
:images="lfsImages"
:currentIndex="currentGalleryIndex"
:current-index="currentGalleryIndex"
mode="with-title"
@close="closeGallery"
/>

View File

@ -1,6 +1,5 @@
<script setup>
import { ref, onMounted, onUnmounted, computed, watch } from 'vue'
import FuClickArea from './FuClickArea.vue'
//
const props = defineProps({
@ -27,7 +26,6 @@ const isMusicPlaying = ref(false)
const musicPlayer = ref(null)
//
const fuClickAreaVisible = ref(true)
const sq1ImageVisible = ref(false)
//
@ -72,15 +70,15 @@ const parallaxOffset = computed(() => {
return offset
})
//
const handleFuClick = () => {
fuClickAreaVisible.value = false
// /
const toggleMusic = () => {
//
if (!sealCollected.value) {
sealCollected.value = true
sq1ImageVisible.value = true
emit('collect-seal')
}
// /
const toggleMusic = () => {
if (!musicPlayer.value) {
//
musicPlayer.value = uni.createInnerAudioContext()
@ -182,16 +180,7 @@ onUnmounted(() => {
/>
</div>
<!-- 福字点击区域 -->
<FuClickArea
:visible="fuClickAreaVisible"
:x-range="630"
:y-range="400"
:y-start="350"
:fu-width="100"
:fu-height="100"
@click="handleFuClick"
/>
<!-- sq1图片 -->
<img

View File

@ -1,6 +1,6 @@
<script setup>
import { ref, onMounted, computed, watch } from 'vue'
import FuClickArea from './FuClickArea.vue'
import ImageGalleryModal from './ImageGalleryModal.vue'
import ImagePreloader from '@/utils/preload';
//
@ -21,7 +21,6 @@ const props = defineProps({
const emit = defineEmits(['collect-seal'])
//
const fuClickAreaVisible = ref(true)
const sq3ImageVisible = ref(false)
//
@ -59,13 +58,6 @@ watch(() => props.active, async (newActive) => {
}
})
//
const handleFuClick = () => {
fuClickAreaVisible.value = false
sq3ImageVisible.value = true
emit('collect-seal')
}
// URL
const generateImageUrl = (name) => {
const url = new URL(`/static/wfj/${name}.jpg`, import.meta.url)
@ -80,15 +72,26 @@ const images = [
{ src: generateImageUrl('img3'), title: '' },
{ src: generateImageUrl('img4'), title: '' }
]
const currentImageIndex = ref(0)
//
const prevImage = () => {
currentImageIndex.value = (currentImageIndex.value - 1 + images.length) % images.length
//
const galleryVisible = ref(false)
const currentGalleryIndex = ref(0)
//
const openGallery = (index) => {
currentGalleryIndex.value = index
galleryVisible.value = true
// sq3
if (!sq3ImageVisible.value) {
sq3ImageVisible.value = true
emit('collect-seal')
}
}
const nextImage = () => {
currentImageIndex.value = (currentImageIndex.value + 1) % images.length
//
const closeGallery = () => {
galleryVisible.value = false
}
//
@ -114,17 +117,6 @@ onMounted(() => {
<img src="/static/bg/bg3.jpg" alt="王府井商圈" class="background-image" />
</div>
<!-- 福字点击区域 -->
<FuClickArea
:visible="fuClickAreaVisible"
:x-range="630"
:y-range="900"
:y-start="150"
:fu-width="100"
:fu-height="100"
@click="handleFuClick"
/>
<!-- sq3图片 -->
<img
v-if="sq3ImageVisible"
@ -133,22 +125,22 @@ onMounted(() => {
class="sq3-image"
/>
<!-- 图片浏览组件 -->
<div class="image-gallery">
<div class="gallery-image-wrapper">
<div class="loading-overlay" v-if="isPreloading">
<div class="loading-spinner"></div>
</div>
<div class="nav-btn prev-btn" @click="prevImage">
<img src="/static/images/btn_prev.png" alt="上一张" class="nav-icon" />
</div>
<img :src="images[currentImageIndex].src" :alt="images[currentImageIndex].title" mode="widthFit" class="gallery-image" />
<div class="nav-btn next-btn" @click="nextImage">
<img src="/static/images/btn_next.png" alt="下一张" class="nav-icon" />
</div>
<!-- 热点点击区域1 -->
<div class="hotspot-area" style="left: 163rpx; top: 950rpx;" @click="openGallery(0)">
<div class="pulse-indicator">
<div class="pulse-circle"></div>
</div>
</div>
<!-- 图片浏览器弹窗 -->
<ImageGalleryModal
:visible="galleryVisible"
:images="images"
:current-index="currentGalleryIndex"
mode="without-title"
@close="closeGallery"
/>
</section>
</template>
@ -502,4 +494,47 @@ onMounted(() => {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* 热点点击区域 */
.hotspot-area {
position: absolute;
width: 150rpx;
height: 150rpx;
cursor: pointer;
z-index: 25;
display: flex;
align-items: center;
justify-content: center;
}
/* 脉冲动效 */
.pulse-indicator {
position: relative;
width: 100rpx;
height: 100rpx;
}
.pulse-circle {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
height: 100%;
border-radius: 50%;
background-color: rgba(255, 215, 0, 0.4);
border: 3rpx solid rgba(255, 215, 0, 0.8);
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0% {
transform: translate(-50%, -50%) scale(0.8);
opacity: 0.8;
}
100% {
transform: translate(-50%, -50%) scale(2);
opacity: 0;
}
}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 457 KiB

After

Width:  |  Height:  |  Size: 445 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB