Browse Source

提交转盘代码

dev
zhaoruhui 1 day ago
parent
commit
d03004aed7
  1. BIN
      src/assets/img/anniversary/-188.png
  2. BIN
      src/assets/img/anniversary/-27.png
  3. BIN
      src/assets/img/anniversary/-880.png
  4. BIN
      src/assets/img/anniversary/100.png
  5. BIN
      src/assets/img/anniversary/18.png
  6. BIN
      src/assets/img/anniversary/500.png
  7. BIN
      src/assets/img/anniversary/anniversary.png
  8. BIN
      src/assets/img/anniversary/guang.png
  9. BIN
      src/assets/img/anniversary/jiantou.png
  10. BIN
      src/assets/img/anniversary/pan.png
  11. BIN
      src/assets/img/anniversary/pandi.png
  12. BIN
      src/assets/img/anniversary/tanchuang.png
  13. BIN
      src/assets/img/anniversary/tanchuang1.png
  14. 7
      src/router/index.js
  15. 437
      src/views/platform/anniversary.vue

BIN
src/assets/img/anniversary/-188.png

After

Width: 96  |  Height: 65  |  Size: 6.8 KiB

BIN
src/assets/img/anniversary/-27.png

After

Width: 96  |  Height: 65  |  Size: 6.6 KiB

BIN
src/assets/img/anniversary/-880.png

After

Width: 96  |  Height: 65  |  Size: 5.0 KiB

BIN
src/assets/img/anniversary/100.png

After

Width: 96  |  Height: 65  |  Size: 6.3 KiB

BIN
src/assets/img/anniversary/18.png

After

Width: 96  |  Height: 65  |  Size: 5.5 KiB

BIN
src/assets/img/anniversary/500.png

After

Width: 96  |  Height: 65  |  Size: 5.9 KiB

BIN
src/assets/img/anniversary/anniversary.png

After

Width: 1207  |  Height: 679  |  Size: 766 KiB

BIN
src/assets/img/anniversary/guang.png

After

Width: 253  |  Height: 253  |  Size: 60 KiB

BIN
src/assets/img/anniversary/jiantou.png

After

Width: 72  |  Height: 90  |  Size: 8.3 KiB

BIN
src/assets/img/anniversary/pan.png

After

Width: 310  |  Height: 310  |  Size: 58 KiB

BIN
src/assets/img/anniversary/pandi.png

After

Width: 426  |  Height: 492  |  Size: 120 KiB

BIN
src/assets/img/anniversary/tanchuang.png

After

Width: 300  |  Height: 300  |  Size: 278 KiB

BIN
src/assets/img/anniversary/tanchuang1.png

After

Width: 693  |  Height: 736  |  Size: 342 KiB

7
src/router/index.js

@ -3,7 +3,7 @@ import { useAuthStore } from '../stores/auth';
const routes = [ const routes = [
{ {
path: '/', path: '/',
redirect: 'homePage'
redirect: '/anniversary'
}, },
{ {
path: '/homePage', path: '/homePage',
@ -32,6 +32,11 @@ const routes = [
path: '/login', path: '/login',
name: 'login', name: 'login',
component: () => import('../views/choujiang/Login.vue'), component: () => import('../views/choujiang/Login.vue'),
},
{
path: '/anniversary',
name: 'anniversary',
component: () => import('../views/platform/anniversary.vue'),
} }
] ]
// 创建路由实例 // 创建路由实例

437
src/views/platform/anniversary.vue

@ -0,0 +1,437 @@
<template>
<div class="container" :style="{ backgroundImage: `url(${anniversary})` }">
<div class="turntable-container">
<!-- 余额显示区域 -->
<div class="balance">{{ balance }}</div>
<!-- 光效背景 -->
<div class="guang" :style="{
backgroundImage: `url(${guang})`,
transform: `translate(-50%, -50%) rotate(${guangRotation}deg)`
}"></div>
<!-- 转盘底座 -->
<div class="pandi" :style="{ backgroundImage: `url(${pandi})` }"></div>
<!-- 转盘主体 -->
<div
class="pan"
:style="{
transform: `translate(-50%, -50%) scale(1.5) rotate(${rotation}deg)`,
backgroundImage: `url(${pan})`
}"
>
<!-- 奖品位置 -->
<div
v-for="(prize, index) in prizePositions"
:key="index"
class="prize-container"
:style="getPrizeContainerStyle(index, rotation)"
>
<!-- 奖品图片使用修改后的大小 -->
<img :src="getPrizeImage(prize.value)" class="prize-image"/>
</div>
</div>
<!-- 开始按钮 -->
<div
class="jiantou"
@click="startSpin"
:class="{ disabled: isSpinning || drawCount >= 8 }"
:style="{ backgroundImage: `url(${jiantou})` }"
></div>
<!-- 中奖结果弹窗 -->
<transition name="flip">
<div class="result-popup" v-if="showResult">
<div class="popup-overlay"></div>
<div class="popup-content">
<div class="popup-bg" :style="{ backgroundImage: `url(${tanchuang})` }">
<!-- 添加了脉冲动画效果的中奖金额 -->
<div class="prize-value" :class="{ 'pulse-animation': showResult }">{{ resultValue }}</div>
</div>
</div>
</div>
</transition>
</div>
</div>
</template>
<script setup>
import { ref, watch, onUnmounted } from 'vue'
// ========== ==========
//
const anniversary = new URL('@/assets/img/anniversary/anniversary.png', import.meta.url).href
//
const pandi = new URL('@/assets/img/anniversary/pandi.png', import.meta.url).href
//
const pan = new URL('@/assets/img/anniversary/pan.png', import.meta.url).href
//
const jiantou = new URL('@/assets/img/anniversary/jiantou.png', import.meta.url).href
//
const tanchuang = new URL('@/assets/img/anniversary/tanchuang1.png', import.meta.url).href
//
const guang = new URL('@/assets/img/anniversary/guang.png', import.meta.url).href
// ========== ==========
//
const prizePositions = [
{ value: '500', angle: 0 }, // 12
{ value: '-880', angle: 60 }, // 2
{ value: '18', angle: 120 }, // 4
{ value: '-27', angle: 180 }, // 6
{ value: '100', angle: 240 }, // 8
{ value: '-188', angle: 300 } // 10
]
// ========== ==========
const balance = ref(8000) //
const rotation = ref(0) //
const guangRotation = ref(0) //
const isSpinning = ref(false) //
const showResult = ref(false) //
const resultValue = ref('') //
const drawCount = ref(0) //
// ========== ==========
//
const prizeDistribution = ref([
'-27', '-27', '-27', '-27', // -27
'18', '18', // 18
'100', // 100
'-188' // -188
])
// ========== ==========
const prizeImages = {
'18': new URL('@/assets/img/anniversary/18.png', import.meta.url).href,
'-27': new URL('@/assets/img/anniversary/-27.png', import.meta.url).href,
'100': new URL('@/assets/img/anniversary/100.png', import.meta.url).href,
'-188': new URL('@/assets/img/anniversary/-188.png', import.meta.url).href,
'500': new URL('@/assets/img/anniversary/500.png', import.meta.url).href,
'-880': new URL('@/assets/img/anniversary/-880.png', import.meta.url).href
}
// ========== ==========
let guangRotationInterval = null //
//
watch(showResult, (newVal) => {
if (!newVal && drawCount.value < 8) {
startGuangRotation() // 8
} else {
stopGuangRotation() //
}
})
//
onUnmounted(() => {
stopGuangRotation()
})
//
const startGuangRotation = () => {
if (guangRotationInterval) return
guangRotationInterval = setInterval(() => {
guangRotation.value = (guangRotation.value + 2) % 360 // 10ms2
}, 5)
}
//
const stopGuangRotation = () => {
if (guangRotationInterval) {
clearInterval(guangRotationInterval)
guangRotationInterval = null
}
}
//
const getPrizeImage = (prize) => {
return prizeImages[prize] || ''
}
//
const getPrizeContainerStyle = (index, currentRotation) => {
const prizeAngle = prizePositions[index].angle //
const radius = 100 //
const radian = prizeAngle * Math.PI / 180 //
// x,y
const x = Math.sin(radian) * radius
const y = -Math.cos(radian) * radius
// 使
const compensateRotation = -currentRotation
return {
position: 'absolute',
left: '50%',
top: '50%',
width: '80px',
height: '80px',
marginLeft: '-40px', //
marginTop: '-40px', //
transform: `translate(${x}px, ${y}px) rotate(${compensateRotation}deg)`,
transformOrigin: 'center center',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
transition: 'transform 5s cubic-bezier(0.17, 0.67, 0.21, 0.99)' //
}
}
//
const startSpin = () => {
// 8
if (isSpinning.value || drawCount.value >= 8) return
isSpinning.value = true //
showResult.value = false //
stopGuangRotation() //
//
const randomIndex = Math.floor(Math.random() * prizeDistribution.value.length)
const selectedPrize = prizeDistribution.value[randomIndex]
//
prizeDistribution.value.splice(randomIndex, 1)
//
const targetPrize = prizePositions.find(p => p.value === selectedPrize)
if (!targetPrize) {
isSpinning.value = false
return
}
//
const currentAngle = rotation.value % 360
let remainingAngle = (720 - currentAngle - targetPrize.angle) % 360
// 4(1440)
const totalRotation = rotation.value + 1440 + remainingAngle
//
rotation.value = totalRotation
// 5
setTimeout(() => {
isSpinning.value = false
drawCount.value++
resultValue.value = selectedPrize
showResult.value = true
// 2
setTimeout(() => {
showResult.value = false
balance.value += parseInt(selectedPrize)
}, 2500)
}, 5000)
}
</script>
<style scoped>
/* 容器样式 */
.container {
width: 100vw;
height: 100vh;
background-image: url(${anniversary});
background-size: 100% auto; /* 背景图宽度100%,高度自适应 */
background-position: center center;
background-repeat: no-repeat;
background-color: #000; /* 黑色背景 */
overflow: hidden;
position: relative;
}
/* 转盘容器 */
.turntable-container {
position: relative;
width: 500px;
height: 500px;
margin: auto auto 10px; /* 居中 */
}
/* 余额显示样式 */
.balance {
position: absolute;
top: -1%;
left: 50%;
transform: translateX(-50%);
font-size: 120px;
text-shadow: 0 0 20px rgba(255, 215, 0, 0.5); /* 金色发光效果 */
font-weight: 900;
color: rgb(255,214,66); /* 金色文字 */
z-index: 1000;
width: 150%;
text-align: center;
font-family: 'Arial Black', Gadget, sans-serif;
letter-spacing: 2px;
}
/* 光效样式 */
.guang {
position: absolute;
top: 15%;
left: 50%;
transform: translateX(-50%);
width: 500px;
height: 400px;
background-size: contain;
background-position: center;
background-repeat: no-repeat;
z-index: 1;
transform-origin: center center; /* 旋转中心 */
}
/* 转盘底座样式 */
.pandi {
position: absolute;
width: 90%;
height: 90%;
left: 50%;
transform: translateX(-50%) scale(1.8); /* 放大1.8倍 */
bottom: -65%;
background-size: contain;
background-position: center bottom;
background-repeat: no-repeat;
z-index: 2;
}
/* 转盘主体样式 */
.pan {
position: absolute;
width: 67%;
height: 67%;
bottom: -78.5%;
left: 48%;
transform-origin: center center; /* 旋转中心 */
background-size: contain;
background-position: center;
background-repeat: no-repeat;
z-index: 3;
transition: transform 5s cubic-bezier(0.17, 0.67, 0.21, 0.99); /* 平滑旋转动画 */
}
/* 奖品容器样式 */
.prize-container {
pointer-events: none; /* 禁止鼠标事件 */
}
/* 奖品图片样式 - 修改为更大尺寸 */
.prize-image {
width: auto;
height: 70px; /* 从60px增大到70px */
max-width: 90px; /* 从80px增大到90px */
object-fit: contain; /* 保持纵横比 */
}
/* 开始按钮样式 */
.jiantou {
position: absolute;
width: 15%;
height: 15%;
bottom: -25.4%;
left: 48%;
transform: translate(-50%, -50%) scale(1.5); /* 放大1.5倍 */
background-size: contain;
background-position: center;
background-repeat: no-repeat;
z-index: 5;
cursor: pointer;
}
/* 禁用状态的开始按钮 */
.jiantou.disabled {
cursor: not-allowed;
opacity: 1; /* 修改为完全不透明 */
filter: grayscale(3 0%); /* 灰度效果表示禁用 */
}
/* 结果弹窗样式 */
.result-popup {
position: fixed;
top: -7%;
left: -1.5%;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: flex-start;
z-index: 100;
}
/* 弹窗内容 */
.popup-content {
position: relative;
z-index: 101;
}
/* 弹窗背景 */
.popup-bg {
width: 900px;
height: 900px;
background-size: contain;
background-position: center;
background-repeat: no-repeat;
display: flex;
justify-content: center;
top: 80%;
}
/* 奖品值样式 */
.prize-value {
font-size: 120px;
color: rgb(255,214,66); /* 金色文字 */
font-weight: 900;
text-shadow: 0 0 20px rgba(255, 215, 0, 0.5); /* 发光效果 */
margin-top: 230px;
font-family: 'Arial Black', Gadget, sans-serif;
}
/* 添加的脉冲动画效果 */
.pulse-animation {
animation: pulse 1s infinite alternate; /* 无限循环交替动画 */
}
/* 脉冲动画关键帧 */
@keyframes pulse {
0% {
transform: scale(1.1); /* 原始大小 */
text-shadow: 0 0 20px rgba(255, 215, 0, 0.5);
}
100% {
transform: scale(1); /* 放大10% */
text-shadow: 0 0 30px rgba(255, 215, 0, 0.8); /* 更强的发光效果 */
}
}
/* 弹窗翻转动画 */
.flip-enter-active {
animation: flipIn 0.01s ease-out;
}
.flip-leave-active {
animation: flipOut 0.1s ease-in;
}
/* 弹窗进入动画 */
@keyframes flipIn {
0% {
transform: perspective(600px) rotateY(30deg); /* 从侧面翻转 */
opacity: 0;
}
100% {
transform: perspective(600px) rotateY(0deg); /* 转到正面 */
opacity: 1;
}
}
/* 弹窗退出动画 */
@keyframes flipOut {
0% {
transform: perspective(600px) rotateY(0deg); /* 从正面开始 */
opacity: 1;
}
100% {
transform: perspective(600px) rotateY(60deg); /* 转到侧面 */
opacity: 0;
}
}
</style>
Loading…
Cancel
Save