-
BINsrc/assets/img/liveEvent/bg.png
-
BINsrc/assets/img/liveEvent/bg1.png
-
BINsrc/assets/img/liveEvent/close.png
-
BINsrc/assets/img/liveEvent/notice.png
-
BINsrc/assets/img/liveEvent/rotate.png
-
BINsrc/assets/img/liveEvent/show.png
-
BINsrc/assets/img/liveEvent/tanchuang3.png
-
BINsrc/assets/img/liveEvent/tanchuang4.png
-
BINsrc/assets/img/liveEvent/wheel.png
-
7src/router/index.js
-
287src/views/platform/liveEvent.vue
After Width: 1920 | Height: 1080 | Size: 1.8 MiB |
After Width: 3840 | Height: 2160 | Size: 1.8 MiB |
After Width: 104 | Height: 104 | Size: 3.8 KiB |
After Width: 498 | Height: 126 | Size: 18 KiB |
After Width: 430 | Height: 492 | Size: 194 KiB |
After Width: 1190 | Height: 254 | Size: 130 KiB |
After Width: 1710 | Height: 1238 | Size: 1.1 MiB |
After Width: 1710 | Height: 1238 | Size: 1.5 MiB |
After Width: 1360 | Height: 1360 | Size: 2.5 MiB |
@ -0,0 +1,287 @@ |
|||||
|
<template> |
||||
|
<div class="wheel-page"> |
||||
|
<!-- 背景 --> |
||||
|
<div class="bg-container"> |
||||
|
<img class="bg-image" :src="bgImage" alt="Background" /> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 转盘 + 按钮 --> |
||||
|
<div class="wheel-container"> |
||||
|
<img |
||||
|
class="wheel" |
||||
|
:src="wheelImage" |
||||
|
alt="Wheel" |
||||
|
:style="{ transform: `rotate(${rotationDegrees}deg)` }" |
||||
|
/> |
||||
|
<img |
||||
|
class="rotate-btn" |
||||
|
:src="rotateImage" |
||||
|
alt="Rotate Button" |
||||
|
:class="{ disabled: isRotated }" |
||||
|
@click="startRotation" |
||||
|
/> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 弹窗 --> |
||||
|
<div class="dialog-overlay" v-if="showDialog"> |
||||
|
<div class="dialog-content"> |
||||
|
<img class="dialog-bg" :src="tanchuangImage" alt="Dialog Background" /> |
||||
|
<img class="close-btn" :src="closeImage" alt="Close" @click="closeDialog" /> |
||||
|
<img class="notice-img" :src="noticeImage" alt="Notice" /> |
||||
|
<div class="show-container"> |
||||
|
<img class="show-bg" :src="showImage" alt="Show Background" /> |
||||
|
<div class="prize-number">-1880</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
/* -------------------- 图片引入 -------------------- */ |
||||
|
import bgImage from '@/assets/img/liveEvent/bg.png' |
||||
|
import wheelImage from '@/assets/img/liveEvent/wheel.png' |
||||
|
import rotateImage from '@/assets/img/liveEvent/rotate.png' |
||||
|
import tanchuangImage from '@/assets/img/liveEvent/tanchuang4.png' |
||||
|
import closeImage from '@/assets/img/liveEvent/close.png' |
||||
|
import noticeImage from '@/assets/img/liveEvent/notice.png' |
||||
|
import showImage from '@/assets/img/liveEvent/show.png' |
||||
|
|
||||
|
/* -------------------- 核心常量 -------------------- */ |
||||
|
const SEGMENT = 360 / 7 |
||||
|
const TARGET_ANGLE = 360 - SEGMENT // 308.57° → 12 点指向 -1880 区域中心 |
||||
|
|
||||
|
/* -------------------- 响应式状态 -------------------- */ |
||||
|
import { ref, onUnmounted } from 'vue' |
||||
|
|
||||
|
const isRotated = ref(false) // 永久标志:true 后永不恢复 |
||||
|
const showDialog = ref(false) |
||||
|
const rotationDegrees = ref(0) |
||||
|
let rotationTimeout = null |
||||
|
|
||||
|
/* -------------------- 仅允许转一次 -------------------- */ |
||||
|
function startRotation() { |
||||
|
if (isRotated.value) return |
||||
|
isRotated.value = true |
||||
|
|
||||
|
const current = rotationDegrees.value % 360 |
||||
|
const extra = 2160 // 6 圈(可任意 360 倍数) |
||||
|
rotationDegrees.value = extra + TARGET_ANGLE - current |
||||
|
|
||||
|
rotationTimeout = setTimeout(() => (showDialog.value = true), 4000) |
||||
|
} |
||||
|
|
||||
|
/* -------------------- 关闭弹窗(不再重置按钮)-------------------- */ |
||||
|
function closeDialog() { |
||||
|
showDialog.value = false |
||||
|
// 不再 isRotated.value = false,按钮永久禁用 |
||||
|
} |
||||
|
|
||||
|
onUnmounted(() => { |
||||
|
if (rotationTimeout) { |
||||
|
clearTimeout(rotationTimeout) |
||||
|
rotationTimeout = null |
||||
|
} |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
/* ---------- 基础重置 ---------- */ |
||||
|
* { |
||||
|
margin: 0; |
||||
|
padding: 0; |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
.wheel-page { |
||||
|
width: 100vw; |
||||
|
height: 100vh; |
||||
|
position: relative; |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
/* ---------- 背景 ---------- */ |
||||
|
.bg-container { |
||||
|
position: absolute; |
||||
|
inset: 0; |
||||
|
z-index: 1; |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
} |
||||
|
.bg-image { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
object-fit: cover; |
||||
|
object-position: center 42%; |
||||
|
} |
||||
|
|
||||
|
/* ---------- 转盘容器(放大 + 下移) ---------- */ |
||||
|
.wheel-container { |
||||
|
position: relative; |
||||
|
z-index: 2; |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
width: 600px; |
||||
|
height: 600px; |
||||
|
max-width: 85vmin; |
||||
|
max-height: 85vmin; |
||||
|
margin-top: 60px; |
||||
|
margin-bottom: 2%; |
||||
|
transform: translateY(40px); |
||||
|
} |
||||
|
|
||||
|
/* ---------- 转盘 ---------- */ |
||||
|
.wheel { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
transition: transform 4s cubic-bezier(0.3, 0.1, 0.1, 1); |
||||
|
transform-origin: center; |
||||
|
} |
||||
|
|
||||
|
/* ---------- 按钮(永久一次)---------- */ |
||||
|
.rotate-btn { |
||||
|
position: absolute; |
||||
|
top: 50%; |
||||
|
left: 50%; |
||||
|
transform: translate(-50%, -50%); /* 几何中心对齐 */ |
||||
|
width: 215px; /* 原图宽度 */ |
||||
|
aspect-ratio: 1 / 1; /* 强制正方形盒子,高度=215px */ |
||||
|
cursor: pointer; |
||||
|
z-index: 3; |
||||
|
transition: transform 0.2s, opacity 0.2s, filter 0.2s; |
||||
|
object-fit: contain; /* 原图等比完整显示 */ |
||||
|
object-position: center; |
||||
|
} |
||||
|
.rotate-btn:hover:not(.disabled) { |
||||
|
transform: translate(-50%, -50%) scale(1.05); |
||||
|
} |
||||
|
.rotate-btn.disabled { |
||||
|
cursor: not-allowed; |
||||
|
opacity: 1; |
||||
|
filter: grayscale(40%); |
||||
|
} |
||||
|
|
||||
|
/* ---------- 弹窗 ---------- */ |
||||
|
.dialog-overlay { |
||||
|
position: fixed; |
||||
|
inset: 0; |
||||
|
background: rgba(0, 0, 0, 0.7); |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
z-index: 10; |
||||
|
animation: fadeIn 0.5s; |
||||
|
} |
||||
|
.dialog-content { |
||||
|
position: relative; |
||||
|
width: 600px; |
||||
|
height: 412px; |
||||
|
max-width: 85vw; |
||||
|
max-height: 65vh; |
||||
|
} |
||||
|
.dialog-bg { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
object-fit: contain; |
||||
|
} |
||||
|
.close-btn { |
||||
|
position: absolute; |
||||
|
top: 22%; |
||||
|
right: 13.2%; |
||||
|
width: 5%; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
.notice-img { |
||||
|
position: absolute; |
||||
|
top: 22%; |
||||
|
left: 50%; |
||||
|
transform: translateX(-50%); |
||||
|
width: 33%; |
||||
|
} |
||||
|
.show-container { |
||||
|
position: absolute; |
||||
|
top: 41%; |
||||
|
left: 0; |
||||
|
width: 100%; |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
} |
||||
|
.show-bg { |
||||
|
width: 71.6%; |
||||
|
} |
||||
|
.prize-number { |
||||
|
position: absolute; |
||||
|
top: 50%; |
||||
|
left: 50%; |
||||
|
transform: translate(-50%, -50%); |
||||
|
font-size: 66px; |
||||
|
font-weight: bold; |
||||
|
color: #ffeb3b; |
||||
|
text-shadow: 0 0 10px rgba(255, 235, 59, 0.8); |
||||
|
animation: pulse 1s infinite alternate; |
||||
|
} |
||||
|
|
||||
|
/* ---------- 动画 ---------- */ |
||||
|
@keyframes fadeIn { |
||||
|
from { |
||||
|
opacity: 0; |
||||
|
} |
||||
|
to { |
||||
|
opacity: 1; |
||||
|
} |
||||
|
} |
||||
|
@keyframes pulse { |
||||
|
from { |
||||
|
transform: translate(-50%, -50%) scale(1); |
||||
|
text-shadow: 0 0 10px rgba(255, 235, 59, 0.8); |
||||
|
} |
||||
|
to { |
||||
|
transform: translate(-50%, -50%) scale(1.1); |
||||
|
text-shadow: 0 0 20px rgba(255, 235, 59, 1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* ---------- 响应式 ---------- */ |
||||
|
@media (max-width: 900px) { |
||||
|
.wheel-container { |
||||
|
width: 75vmin; |
||||
|
height: 75vmin; |
||||
|
margin-top: 40px; |
||||
|
} |
||||
|
} |
||||
|
@media (max-width: 600px) { |
||||
|
.wheel-container { |
||||
|
width: 80vmin; |
||||
|
height: 80vmin; |
||||
|
margin-top: 30px; |
||||
|
} |
||||
|
.dialog-content { |
||||
|
max-height: 55vh; |
||||
|
} |
||||
|
} |
||||
|
@media (max-height: 600px) and (orientation: landscape) { |
||||
|
.wheel-container { |
||||
|
width: 65vmin; |
||||
|
height: 65vmin; |
||||
|
margin-top: 20px; |
||||
|
} |
||||
|
.bg-image { |
||||
|
object-position: center 30%; |
||||
|
} |
||||
|
} |
||||
|
@media (max-width: 375px) { |
||||
|
.wheel-container { |
||||
|
width: 70vmin; |
||||
|
height: 70vmin; |
||||
|
margin-top: 20px; |
||||
|
} |
||||
|
.dialog-content { |
||||
|
max-width: 80vw; |
||||
|
max-height: 50vh; |
||||
|
} |
||||
|
} |
||||
|
</style> |