update
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 18 KiB |
BIN
src/assets/video/1_stab_chf3_rhea1.mp4
Normal 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;
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||