This commit is contained in:
yixu
2025-09-16 16:21:41 +08:00
parent c68b99abd5
commit 9ac7d56e88
14 changed files with 178 additions and 44 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

View File

@@ -372,7 +372,8 @@ const imagePosition = (index) => {
return { return {
top : pos.top, top : pos.top,
left : pos.left, left : pos.left,
width: pos.width width: pos.width,
height: pos.width
}; };
}; };
@@ -495,12 +496,13 @@ import generateImg from '../assets/images/generate-img-bg.webp'
<!-- 图片预览 --> <!-- 图片预览 -->
<div v-if="item.imageUrl" class="preview-container" :style="{ pointerEvents: displayMyPhotoBtn ? 'none' : 'auto' }"> <div v-if="item.imageUrl" class="preview-container" :style="{ pointerEvents: displayMyPhotoBtn ? 'none' : 'auto' }">
<div class="preview-image upload-btn" :style="imagePosition(index + 1)">
<img <img
:src="item.imageUrl" :src="item.imageUrl"
alt="预览图" alt="预览图"
class="preview-image upload-btn" class="pre-img"
:style="imagePosition(index + 1)"
/> />
</div>
<button @click.stop.prevent="clearUploadFile(index)" :style="buttonUploadedPosition(index + 1)" style="position: absolute;"> <button @click.stop.prevent="clearUploadFile(index)" :style="buttonUploadedPosition(index + 1)" style="position: absolute;">
<div :style="{ width: buttonUploadedPosition(index + 1)['--item-width'] }" > <div :style="{ width: buttonUploadedPosition(index + 1)['--item-width'] }" >
<img src="../assets/images/img-uploaded.webp" class="delete-btn upload-img-wrapper" alt="删除图片"> <img src="../assets/images/img-uploaded.webp" class="delete-btn upload-img-wrapper" alt="删除图片">
@@ -525,6 +527,11 @@ import generateImg from '../assets/images/generate-img-bg.webp'
</template> </template>
<style scoped> <style scoped>
.pre-img {
width: 100%;
height: 100%;
border-radius: 50%;
}
.main { .main {
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
@@ -628,8 +635,9 @@ import generateImg from '../assets/images/generate-img-bg.webp'
.home-wrapper { .home-wrapper {
width: 100vw; width: 100vw;
height: 200vw; height: 200vw;
background-size: cover; background-size: 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
margin-top: -8vw;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
@@ -679,6 +687,7 @@ import generateImg from '../assets/images/generate-img-bg.webp'
} }
.item-3 { .item-3 {
position: fixed !important;
width: 54vw; width: 54vw;
bottom: 6vw; bottom: 6vw;
animation-delay: 0s; animation-delay: 0s;

View File

@@ -42,15 +42,17 @@ const closeTodoList = () => {
.home-wrapper { .home-wrapper {
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
min-height: 100vh;
background-image: url('../assets/images/generate-img-confirm.webp'); background-image: url('../assets/images/generate-img-confirm.webp');
background-size: cover; background-size: 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center bottom; /* 从底部开始显示,上方可截断 */
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: flex-end; /* 内容向底部对齐 */
align-items: center; align-items: center;
position: relative; position: relative;
min-height: -webkit-fill-available; overflow: hidden; /* 隐藏溢出的上方内容 */
} }
.scene-item { .scene-item {
@@ -60,6 +62,7 @@ const closeTodoList = () => {
overflow: hidden; overflow: hidden;
border: 3px solid transparent; border: 3px solid transparent;
animation: float 4s ease-in-out infinite; animation: float 4s ease-in-out infinite;
z-index: 10;
} }
.scene-item:hover { .scene-item:hover {
@@ -75,14 +78,16 @@ const closeTodoList = () => {
.item-1 { .item-1 {
width: 10vw; width: 10vw;
top: 15%; bottom: 160vw;
right: 4%; right: 4%;
animation-delay: 0s; animation-delay: 0s;
} }
.item-2 { .item-2 {
width: 47vw; width: 47vw;
bottom: 5vw; bottom: max(5vh, 5vw);
left: 50%;
transform: translateX(-50%);
animation-delay: 0s; animation-delay: 0s;
} }
</style> </style>

View File

@@ -2,6 +2,7 @@
import { ref, computed, watch, onMounted } from "vue" import { ref, computed, watch, onMounted } from "vue"
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import faceFamily from "../assets/audio/faceFamily.mp3" import faceFamily from "../assets/audio/faceFamily.mp3"
import backgroundVideo from "../assets/video/1_stab_chf3_rhea1.mp4"
import MyPhoto from './MyPhoto.vue' import MyPhoto from './MyPhoto.vue'
import PhotoSquare from './PhotoSquare.vue' import PhotoSquare from './PhotoSquare.vue'
import globalToastEvent, { ToastType } from '../globalToastEvent'; import globalToastEvent, { ToastType } from '../globalToastEvent';
@@ -14,42 +15,138 @@ defineProps({
}) })
const isMusicOn = ref(false); const isMusicOn = ref(false);
const audioElement = ref(null); const audioElement = ref(null);
const videoElement = ref(null);
// 初始化全局音频实例
const initGlobalAudio = () => {
if (!globalStore.globalAudio) {
globalStore.globalAudio = new Audio(faceFamily);
globalStore.globalAudio.loop = true; // 设置循环播放
globalStore.globalAudio.preload = 'auto';
// 监听音频事件
globalStore.globalAudio.addEventListener('play', () => {
isMusicOn.value = true;
});
globalStore.globalAudio.addEventListener('pause', () => {
isMusicOn.value = false;
});
globalStore.globalAudio.addEventListener('ended', () => {
isMusicOn.value = false;
});
}
audioElement.value = globalStore.globalAudio;
// 同步当前音乐状态
isMusicOn.value = !globalStore.globalAudio.paused;
};
onMounted(() => { onMounted(() => {
audioElement.value = new Audio(faceFamily); initGlobalAudio();
tryAutoPlay(); initVideo();
checkAndPlayAudio();
}) })
// 尝试自动播放 // 检查并播放音频
const tryAutoPlay = () => { const checkAndPlayAudio = () => {
// 先加载音频 if (!audioElement.value) return;
audioElement.value.load();
// 尝试播放 // 如果用户曾经手动静音,则不自动播放
if (globalStore.userMutedMusic) {
console.log('用户曾经手动静音,不自动播放音乐');
isMusicOn.value = false;
return;
}
// 检查音频是否已在播放
if (!audioElement.value.paused) {
console.log('音频已在播放,跳过重复播放');
isMusicOn.value = true;
return;
}
// 只在首次访问或音乐没有被用户手动静音时才尝试自动播放
if (globalStore.isFirstVisitHomePage || !globalStore.userMutedMusic) {
const playPromise = audioElement.value.play(); const playPromise = audioElement.value.play();
if (playPromise !== undefined) { if (playPromise !== undefined) {
playPromise.then(() => { playPromise.then(() => {
// 自动播放成功 // 自动播放成功
isMusicOn.value = true; isMusicOn.value = true;
console.log("自动播放成功"); globalStore.isFirstVisitHomePage = false;
console.log('自动播放成功');
}) })
.catch(error => { .catch(error => {
// 自动播放被阻止 // 自动播放被阻止
console.log("自动播放被阻止,需要用户交互:", error); console.log('自动播放被阻止,需要用户交互:', error);
isMusicOn.value = false; isMusicOn.value = false;
audioElement.value.pause(); audioElement.value.pause();
}); });
} }
} else {
// 非首次访问且用户没有手动静音,但音乐当前暂停,则保持暂停状态
isMusicOn.value = false;
}
};
// 初始化视频
const initVideo = () => {
// 等待DOM渲染完成后初始化视频
setTimeout(() => {
const video = document.querySelector('.background-video');
if (video) {
videoElement.value = video;
// 确保视频静音并循环播放
video.muted = true;
video.loop = true;
video.autoplay = true;
// 处理移动设备的自动播放限制
video.addEventListener('canplaythrough', () => {
video.play().catch(error => {
console.log('视频自动播放被阻止:', error);
});
});
// 确保视频在加载完成后开始播放
if (video.readyState >= 3) {
video.play().catch(error => {
console.log('视频播放失败:', error);
});
}
}
}, 100);
}; };
// 播放/暂停切换 // 播放/暂停切换
const toggleMusicState = () => { const toggleMusicState = () => {
isMusicOn.value = !isMusicOn.value; if (!audioElement.value) {
if (!isMusicOn.value) { initGlobalAudio();
}
if (isMusicOn.value) {
// 当前在播放,用户点击静音
audioElement.value.pause(); audioElement.value.pause();
globalStore.userMutedMusic = true; // 记录用户手动静音
isMusicOn.value = false;
console.log('用户手动静音音乐');
} else { } else {
audioElement.value.play().catch(error => { // 当前暂停,用户点击播放
console.log("播放失败:", error); const playPromise = audioElement.value.play();
if (playPromise !== undefined) {
playPromise.then(() => {
globalStore.userMutedMusic = false; // 用户重新开启音乐,清除静音标记
isMusicOn.value = true;
console.log('用户手动开启音乐');
})
.catch(error => {
console.log('播放失败:', error);
isMusicOn.value = false;
}); });
} }
}
}; };
const navigateTodoList = () => { const navigateTodoList = () => {
@@ -175,6 +272,16 @@ watch(() => mergeId, async (newVal) => {
<template> <template>
<div :show="show" class="main"> <div :show="show" class="main">
<div class="home-wrapper"> <div class="home-wrapper">
<!-- 视频背景 -->
<video
class="background-video"
:src="backgroundVideo"
autoplay
loop
muted
playsinline
></video>
<div class="scene-item item-1" @click="handleLottery" :class="{ 'disabled': globalStore.draw_chances <= 0 }"> <div class="scene-item item-1" @click="handleLottery" :class="{ 'disabled': globalStore.draw_chances <= 0 }">
<img src="../assets/images/lottery.webp" alt="抽奖"> <img src="../assets/images/lottery.webp" alt="抽奖">
<div class="lottery-main"> <div class="lottery-main">
@@ -227,15 +334,24 @@ watch(() => mergeId, async (newVal) => {
.home-wrapper { .home-wrapper {
width: 100vw; width: 100vw;
height: 200vw; height: 200vw;
background-image: url('../assets/images/home-bg.webp');
background-size: cover;
background-repeat: no-repeat;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
position: relative; position: relative;
min-height: -webkit-fill-available; min-height: -webkit-fill-available;
overflow: hidden; /* 防止视频溢出 */
}
/* 视频背景样式 */
.background-video {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover; /* 保持视频比例并填满容器 */
z-index: 0; /* 置于最底层 */
} }
.scene-item { .scene-item {
@@ -245,6 +361,7 @@ watch(() => mergeId, async (newVal) => {
overflow: hidden; overflow: hidden;
border: 3px solid transparent; border: 3px solid transparent;
animation: float 4s ease-in-out infinite; animation: float 4s ease-in-out infinite;
z-index: 10; /* 确保按钮显示在视频之上 */
} }
.scene-item:hover { .scene-item:hover {

View File

@@ -197,7 +197,7 @@ const handleHaibao = async () => {
haibaoSave.add(url, 64, 250) haibaoSave.add(url, 64, 250)
haibaoSave.add(qrcode, 115, 1875) haibaoSave.add(qrcode, 115, 1875)
haibaoSave.draw().then(() => { haibaoSave.draw().then(() => {
haibaoSave.text(infos.nickname, haibaoSave.canvas.width / 2, 200, { font: 'bold 50px Arial', color: '#ffee6f' }) haibaoSave.text(infos.nickname + '的全家福', haibaoSave.canvas.width / 2, 200, { font: 'bold 50px Arial', color: '#fcf2b3' })
haibaoSave.generate({ mimeType: 'image/png' }).then(url => { haibaoSave.generate({ mimeType: 'image/png' }).then(url => {
haibaoUrl.value = url haibaoUrl.value = url
loading.hide() loading.hide()

View File

@@ -83,7 +83,7 @@ const handleHaibao = async () => {
haibaoSave.add(url, 64, 250) haibaoSave.add(url, 64, 250)
haibaoSave.add(qrcode, 115, 1875) haibaoSave.add(qrcode, 115, 1875)
haibaoSave.draw().then(() => { haibaoSave.draw().then(() => {
haibaoSave.text(infos.nickname, haibaoSave.canvas.width / 2, 200, { font: 'bold 50px Arial', color: '#ffee6f' }) haibaoSave.text(infos.nickname + '的全家福', haibaoSave.canvas.width / 2, 200, { font: 'bold 50px Arial', color: '#fcf2b3' })
haibaoSave.generate({ mimeType: 'image/png' }).then(url => { haibaoSave.generate({ mimeType: 'image/png' }).then(url => {
haibaoUrl.value = url haibaoUrl.value = url
loading.hide() loading.hide()

View File

@@ -74,7 +74,7 @@ const handleHaibao = async () => {
haibaoSave.add(url, 64, 250) haibaoSave.add(url, 64, 250)
haibaoSave.add(qrcode, 115, 1875) haibaoSave.add(qrcode, 115, 1875)
haibaoSave.draw().then(() => { haibaoSave.draw().then(() => {
haibaoSave.text(infos.nickname, haibaoSave.canvas.width / 2, 200, { font: 'bold 50px Arial', color: '#ffee6f' }) haibaoSave.text(infos.nickname + '的全家福', haibaoSave.canvas.width / 2, 200, { font: 'bold 50px Arial', color: '#fcf2b3' })
haibaoSave.generate({ mimeType: 'image/png' }).then(url => { haibaoSave.generate({ mimeType: 'image/png' }).then(url => {
haibaoUrl.value = url haibaoUrl.value = url
loading.hide() loading.hide()

View File

@@ -1,6 +1,9 @@
import { reactive } from "vue" import { reactive } from "vue"
export const globalStore = reactive({ export const globalStore = reactive({
globalAudio: null,
userMutedMusic: false, // 用户是否手动静音了音乐
isFirstVisitHomePage: true, // 是否首次访问首页
select_template: '', select_template: '',
people_count: 0, people_count: 0,
draw_chances: 0, draw_chances: 0,