refactor: 重构首页代码,提取处理函数

This commit is contained in:
LOG1997
2025-09-21 20:24:53 +08:00
parent b1077b23e6
commit 88e773da37
6 changed files with 362 additions and 347 deletions

3
pnpm-lock.yaml generated
View File

@@ -29,6 +29,9 @@ importers:
localforage: localforage:
specifier: ^1.10.0 specifier: ^1.10.0
version: 1.10.0 version: 1.10.0
lodash-es:
specifier: ^4.17.21
version: 4.17.21
markdown-it: markdown-it:
specifier: ^14.1.0 specifier: ^14.1.0
version: 14.1.0 version: 14.1.0

View File

@@ -1,5 +1,11 @@
import dayjs from 'dayjs' import dayjs from 'dayjs'
// 筛选人员数据
/**
* @description: 处理表格数据添加x,y,id等信息
* @param tableData 表格数据
* @param localRowCount 每一行有多少个元素
* @returns 处理后的表格数据
*/
export function filterData(tableData: any[], localRowCount: number) { export function filterData(tableData: any[], localRowCount: number) {
const dataLength = tableData.length const dataLength = tableData.length
let j = 0 let j = 0

View File

@@ -0,0 +1,138 @@
.label {
width: 120px;
}
.prize-list-enter-active {
-webkit-animation: slide-right 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
animation: slide-right 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
}
.prize-list-leave-active {
-webkit-animation: slide-left 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
animation: slide-left 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
}
.prize-operate-enter-active {
// 延时显示
animation: show-operate 0.6s;
-webkit-animation: show-operate 0.6s;
}
.current-prize {
position: relative;
display: block;
overflow: hidden;
isolation: isolate;
border-radius: 20px;
padding: 3px;
}
.current-prize::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 400%;
height: 100%;
background: linear-gradient(115deg, #4fcf70, #fad648, #a767e5, #12bcfe, #44ce7b);
background-size: 25% 100%;
animation: an-at-keyframe-css-at-rule-that-translates-via-the-transform-property-the-background-by-negative-25-percent-of-its-width-so-that-it-gives-a-nice-border-animation_-We-use-the-translate-property-to-have-a-nice-transition-so-it_s-not-a-jerk-of-a-start-or-stop .75s linear infinite;
// animation-play-state: paused;
translate: -5% 0%;
transition: translate 0.25s ease-out;
animation-play-state: running;
transition-duration: 0.75s;
translate: 0% 0%;
}
.current-prize::after {
content: "";
position: absolute;
inset: 4px;
border-top-left-radius: 20px;
border-bottom-right-radius: 20px;
z-index: -1;
}
@keyframes an-at-keyframe-css-at-rule-that-translates-via-the-transform-property-the-background-by-negative-25-percent-of-its-width-so-that-it-gives-a-nice-border-animation_-We-use-the-translate-property-to-have-a-nice-transition-so-it_s-not-a-jerk-of-a-start-or-stop {
to {
transform: translateX(-25%);
}
}
@-webkit-keyframes slide-right {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
100% {
-webkit-transform: translateX(30px);
transform: translateX(30px);
}
}
@keyframes slide-right {
0% {
-webkit-transform: translateX(-200px);
transform: translateX(-200px);
}
100% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
@-webkit-keyframes slide-left {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
100% {
-webkit-transform: translateX(-100px);
transform: translateX(-100px);
}
}
@keyframes slide-left {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
100% {
-webkit-transform: translateX(-400px);
transform: translateX(-400px);
}
}
@-webkit-keyframes show-operate {
0% {
opacity: 0;
}
99% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes show-operate {
0% {
opacity: 0;
}
99% {
opacity: 0;
}
100% {
opacity: 1;
}
}

View File

@@ -1,17 +1,17 @@
<script setup lang='ts'> <script setup lang='ts'>
import type { IPrizeConfig } from '../../types/storeType' import type { IPrizeConfig } from '@/types/storeType'
import { storeToRefs } from 'pinia'
import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import defaultPrizeImage from '@/assets/images/龙.png' import defaultPrizeImage from '@/assets/images/龙.png'
import ImageSync from '@/components/ImageSync/index.vue' import ImageSync from '@/components/ImageSync/index.vue'
import EditSeparateDialog from '@/components/NumberSeparate/EditSeparateDialog.vue' import EditSeparateDialog from '@/components/NumberSeparate/EditSeparateDialog.vue'
import i18n from '@/locales/i18n' import i18n from '@/locales/i18n'
import useStore from '@/store' import useStore from '@/store'
import { storeToRefs } from 'pinia'
import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n() const { t } = useI18n()
const prizeConfig = useStore().prizeConfig const prizeConfig = useStore().prizeConfig
const globalConfig = useStore().globalConfig const globalConfig = useStore().globalConfig
@@ -318,142 +318,5 @@ onMounted(() => {
</template> </template>
<style lang='scss' scoped> <style lang='scss' scoped>
.label { @import "./index.scss";
width: 120px;
}
.prize-list-enter-active {
-webkit-animation: slide-right 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
animation: slide-right 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
}
.prize-list-leave-active {
-webkit-animation: slide-left 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
animation: slide-left 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
}
.prize-operate-enter-active {
//
animation: show-operate 0.6s;
-webkit-animation: show-operate 0.6s;
}
.current-prize {
position: relative;
display: block;
overflow: hidden;
isolation: isolate;
border-radius: 20px;
padding: 3px;
}
.current-prize::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 400%;
height: 100%;
background: linear-gradient(115deg, #4fcf70, #fad648, #a767e5, #12bcfe, #44ce7b);
background-size: 25% 100%;
animation: an-at-keyframe-css-at-rule-that-translates-via-the-transform-property-the-background-by-negative-25-percent-of-its-width-so-that-it-gives-a-nice-border-animation_-We-use-the-translate-property-to-have-a-nice-transition-so-it_s-not-a-jerk-of-a-start-or-stop .75s linear infinite;
// animation-play-state: paused;
translate: -5% 0%;
transition: translate 0.25s ease-out;
animation-play-state: running;
transition-duration: 0.75s;
translate: 0% 0%;
}
.current-prize::after {
content: "";
position: absolute;
inset: 4px;
border-top-left-radius: 20px;
border-bottom-right-radius: 20px;
z-index: -1;
}
@keyframes an-at-keyframe-css-at-rule-that-translates-via-the-transform-property-the-background-by-negative-25-percent-of-its-width-so-that-it-gives-a-nice-border-animation_-We-use-the-translate-property-to-have-a-nice-transition-so-it_s-not-a-jerk-of-a-start-or-stop {
to {
transform: translateX(-25%);
}
}
@-webkit-keyframes slide-right {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
100% {
-webkit-transform: translateX(30px);
transform: translateX(30px);
}
}
@keyframes slide-right {
0% {
-webkit-transform: translateX(-200px);
transform: translateX(-200px);
}
100% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
@-webkit-keyframes slide-left {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
100% {
-webkit-transform: translateX(-100px);
transform: translateX(-100px);
}
}
@keyframes slide-left {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
100% {
-webkit-transform: translateX(-400px);
transform: translateX(-400px);
}
}
@-webkit-keyframes show-operate {
0% {
opacity: 0;
}
99% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes show-operate {
0% {
opacity: 0;
}
99% {
opacity: 0;
}
100% {
opacity: 1;
}
}
</style> </style>

131
src/views/Home/index.ts Normal file
View File

@@ -0,0 +1,131 @@
import type { IPersonConfig } from '@/types/storeType'
import confetti from 'canvas-confetti'
import { Object3D, Vector3 } from 'three'
import { filterData } from '@/utils'
/**
* @description 初始化表格数据
* @param0 allPersonList 所有人的列表
* @param1 rowCount 行数默认是7行
* @returns 表格数据
*/
export function initTableData({ allPersonList, rowCount }: { allPersonList: IPersonConfig[], rowCount: number }): IPersonConfig[] {
let tableData: IPersonConfig[] = []
if (allPersonList.length <= 0) {
return []
}
const totalCount = rowCount * 7
const allPersonLength = allPersonList.length
if (allPersonLength < totalCount) {
tableData = Array.from({ length: totalCount }, () => JSON.parse(JSON.stringify(allPersonList))).flat()
}
else {
tableData = allPersonList.slice(0, totalCount)
}
tableData = filterData(tableData.slice(0, totalCount), rowCount)
return tableData
}
/**
* @description 横铺图形:处理数据,把每个卡片在界面的位置写入
* @param0 tableData 表格数据
* @param1 rowCount 每行有多少个元素
* @param2 cardSize 卡片的大小
* @returns Object3D[]
*/
export function createTableVertices({ tableData, rowCount, cardSize }: { tableData: IPersonConfig[], rowCount: number, cardSize: { width: number, height: number } }): Object3D[] {
const tableLen = tableData.length
const objects: Object3D[] = []
for (let i = 0; i < tableLen; i++) {
const object = new Object3D()
object.position.x = tableData[i].x * (cardSize.width + 40) - rowCount * 90
object.position.y = -tableData[i].y * (cardSize.height + 20) + 1000
object.position.z = 0
objects.push(object)
// targets.table.push(object)
}
return objects
}
/**
* @description 创建球体
* @param0 objectsLength 物体的个数
* @returns Object3D[]
*/
export function createSphereVertices({ objectsLength }: { objectsLength: number }): Object3D[] {
let i = 0
const resObjects: Object3D[] = []
// const objLength = objects.value.length
const vector = new Vector3()
for (; i < objectsLength; ++i) {
const phi = Math.acos(-1 + (2 * i) / objectsLength)
const theta = Math.sqrt(objectsLength * Math.PI) * phi
const object = new Object3D()
object.position.x = 800 * Math.cos(theta) * Math.sin(phi)
object.position.y = 800 * Math.sin(theta) * Math.sin(phi)
object.position.z = -800 * Math.cos(phi)
// rotation object
vector.copy(object.position).multiplyScalar(2)
object.lookAt(vector)
resObjects.push(object)
}
return resObjects
}
export function confettiFire() {
const duration = 3 * 1000
const end = Date.now() + duration;
(function frame() {
// launch a few confetti from the left edge
confetti({
particleCount: 2,
angle: 60,
spread: 55,
origin: { x: 0 },
})
// and launch a few from the right edge
confetti({
particleCount: 2,
angle: 120,
spread: 55,
origin: { x: 1 },
})
// keep going until we are out of time
if (Date.now() < end) {
requestAnimationFrame(frame)
}
}())
centerFire(0.25, {
spread: 26,
startVelocity: 55,
})
centerFire(0.2, {
spread: 60,
})
centerFire(0.35, {
spread: 100,
decay: 0.91,
scalar: 0.8,
})
centerFire(0.1, {
spread: 120,
startVelocity: 25,
decay: 0.92,
scalar: 1.2,
})
centerFire(0.1, {
spread: 120,
startVelocity: 45,
})
}
function centerFire(particleRatio: number, opts: any) {
const count = 200
confetti({
origin: { y: 0.7 },
...opts,
particleCount: Math.floor(count * particleRatio),
})
}

View File

@@ -1,23 +1,23 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Material, Object3D } from 'three'
import type { IPersonConfig } from '@/types/storeType' import type { IPersonConfig } from '@/types/storeType'
import type { Material } from 'three'
import StarsBackground from '@/components/StarsBackground/index.vue'
import { useElementPosition, useElementStyle } from '@/hooks/useElement'
import i18n from '@/locales/i18n'
import useStore from '@/store'
import { filterData, selectCard } from '@/utils'
import { rgba } from '@/utils/color'
import * as TWEEN from '@tweenjs/tween.js' import * as TWEEN from '@tweenjs/tween.js'
import confetti from 'canvas-confetti'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { Object3D, PerspectiveCamera, Scene, Vector3 } from 'three' import { PerspectiveCamera, Scene, Vector3 } from 'three'
import { CSS3DObject, CSS3DRenderer } from 'three-css3d' import { CSS3DObject, CSS3DRenderer } from 'three-css3d'
import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls.js' import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls.js'
import { nextTick, onMounted, onUnmounted, ref } from 'vue' import { nextTick, onMounted, onUnmounted, ref } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useToast } from 'vue-toast-notification' import { useToast } from 'vue-toast-notification'
import PrizeList from './PrizeList.vue' import StarsBackground from '@/components/StarsBackground/index.vue'
import { useElementPosition, useElementStyle } from '@/hooks/useElement'
import i18n from '@/locales/i18n'
import useStore from '@/store'
import { selectCard } from '@/utils'
import { rgba } from '@/utils/color'
import PrizeList from './components/PrizeList/index.vue'
import { confettiFire, createSphereVertices, createTableVertices, initTableData } from './index'
import 'vue-toast-notification/dist/theme-sugar.css' import 'vue-toast-notification/dist/theme-sugar.css'
const { t } = useI18n() const { t } = useI18n()
@@ -32,7 +32,14 @@ const { getAllPersonList: allPersonList, getNotPersonList: notPersonList, getNot
const { getCurrentPrize: currentPrize } = storeToRefs(prizeConfig) const { getCurrentPrize: currentPrize } = storeToRefs(prizeConfig)
const { getTopTitle: topTitle, getCardColor: cardColor, getPatterColor: patternColor, getPatternList: patternList, getTextColor: textColor, getLuckyColor: luckyColor, getCardSize: cardSize, getTextSize: textSize, getRowCount: rowCount, getBackground: homeBackground, getIsShowAvatar: isShowAvatar } = storeToRefs(globalConfig) const { getTopTitle: topTitle, getCardColor: cardColor, getPatterColor: patternColor, getPatternList: patternList, getTextColor: textColor, getLuckyColor: luckyColor, getCardSize: cardSize, getTextSize: textSize, getRowCount: rowCount, getBackground: homeBackground, getIsShowAvatar: isShowAvatar } = storeToRefs(globalConfig)
const tableData = ref<any[]>([]) const tableData = ref<any[]>([])
const currentStatus = ref(0) // 0为初始状态 1为抽奖准备状态2为抽奖中状态3为抽奖结束状态
enum LotteryStatus {
init = 0,
ready = 1,
running = 2,
end = 3,
}
const currentStatus = ref<LotteryStatus>(LotteryStatus.init) // 0为初始状态 1为抽奖准备状态2为抽奖中状态3为抽奖结束状态
const ballRotationY = ref(0) const ballRotationY = ref(0)
const containerRef = ref<HTMLElement>() const containerRef = ref<HTMLElement>()
const canOperate = ref(true) const canOperate = ref(true)
@@ -62,26 +69,6 @@ const luckyCount = ref(10)
const personPool = ref<IPersonConfig[]>([]) const personPool = ref<IPersonConfig[]>([])
const intervalTimer = ref<any>(null) const intervalTimer = ref<any>(null)
// 填充数据,填满七行
function initTableData() {
if (allPersonList.value.length <= 0) {
return
}
const totalCount = rowCount.value * 7
const originPersonData = JSON.parse(JSON.stringify(allPersonList.value))
const originPersonLength = originPersonData.length
if (originPersonLength < totalCount) {
const repeatCount = Math.ceil(totalCount / originPersonLength)
// 复制数据
for (let i = 0; i < repeatCount; i++) {
tableData.value = tableData.value.concat(JSON.parse(JSON.stringify(originPersonData)))
}
}
else {
tableData.value = originPersonData.slice(0, totalCount)
}
tableData.value = filterData(tableData.value.slice(0, totalCount), rowCount.value)
}
function init() { function init() {
const felidView = 40 const felidView = 40
const width = window.innerWidth const width = window.innerWidth
@@ -156,70 +143,12 @@ function init() {
objects.value.push(object) objects.value.push(object)
} }
// 创建横铺的界面
createTableVertices() const tableVertices = createTableVertices({ tableData: tableData.value, rowCount: rowCount.value, cardSize: cardSize.value })
createSphereVertices() targets.table = tableVertices
createHelixVertices() // 创建球体
const sphereVertices = createSphereVertices({ objectsLength: objects.value.length })
function createTableVertices() { targets.sphere = sphereVertices
const tableLen = tableData.value.length
for (let i = 0; i < tableLen; i++) {
const object = new Object3D()
object.position.x = tableData.value[i].x * (cardSize.value.width + 40) - rowCount.value * 90
object.position.y = -tableData.value[i].y * (cardSize.value.height + 20) + 1000
object.position.z = 0
targets.table.push(object)
}
}
function createSphereVertices() {
let i = 0
const objLength = objects.value.length
const vector = new Vector3()
for (; i < objLength; ++i) {
const phi = Math.acos(-1 + (2 * i) / objLength)
const theta = Math.sqrt(objLength * Math.PI) * phi
const object = new Object3D()
object.position.x = 800 * Math.cos(theta) * Math.sin(phi)
object.position.y = 800 * Math.sin(theta) * Math.sin(phi)
object.position.z = -800 * Math.cos(phi)
// rotation object
vector.copy(object.position).multiplyScalar(2)
object.lookAt(vector)
targets.sphere.push(object)
}
}
function createHelixVertices() {
let i = 0
const vector = new Vector3()
const objLength = objects.value.length
for (; i < objLength; ++i) {
const phi = i * 0.213 + Math.PI
const object = new Object3D()
object.position.x = 800 * Math.sin(phi)
object.position.y = -(i * 8) + 450
object.position.z = 800 * Math.cos(phi + Math.PI)
object.scale.set(1.1, 1.1, 1.1)
vector.x = object.position.x * 2
vector.y = object.position.y
vector.z = object.position.z * 2
object.lookAt(vector)
targets.helix.push(object)
}
}
window.addEventListener('resize', onWindowResize, false) window.addEventListener('resize', onWindowResize, false)
transform(targets.table, 1000) transform(targets.table, 1000)
render() render()
@@ -238,6 +167,7 @@ function transform(targets: any[], duration: number) {
for (let i = 0; i < objLength; ++i) { for (let i = 0; i < objLength; ++i) {
const object = objects.value[i] const object = objects.value[i]
const target = targets[i] const target = targets[i]
// console.log('target', i, target, targets)
new TWEEN.Tween(object.position) new TWEEN.Tween(object.position)
.to({ x: target.position.x, y: target.position.y, z: target.position.z }, Math.random() * duration + duration) .to({ x: target.position.x, y: target.position.y, z: target.position.z }, Math.random() * duration + duration)
.easing(TWEEN.Easing.Exponential.InOut) .easing(TWEEN.Easing.Exponential.InOut)
@@ -366,6 +296,7 @@ function render() {
renderer.value.render(scene.value, camera.value) renderer.value.render(scene.value, camera.value)
} }
} }
// 进入抽奖,从平铺转为球体
async function enterLottery() { async function enterLottery() {
if (!canOperate.value) { if (!canOperate.value) {
return return
@@ -382,7 +313,7 @@ async function enterLottery() {
} }
canOperate.value = false canOperate.value = false
await transform(targets.sphere, 1000) await transform(targets.sphere, 1000)
currentStatus.value = 1 currentStatus.value = LotteryStatus.ready
rollBall(0.1, 2000) rollBall(0.1, 2000)
} }
// 开始抽奖 // 开始抽奖
@@ -443,10 +374,10 @@ function startLottery() {
position: 'top-right', position: 'top-right',
duration: 8000, duration: 8000,
}) })
currentStatus.value = 2 currentStatus.value = LotteryStatus.running
rollBall(10, 3000) rollBall(10, 3000)
} }
// 停止抽奖,开始选取中将卡片并展示
async function stopLottery() { async function stopLottery() {
if (!canOperate.value) { if (!canOperate.value) {
return return
@@ -476,7 +407,7 @@ async function stopLottery() {
.start() .start()
.onComplete(() => { .onComplete(() => {
canOperate.value = true canOperate.value = true
currentStatus.value = 3 currentStatus.value = LotteryStatus.end
}) })
new TWEEN.Tween(item.rotation) new TWEEN.Tween(item.rotation)
.to({ .to({
@@ -519,63 +450,7 @@ async function continueLottery() {
} }
function quitLottery() { function quitLottery() {
enterLottery() enterLottery()
currentStatus.value = 0 currentStatus.value = LotteryStatus.init
}
// 庆祝动画
function confettiFire() {
const duration = 3 * 1000
const end = Date.now() + duration;
(function frame() {
// launch a few confetti from the left edge
confetti({
particleCount: 2,
angle: 60,
spread: 55,
origin: { x: 0 },
})
// and launch a few from the right edge
confetti({
particleCount: 2,
angle: 120,
spread: 55,
origin: { x: 1 },
})
// keep going until we are out of time
if (Date.now() < end) {
requestAnimationFrame(frame)
}
}())
centerFire(0.25, {
spread: 26,
startVelocity: 55,
})
centerFire(0.2, {
spread: 60,
})
centerFire(0.35, {
spread: 100,
decay: 0.91,
scalar: 0.8,
})
centerFire(0.1, {
spread: 120,
startVelocity: 25,
decay: 0.92,
scalar: 1.2,
})
centerFire(0.1, {
spread: 120,
startVelocity: 45,
})
}
function centerFire(particleRatio: number, opts: any) {
const count = 200
confetti({
origin: { y: 0.7 },
...opts,
particleCount: Math.floor(count * particleRatio),
})
} }
function setDefaultPersonList() { function setDefaultPersonList() {
@@ -614,23 +489,23 @@ function listenKeyboard(e: any) {
if ((e.keyCode !== 32 || e.keyCode !== 27) && !canOperate.value) { if ((e.keyCode !== 32 || e.keyCode !== 27) && !canOperate.value) {
return return
} }
if (e.keyCode === 27 && currentStatus.value === 3) { if (e.keyCode === 27 && currentStatus.value === LotteryStatus.running) {
quitLottery() quitLottery()
} }
if (e.keyCode !== 32) { if (e.keyCode !== 32) {
return return
} }
switch (currentStatus.value) { switch (currentStatus.value) {
case 0: case LotteryStatus.init:
enterLottery() enterLottery()
break break
case 1: case LotteryStatus.ready:
startLottery() startLottery()
break break
case 2: case LotteryStatus.running:
stopLottery() stopLottery()
break break
case 3: case LotteryStatus.end:
continueLottery() continueLottery()
break break
default: default:
@@ -639,7 +514,6 @@ function listenKeyboard(e: any) {
} }
function cleanup() { function cleanup() {
// animationRunning.value = false
clearInterval(intervalTimer.value) clearInterval(intervalTimer.value)
intervalTimer.value = null intervalTimer.value = null
if (scene.value) { if (scene.value) {
@@ -685,7 +559,7 @@ function cleanup() {
controls.value = null controls.value = null
} }
onMounted(() => { onMounted(() => {
initTableData() tableData.value = initTableData({ allPersonList: allPersonList.value, rowCount: rowCount.value })
init() init()
animation() animation()
containerRef.value!.style.color = `${textColor}` containerRef.value!.style.color = `${textColor}`
@@ -728,11 +602,11 @@ onUnmounted(() => {
<div id="container" ref="containerRef" class="3dContainer"> <div id="container" ref="containerRef" class="3dContainer">
<!-- 选中菜单结构 start --> <!-- 选中菜单结构 start -->
<div id="menu"> <div id="menu">
<button v-if="currentStatus === 0 && tableData.length > 0" class="btn-end " @click="enterLottery"> <button v-if="currentStatus === LotteryStatus.init && tableData.length > 0" class="btn-end " @click="enterLottery">
{{ t('button.enterLottery') }} {{ t('button.enterLottery') }}
</button> </button>
<div v-if="currentStatus === 1" class="start"> <div v-if="currentStatus === LotteryStatus.ready" class="start">
<button class="btn-start" @click="startLottery"> <button class="btn-start" @click="startLottery">
<strong>{{ t('button.start') }}</strong> <strong>{{ t('button.start') }}</strong>
<div id="container-stars"> <div id="container-stars">
@@ -746,11 +620,11 @@ onUnmounted(() => {
</button> </button>
</div> </div>
<button v-if="currentStatus === 2" class="btn-end btn glass btn-lg" @click="stopLottery"> <button v-if="currentStatus === LotteryStatus.running" class="btn-end btn glass btn-lg" @click="stopLottery">
{{ t('button.selectLucky') }} {{ t('button.selectLucky') }}
</button> </button>
<div v-if="currentStatus === 3" class="flex justify-center gap-6 enStop"> <div v-if="currentStatus === LotteryStatus.end" class="flex justify-center gap-6 enStop">
<div class="start"> <div class="start">
<button class="btn-start" @click="continueLottery"> <button class="btn-start" @click="continueLottery">
<strong>{{ t('button.continue') }}</strong> <strong>{{ t('button.continue') }}</strong>